diff --git a/CLAUDE.md b/CLAUDE.md index cceecec..0b04993 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,77 +1,96 @@ -# Claude Code Rules - Godot 4.x Town Project +# ๐ŸŽฏ CLAUDE.md - WhaleTown Project Instructions -## Project Overview -A 2D top-down pixel art RPG built in Godot 4.x using a layered architecture. -- **Core**: `_Core/` (SceneManager, EventSystem, GameManager) -- **Gameplay**: `Scenes/` (Maps, Entities, Components) -- **UI**: `UI/` (Windows, Overlays) +## 1. Project Vision & Context +- **Project**: "WhaleTown" - A 2D top-down pixel art RPG. +- **Engine**: Godot 4.2+ (Strictly NO Godot 3.x syntax). +- **Architecture**: Strictly layered: `_Core` (Framework), `Scenes` (Gameplay), `UI` (Interface). +- **Core Principle**: "Signal Up, Call Down". High decoupling via `EventSystem`. -## Coding Standards (GDScript) -- **Type Safety**: Use static typing strictly (e.g., `var speed: float = 100.0`, `func _ready() -> void`). +## 2. ๐Ÿ›  Command Reference & Setup +- **Input Map (Required Configuration)**: + - `move_left`, `move_right`, `move_up`, `move_down` (WASD / Arrows) + - `interact` (E Key / Space) + - `pause` (ESC) +- **Run Game**: `godot --path .` +- **Run Tests (GUT)**: `godot --headless -s addons/gut/gut_cmdline.gd -gdir=res://tests/ -ginclude_subdirs` +- **Init Structure**: `mkdir -p _Core/managers _Core/systems Scenes/Maps Scenes/Entities Scenes/Components UI/Windows UI/HUD Assets/Sprites tests/unit tests/integration` + +## 3. ๐Ÿ“‚ File Path Rules (STRICT LOWERCASE) +*Claude: Root folders MUST be lowercase. Scripts and Scenes MUST stay together.* +- **Core Managers**: `_Core/managers/[Name].gd` +- **Core Systems**: `_Core/systems/[Name].gd` +- **Entities**: `Scenes/Entities/[EntityName]/[EntityName].tscn` (Script `.gd` in same folder). +- **Maps**: `Scenes/Maps/[map_name].tscn` +- **Components**: `Scenes/Components/[ComponentName].gd` (Reusable logic nodes). +- **UI Windows**: `UI/Windows/[WindowName].tscn` +- **Tests**: `tests/[unit|integration]/test_[name].gd` (Folder is lowercase `tests`). + +## 4. ๐Ÿ“‹ Coding Standards (The Law) +- **Type Safety**: ALWAYS use strict static typing: `var speed: float = 100.0`, `func _ready() -> void`. - **Naming Conventions**: - - Classes: `PascalCase` (using `class_name`). - - Variables/Functions: `snake_case`. - - Constants: `SCREAMING_SNAKE_CASE`. - - Signals: `snake_case` (e.g., `signal player_interacted(data)`). -- **Node Access**: Use `@onready var name = $Path` or `%UniqueName`. Prefer `%UniqueName` for UI and internal scene components. -- **Best Practices**: - - Use `await` for signals and timers instead of `yield`. - - Use `Callable` for callbacks. - - Follow the "Signal Up, Call Down" rule: Parent calls methods on children; children emit signals to parents. - - Use `Input.get_vector("left", "right", "up", "down")` for 2D movement. + - `class_name PascalCase` at the top of every script. + - Variables/Functions: `snake_case`. Constants: `SCREAMING_SNAKE_CASE`. + - Private members: Prefix with underscore `_` (e.g., `var _health: int`). +- **Node Access**: Use `%UniqueName` for UI and internal scene components. +- **Signals**: Use "Signal Up, Call Down". Parent calls child methods; Child emits signals. +- **Forbidden Patterns**: + - โŒ NO `yield()` -> Use `await`. + - โŒ NO `get_node()` in `_process` -> Cache with `@onready`. + - โŒ NO Linear Filter -> All Sprite2D/TileMap resources MUST use **Nearest** filter. -## Project Architecture Rules -- **Decoupling**: Never reference singleton managers directly in low-level entities. Use `EventSystem` to communicate across modules. -- **Scene Management**: All scene transitions must go through `SceneManager.change_scene(scene_key)`. -- **Components**: Logic like "Health", "Interactions", or "Movement" should be encapsulated in `Scenes/Components/` as reusable nodes. +## 5. ๐Ÿ› Architecture & Communication +- **EventSystem**: Use `_Core/systems/EventSystem.gd` for cross-module messaging. +- **Event Registry**: Use `class_name EventNames` in `_Core/EventNames.gd`. + ```gdscript + class_name EventNames + const PLAYER_MOVED = "player_moved" + const INTERACT_PRESSED = "interact_pressed" + const NPC_TALKED = "npc_talked" +Singletons: Only GameManager, SceneManager, EventSystem allowed as Autoloads. +Decoupling: Low-level entities MUST NOT reference GameManager. Use events. +6. ๐Ÿ— Implementation Details +Player: CharacterBody2D. Must include Camera2D with position_smoothing_enabled = true. +NPC/Interactables: Use Area2D named InteractionArea. Trigger via EventSystem. +TileMap Layers: +Layer 0: Ground (No collision). +Layer 1: Obstacles (Physics Layer enabled). +Layer 2: Decoration (Y-Sort enabled). +Camera: Must auto-calculate limits via TileMap.get_used_rect(). +7. ๐Ÿงช Testing Requirements (MANDATORY) +Coverage: Every Manager/System in _Core/ MUST have a GUT test. +Naming: Test files must start with test_ and extend GutTest. +Example: +code +Gdscript +extends GutTest +func test_event_emission(): + var sender = Node.new() + watch_signals(EventSystem) + EventSystem.emit_event(EventNames.PLAYER_MOVED, {}) + assert_signal_emitted(EventSystem, "event_raised") +8. ๐Ÿง˜ The Zen of Development +Juice or Death: Every interaction (UI popup, NPC talk) MUST have a Tween placeholder. +Zero Magic Numbers: All speeds/timers MUST be @export or defined in Config/. +Simplicity: If a function does two things, split it. +Back of the Fence: Hidden logic (like ResponseHandler.gd) must be as clean as the HUD. +9. ๐Ÿ“ Code Template (Entity Pattern) +code +Gdscript +extends CharacterBody2D +class_name Player -## Implementation Specifics (Town Map) +# 1. Exports & Constants +@export var move_speed: float = 200.0 -### 1. Entity Structure -- **Player**: Must be a `CharacterBody2D`. Include a `Camera2D` with `position_smoothing_enabled = true`. -- **NPC**: Must be a `StaticBody2D` or `CharacterBody2D` with an `Area2D` named `InteractionArea`. -- **Interactables**: Use a shared `InteractableComponent` (Area2D based) for building entrances and NPCs. +# 2. Node References +@onready var sprite: Sprite2D = %Sprite2D -### 2. Interaction System -- NPC/Entrance interaction must trigger via `EventSystem`. -- Interaction logic: - 1. Player enters `InteractionArea`. - 2. Player presses "E" or "UI_Accept". - 3. Emit `EventSystem.notify_interaction_triggered(interactable_data)`. +# 3. Lifecycle +func _physics_process(delta: float) -> void: + _move(delta) -### 3. TileMap Rules -- Use `TileMap` (or `TileMapLayer` if Godot 4.3+). -- Layer 0: Ground (No collision). -- Layer 1: Obstacles/Walls (With Physics Layer collision). -- Layer 2: Decorations (Y-Sort enabled). - -## File Organization -- New maps: `Scenes/Maps/[map_name].tscn` -- New entities: `Scenes/Entities/[entity_name]/[entity_name].tscn` -- New scripts: Same folder as their scene files. -- Assets: Always reference assets from `res://Assets/Sprites/`. - -## Command Reference -- Build/Run: `godot --path .` -- Export (Linux): `godot --path . --export-release "Linux/X11"` - -## Testing Standards -- **Framework**: Use GUT (Godot Unit Test) for all tests. -- **Test Location**: All test scripts must be in `res://test/unit/` or `res://test/integration/`. -- **File Naming**: Test files must start with `test_` and end with `.gd` (e.g., `test_player_movement.gd`). -- **Class Structure**: Every test file must `extends GutTest`. -- **Requirements**: - - Every new core logic (in `_Core`) must have a corresponding unit test. - - Player movement and NPC interactions must have integration tests using `yield_for` or `await`. - - Use `assert_eq`, `assert_true`, and `assert_signal_emitted` for validations. - -## Commands -- **Run all tests**: `godot --headless -s addons/gut/gut_cmdline.gd -gdir=res://test/ -ginclude_subdirs` -- **Run specific test**: `godot --headless -s addons/gut/gut_cmdline.gd -gtest=res://test/unit/test_example.gd` - -## The Zen of Development (Pro Tips) -- **Simplicity is the ultimate sophistication**: If a function does two things, it's one thing too many. Split it. -- **The "Back of the Fence" Rule**: Even parts the player never sees (like the EventSystem logic) must be clean and beautiful. No "quick hacks". -- **Feedback Loop**: Every interaction MUST have a placeholder for juice (Tween, Sound, or Particle). Code is the skeleton, but juice is the soul. -- **Zero Hard-Coding**: All paths, configuration values, and magic numbers must be defined as constants or @export variables. -- **The "It Just Works" Camera**: Camera logic must automatically find TileMap limits. The player should never see the "gray void" outside the map. \ No newline at end of file +# 4. Private Methods +func _move(_delta: float) -> void: + var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down") + velocity = dir * move_speed + move_and_slide() \ No newline at end of file