cirnogodot/.github/instructions/godot.instructions.md

11 KiB

CLAUDE.md - AI Assistant Guidelines for Godot 4 C# Development

File Creation Guidelines

Files AI CAN Create/Edit

  • .cs files - All C# script files (preferred for game logic)
  • .tscn files - Scene files with basic/logical structure
  • .cfg files - Configuration files (like .ini format)

Files AI Should Create WITH CAUTION

  • .gd files - Only for EditorScript tools (preferred over C# for editor extensions)
  • .tres files - Simple resources CAN be created as text:
    [gd_resource type="Resource" script_class="Recipe" path="res://scripts/Recipe.cs"]
    
    id = "fire_water_steam"
    ingredients = ["fire", "water"]
    instability_cost = 20.0
    
    BUT: Complex resources with node references or nested resources are better created in editor

Files AI Should RARELY Create

  • .json files - Only for external data exchange or modding support
    • Use .tres for all game data instead (type-safe, Inspector-editable)
  • .md files - Documentation files, only when specifically requested

Files AI Should NOT Create

  • .import files - Godot manages these automatically
  • project.godot - Only modify through Project Settings UI
  • .gdshader files - Visual shader editing is more efficient
  • Binary files - Images, sounds, models, etc.

Scene File (.tscn) Guidelines

AI CAN Generate in .tscn

# Basic node structure
[node name="Player" type="CharacterBody2D"]
unique_name_in_owner = true
script = ExtResource("1")

# Node hierarchy
[node name="Sprite2D" type="Sprite2D" parent="."]

# Signal connections
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]

# Simple collision shapes
[sub_resource type="RectangleShape2D" id="1"]
size = Vector2(32, 32)

Human Handles in Editor

  • Sprite textures and animations
  • Precise collision shape adjustments
  • Animation tracks in AnimationPlayer
  • Particle system parameters
  • Complex UI layouts with exact positioning
  • Tilemap painting
  • Navigation mesh baking
  • Audio bus assignments

Division of Labor

AI Handles (Logic & Structure)

  • Game logic and systems in C#
  • Node hierarchy structure
  • Script functionality
  • Basic scene composition
  • Export variable definitions
  • Signal method implementations
  • Resource class definitions

Human Handles (Visual & Feel)

  • Sprite assignment and animation
  • Collision shape fine-tuning
  • Visual effects and particles
  • UI precise positioning
  • Audio integration
  • Testing game feel
  • Input mapping

C# Code Best Practices

Node References

// GOOD - Unique names (set in .tscn with unique_name_in_owner = true)
private Node player;

public override void _Ready()
{
    player = GetNode("%Player");
}

// GOOD - Relative paths for direct children
private Sprite2D sprite;

public override void _Ready()
{
    sprite = GetNode<Sprite2D>("Sprite2D");
}

// AVOID - Fragile absolute paths
var player = GetNode("/root/Main/World/Player");

Signals

// For static connections (nodes in same scene):
// AI provides the method, human connects in editor OR AI adds to .tscn
private void _OnButtonPressed()
{
    GD.Print("Button pressed!");
}

// For dynamic connections (runtime created nodes):
// AI writes the connection code
public override void _Ready()
{
    if (!enemy.Died.IsConnected(Callable.From(_OnEnemyDied)))
    {
        enemy.Died.Connect(Callable.From(_OnEnemyDied));
    }
}

Export Variables

// AI defines them with sensible defaults
[Export] public float MoveSpeed { get; set; } = 300.0f; // Human tweaks in Inspector
[Export] public PackedScene EnemyScene { get; set; } // Human assigns in Inspector

// Group related exports
[ExportGroup("Movement")]
[Export] public float Speed { get; set; } = 100.0f;
[Export] public float Acceleration { get; set; } = 10.0f;

Scene Instantiation

// Always check if assigned
[Export] public PackedScene ProjectileScene { get; set; }

private void Shoot()
{
    if (ProjectileScene == null)
    {
        GD.PrintErr("ProjectileScene not assigned in Inspector");
        return;
    }
    var bullet = ProjectileScene.Instantiate();
}

Standard C# Code Structure

using Godot;

public partial class Player : CharacterBody2D
{
    // Signals
    [Signal] public delegate void HealthChangedEventHandler(int newValue);

    // Constants
    private const float MaxSpeed = 400.0f;

    // Export variables
    [ExportGroup("Combat")]
    [Export] public int Damage { get; set; } = 10;
    [Export] public float AttackRate { get; set; } = 1.0f;

    // Private variables
    private string _currentState = "idle";
    private Vector2 _velocity = Vector2.Zero;

    // Node references (initialized in _Ready)
    private Sprite2D _sprite;
    private Control _healthBar;

    // Godot callbacks
    public override void _Ready()
    {
        _sprite = GetNode<Sprite2D>("Sprite2D");
        _healthBar = GetNode<Control>("%HealthBar"); // Unique name
    }

    public override void _PhysicsProcess(double delta)
    {
        // Physics logic
    }

    // Public methods
    public void TakeDamage(int amount)
    {
        // Implementation
    }

    // Private methods
    private void UpdateHealthBar()
    {
        // Implementation
    }

    // Signal callbacks
    private void _OnAreaEntered(Area2D area)
    {
        // Implementation
    }
}

