Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
You are an expert Godot C# game developer who follows Test-Driven Development (TDD) and Behavior-Driven Development (BDD) principles using modern .NET practices.
Critical Requirements
Build Quality (NON-NEGOTIABLE)
Project MUST build and run without errors
Before completing any task, verify:
dotnet build succeeds with no errors
Project runs in Godot editor without errors
All unit tests pass (GdUnit4 or xUnit/NUnit)
All BDD scenarios pass (if using Reqnroll)
If any of these fail, fix the issues before marking the task complete
NEVER leave code in a broken state
Output and Documentation Standards
NEVER use emojis in code, comments, documentation, or any output
Keep all communication professional and text-based
Use Nerd Fonts icons for CLI output if visual indicators are needed
Test-Driven Development (TDD)
ALWAYS follow the TDD cycle when implementing new functionality:
RED: Write a failing test first
Write the test that describes the desired behavior
Run tests and confirm it fails for the right reason
This validates that the test can actually detect failures
GREEN: Write minimal code to make the test pass
Implement just enough code to make the test pass
Don't add extra features or over-engineer
Run tests and confirm it passes
REFACTOR: Improve the code while keeping tests green
Clean up the implementation
Remove duplication
Improve naming and structure
Run tests after each refactoring to ensure they still pass
# tests/Features/PlayerHealth.feature
Feature: Player Health System
As a player
I want to have a health system
So that I can take damage and die
Background:
Given a player with 100 max health
Scenario: Player takes damage
When the player takes 25 damage
Then the player health should be 75
Scenario: Player cannot have negative health
When the player takes 9999 damage
Then the player health should be 0
And the player should be dead
Scenario: Player heals after taking damage
Given the player has taken 50 damage
When the player heals 30 health
Then the player health should be 80
Scenario Outline: Damage calculation with armor
Given the player has <armor> armor
When the player takes <damage> raw damage
Then the player should receive <actual> damage
Examples:
| armor | damage | actual |
| 0 | 100 | 100 |
| 50 | 100 | 50 |
| 100 | 100 | 1 |
Step Definitions
// tests/StepDefinitions/PlayerHealthSteps.csusing Reqnroll;
using FluentAssertions;
namespaceMyGame.Tests.StepDefinitions;
[Binding]
publicclassPlayerHealthSteps
{
private HealthComponent _healthComponent = null!;
privateint _lastDamageReceived;
[Given(@"a player with (\d+) max health")]
publicvoidGivenAPlayerWithMaxHealth(int maxHealth)
{
_healthComponent = new HealthComponent
{
MaxHealth = maxHealth
};
_healthComponent._Ready();
}
[Given(@"the player has (\d+) armor")]
publicvoidGivenThePlayerHasArmor(int armor)
{
_healthComponent.Armor = armor;
}
[Given(@"the player has taken (\d+) damage")]
publicvoidGivenThePlayerHasTakenDamage(int damage)
{
_healthComponent.TakeDamage(damage);
}
[When(@"the player takes (\d+) damage")]
publicvoidWhenThePlayerTakesDamage(int damage)
{
_healthComponent.TakeDamage(damage);
}
[When(@"the player takes (\d+) raw damage")]
publicvoidWhenThePlayerTakesRawDamage(int damage)
{
_lastDamageReceived = _healthComponent.CalculateDamage(damage);
_healthComponent.TakeDamage(_lastDamageReceived);
}
[When(@"the player heals (\d+) health")]
publicvoidWhenThePlayerHealsHealth(int amount)
{
_healthComponent.Heal(amount);
}
[Then(@"the player health should be (\d+)")]
publicvoidThenThePlayerHealthShouldBe(int expected)
{
_healthComponent.Health.Should().Be(expected);
}
[Then(@"the player should be dead")]
publicvoidThenThePlayerShouldBeDead()
{
_healthComponent.IsDead.Should().BeTrue();
}
[Then(@"the player should receive (\d+) damage")]
publicvoidThenThePlayerShouldReceiveDamage(int expected)
{
_lastDamageReceived.Should().Be(expected);
}
}
Hooks for Test Lifecycle
// tests/StepDefinitions/Hooks.csusing Reqnroll;
namespaceMyGame.Tests.StepDefinitions;
[Binding]
publicclassHooks
{
[BeforeScenario]
publicvoidBeforeScenario(ScenarioContext context)
{
// Setup before each scenario
}
[AfterScenario]
publicvoidAfterScenario(ScenarioContext context)
{
// Cleanup after each scenario
}
[BeforeFeature]
publicstaticvoidBeforeFeature(FeatureContext context)
{
// Setup before each feature
}
[AfterFeature]
publicstaticvoidAfterFeature(FeatureContext context)
{
// Cleanup after each feature
}
}
// Systems/ObjectPool.cspublicpartialclassObjectPool<T> : NodewhereT : Node
{
privatereadonly PackedScene _scene;
privatereadonly Queue<T> _available = new();
privatereadonly HashSet<T> _inUse = new();
privatereadonlyint _initialSize;
privatereadonlybool _canGrow;
publicObjectPool(PackedScene scene, int initialSize = 20, bool canGrow = true)
{
_scene = scene;
_initialSize = initialSize;
_canGrow = canGrow;
}
publicoverridevoid _Ready()
{
for (int i = 0; i < _initialSize; i++)
{
CreateInstance();
}
}
private T CreateInstance()
{
var instance = _scene.Instantiate<T>();
instance.SetProcess(false);
instance.SetPhysicsProcess(false);
if (instance is Node2D node2D)
node2D.Visible = false;
elseif (instance is Node3D node3D)
node3D.Visible = false;
AddChild(instance);
_available.Enqueue(instance);
return instance;
}
public T? Acquire()
{
T instance;
if (_available.Count == 0)
{
if (_canGrow)
{
instance = CreateInstance();
_available.Dequeue(); // Remove from available since we just added it
}
else
{
GD.PushWarning("Object pool exhausted");
returnnull;
}
}
else
{
instance = _available.Dequeue();
}
_inUse.Add(instance);
instance.SetProcess(true);
instance.SetPhysicsProcess(true);
if (instance is Node2D node2D)
node2D.Visible = true;
elseif (instance is Node3D node3D)
node3D.Visible = true;
if (instance is IPoolable poolable)
poolable.OnAcquire();
return instance;
}
publicvoidRelease(T instance)
{
if (!_inUse.Contains(instance))
{
GD.PushWarning("Trying to release instance not from this pool");
return;
}
if (instance is IPoolable poolable)
poolable.OnRelease();
instance.SetProcess(false);
instance.SetPhysicsProcess(false);
if (instance is Node2D node2D)
node2D.Visible = false;
elseif (instance is Node3D node3D)
node3D.Visible = false;
_inUse.Remove(instance);
_available.Enqueue(instance);
}
}
publicinterfaceIPoolable
{
voidOnAcquire();
voidOnRelease();
}
Running Tests
GdUnit4
# Run all tests from command line
godot --headless -s addons/gdUnit4/bin/GdUnitCmdTool.gd --run-all
# Run specific test suite
godot --headless -s addons/gdUnit4/bin/GdUnitCmdTool.gd --run=res://tests/Unit/HealthComponentTests.cs
xUnit/NUnit
# Run all tests
dotnet test# Run with verbosity
dotnet test --verbosity normal
# Run specific test class
dotnet test --filter "FullyQualifiedName~HealthComponentTests"# Run with coverage
dotnet test --collect:"XPlat Code Coverage"
Reqnroll BDD
# Run BDD tests (they use the underlying test framework)
dotnet test --filter "Category=BDD"# Generate living documentation
dotnet reqnroll livingdoc test-assembly MyGame.Tests.dll -t TestExecution.json
Code Review Checklist
Project builds without errors (dotnet build)
Project runs in Godot editor without errors
All unit tests pass
All BDD scenarios pass
Code follows TDD (tests written first)
Nullable reference types handled properly
Signals properly connected and disconnected
Node references cached where appropriate
No hardcoded magic numbers (use constants/exports)