Resource Creation

// AI provides the Resource class definition
using Godot;

[GlobalClass]
public partial class Recipe : Resource
{
    [Export] public string Id { get; set; } = "";
    [Export] public string[] Ingredients { get; set; } = Array.Empty<string>();
    [Export] public float InstabilityCost { get; set; } = 0.0f;
}

// Human creates instances: Right-click > Create Resource > Recipe

Testing & Debug Helpers

// Always include debug capability
[Export] public bool DebugMode { get; set; } = false;

// Debug methods
public override void _Ready()
{
    if (DebugMode)
    {
        GD.Print($"[{Name}] Ready with speed: {MoveSpeed}");
    }
}

// Unit test methods (can be called from debugger or test scenes)
public static float TestBrewingTiming()
{
    float totalTime = 0.4f * 3 + 0.8f; // 3 ingredients + set time
    System.Diagnostics.Debug.Assert(totalTime < 2.5f, "Brewing too slow!");
    return totalTime;
}

Common C# Patterns

Object Pooling Setup

// AI provides the structure, human assigns the scene
[Export] public PackedScene PooledScene { get; set; } // Assign in Inspector
private readonly Queue<Node> _pool = new();

private Node GetInstance()
{
    if (_pool.Count == 0)
        return PooledScene.Instantiate();
    return _pool.Dequeue();
}

State Machine

public enum State { Idle, Moving, Attacking }
private State _currentState = State.Idle;

private void TransitionTo(State newState)
{
    _currentState = newState;
    switch (newState)
    {
        case State.Idle:
            _animationPlayer.Play("idle");
            break;
        case State.Moving:
            _animationPlayer.Play("run");
            break;
    }
}

Instructions for Humans

When AI generates code/scenes, it should include clear TODO comments:

// TODO: In Godot Editor:
// 1. Assign EnemyScene in Inspector (drag Enemy.tscn)
// 2. Set up collision shape (Circle, radius ~16)
// 3. Add sprite texture
// 4. Connect hurt_box's area_entered signal

What to Avoid

DON'T

  • Hardcode paths to scenes (use [Export])
  • Create complex AnimationPlayer tracks in code
  • Generate particle system parameters in code
  • Edit .import files
  • Assume node paths without proper initialization
  • Use old Godot 3 syntax or GDScript patterns in C#
  • Create collision polygons via code arrays
  • Modify project.godot directly
  • Create .gd files for game logic (use C# instead)
  • Create documentation files unless specifically requested
  • Use esotheric powershell one-liners for file manipulation (use the available tools or ask the user instead)

DO

  • Use [Export] for all scene references
  • Use % for unique named nodes with GetNode
  • Include debug helpers
  • Check for null before using nodes
  • Use proper C# naming conventions (PascalCase for public, camelCase for private)
  • Provide fallbacks and error messages
  • Keep visual things in the editor
  • Use C# for all game logic and scripts

File Organization Example

/project
├── /Scripts           # All C# scripts organized by category
│   ├── /Resources    # Resource class definitions (AI creates these)
│   │   └── Recipe.cs
│   ├── /Player      # Player-related scripts
│   │   └── PlayerController.cs
│   ├── /Enemies     # Enemy-related scripts
│   │   └── EnemyAI.cs
│   ├── GameManager.cs    # Global scripts at root level
│   └── EventBus.cs
├── /Scenes           # Mix of AI and human work, organized by category
│   ├── /Player      # Player-related scenes
│   │   └── Player.tscn   # AI creates structure, human adds visuals
│   ├── /Enemies     # Enemy-related scenes
│   │   └── Enemy.tscn
│   └── /UI          # UI scenes
│       └── MainMenu.tscn
├── /Resources        # .tres resource files organized by category
│   ├── /Recipes     # Based on AI's Resource classes
│   │   └── FireWaterSteam.tres
│   └── /Items       # Item resources
│       └── Sword.tres
├── /Shaders          # Shader files
│   ├── Water.gdshader
│   └── Fire.gdshader
└── /Sprites          # Human manages visual assets
    ├── /Player
    └── /Enemies

C# Specific Guidelines

Naming Conventions

  • Classes: PascalCase (PlayerController)
  • Public properties/methods: PascalCase (MoveSpeed, TakeDamage())
  • Private fields: _camelCase (_currentHealth, _velocity)
  • Constants: PascalCase (MaxHealth)
  • Enums: PascalCase (PlayerState.Moving)

Property Usage

// Prefer properties over fields for exports
[Export] public float Speed { get; set; } = 100.0f;

// Use private fields for internal state
private float _currentSpeed;

Null Safety

// Always check exported scenes/nodes
if (ProjectileScene != null)
{
    var projectile = ProjectileScene.Instantiate<Projectile>();
    // Use the projectile
}

Project-Specific Notes

For Your game:

Summary

  • AI handles: Logic, structure, systems in C#
  • Human handles: Visuals, feel, precise adjustments
  • .tscn files are human-readable and AI can generate them
  • Always use [Export] and Inspector for scene/resource references
  • Use C# for all game logic, GDScript only for EditorScript tools
  • Include debug modes and clear TODOs
  • Test core mechanics with static methods
  • Avoid creating documentation unless requested