Add Godot development guidelines
This commit is contained in:
@@ -0,0 +1,239 @@
|
|||||||
|
# Godot Development Guidelines
|
||||||
|
|
||||||
|
**Document Version:** v1
|
||||||
|
|
||||||
|
> **Note on Versioning:**
|
||||||
|
> - This document version is independent — reused across Godot projects
|
||||||
|
> - **Project version** source of truth: `project.godot` (`config/version`) mirrored in an autoload `Constants` script
|
||||||
|
> - Version propagates: `project.godot` → `Constants.gd` → code
|
||||||
|
> - `CHANGELOG.md` uses the project version
|
||||||
|
|
||||||
|
## Related Documents
|
||||||
|
|
||||||
|
- **README.md** — Project overview, gameplay description, build/run instructions
|
||||||
|
- **AGENTS.md** — Rules for AI assistants
|
||||||
|
- **PROJECT.md** — Project goals and current state
|
||||||
|
- **CHANGELOG.md** — Version history
|
||||||
|
|
||||||
|
### Documentation Organization
|
||||||
|
|
||||||
|
All detailed documentation of features and systems belongs in the `docs/` folder, not in the project root.
|
||||||
|
|
||||||
|
The root directory contains only the core documents: `DESIGN_DOCUMENT_GODOT.md`, `AGENTS.md`, `PROJECT.md`, `CHANGELOG.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Code Style
|
||||||
|
|
||||||
|
- **GDScript style guide** (official Godot conventions), 100-character soft line limit
|
||||||
|
- **Tabs** for indentation (Godot default, enforced by `.editorconfig`)
|
||||||
|
- **snake_case** functions/variables/signals, **PascalCase** classes/nodes/scenes, **SCREAMING_SNAKE_CASE** constants, **_leading_underscore** for private members
|
||||||
|
- **Static typing required** on all variables, parameters, and return types (`var speed: float`, `func move(delta: float) -> void`)
|
||||||
|
- **Declaration order** inside a script:
|
||||||
|
1. `class_name` / `extends`
|
||||||
|
2. `## docstring`
|
||||||
|
3. signals
|
||||||
|
4. enums, constants
|
||||||
|
5. `@export` variables
|
||||||
|
6. public variables
|
||||||
|
7. private variables (`_`)
|
||||||
|
8. `@onready` variables
|
||||||
|
9. `_init`, `_ready`, `_process`, `_physics_process` virtuals
|
||||||
|
10. public methods
|
||||||
|
11. private methods (`_`)
|
||||||
|
12. signal callbacks (`_on_*`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. SOLID Principles (applied to nodes & scenes)
|
||||||
|
|
||||||
|
- **SRP** — One scene/script = one responsibility (a node does one job)
|
||||||
|
- **OCP** — Extend behaviour by composing child nodes or new scenes, not by editing shared base scripts
|
||||||
|
- **LSP** — A scene inheriting another must be usable wherever the parent is
|
||||||
|
- **ISP** — Prefer small, focused signals and interfaces over god-objects
|
||||||
|
- **DIP** — Depend on abstractions: reference behaviours via exported node paths / resources, not hard-coded global lookups
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Dependency Injection
|
||||||
|
|
||||||
|
Inject dependencies through `@export` variables or `_init` parameters, set in the editor or by the spawning parent. Avoid reaching across the tree with `get_node("/root/...")` for collaborators. Use autoload singletons **only** for genuinely global services (audio bus, save system, game state).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Composition Over Inheritance
|
||||||
|
|
||||||
|
Prefer **node composition** and reusable **scenes** (e.g. a `Hitbox`, `Hurtbox`, `StateMachine` scene attached as a child) over deep script inheritance. Use `class_name` for shared base behaviour only when an "is-a" relationship is real.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Data Structures and Resources
|
||||||
|
|
||||||
|
- Use **`Resource`** (`class_name`, `extends Resource`) for designer-editable, serializable data (enemy stats, level definitions, weapon configs) — saved as `.tres`
|
||||||
|
- Use plain typed `Dictionary`/`Array` or small data classes for transient in-memory structures
|
||||||
|
- Validate `Resource` fields with `@export_range`, setters, and `_get_configuration_warnings()` where appropriate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Logging and Console Output
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Use a dedicated `Log` autoload that wraps `print`/`push_warning`/`push_error` with levels and timestamps. Never log secrets, passwords, tokens, or API keys.
|
||||||
|
|
||||||
|
#### Log sinks
|
||||||
|
|
||||||
|
| Sink | Level | Format |
|
||||||
|
|------|-------|--------|
|
||||||
|
| File `user://logs/{AppName}_{time}.log` | `DEBUG` | full (timestamp + level + message) |
|
||||||
|
| Editor Output / stdout | `INFO` | full |
|
||||||
|
|
||||||
|
The file sink retains **max 10 log files**. Each run creates a new file via the timestamp in the filename.
|
||||||
|
|
||||||
|
The `DEBUG` sink is only active when `Constants.DEBUG` is `true` (controlled by an `ENV_DEBUG` value read at startup, e.g. from a `user://settings.cfg` or an export feature tag).
|
||||||
|
|
||||||
|
Additional sinks (e.g. an in-game debug overlay / console panel) may be added per project.
|
||||||
|
|
||||||
|
#### Log levels
|
||||||
|
|
||||||
|
| Level | When to use |
|
||||||
|
|-------|-------------|
|
||||||
|
| `DEBUG` | Per-frame / per-entity detail: state transitions, collision events, per-tile operations |
|
||||||
|
| `INFO` | User-visible milestones: level loaded, game saved, scene changed |
|
||||||
|
| `WARNING` | Recoverable issues: missing optional resource, fallback asset used |
|
||||||
|
| `ERROR` | Failures the player/dev must know about: failed save, missing required scene/resource |
|
||||||
|
|
||||||
|
### Console output — `print()`
|
||||||
|
|
||||||
|
`print()` is **allowed** for quick editor-time inspection during development. It is **not** a substitute for the `Log` autoload and must not remain in shipped gameplay code for event tracking. Use `push_warning`/`push_error` so messages appear in the editor Debugger.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Settings and Secrets
|
||||||
|
|
||||||
|
- Store user/runtime config in `user://settings.cfg` via `ConfigFile`
|
||||||
|
- Toggle debug behaviour with an `ENV_DEBUG`-style flag read at startup into `Constants.DEBUG`
|
||||||
|
- Never commit any secrets; keep them out of `project.godot` and committed `.tres`/`.cfg` files
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Error Handling
|
||||||
|
|
||||||
|
Fail fast in development: use `assert()` for invariants that must hold (these are stripped in release builds). For recoverable runtime conditions, check return values and `is_instance_valid()` before use, and surface problems via `push_error`/`Log.error` rather than silently continuing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Testing
|
||||||
|
|
||||||
|
- Use **GUT** (Godot Unit Test) for unit and integration tests
|
||||||
|
- Tests live in `tests/`, files named `test_<thing>.gd`, methods named `test_<action>_<context>`
|
||||||
|
- Arrange-Act-Assert pattern
|
||||||
|
- Keep logic testable: put game rules in plain scripts/`Resource`s that can be exercised without a running scene tree where possible
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Tooling
|
||||||
|
|
||||||
|
| Tool | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| **gdformat** (gdtoolkit) | Formatting |
|
||||||
|
| **gdlint** (gdtoolkit) | Linting / style checks |
|
||||||
|
| **GUT** | Testing |
|
||||||
|
|
||||||
|
Run before every commit:
|
||||||
|
```bash
|
||||||
|
gdformat .
|
||||||
|
gdlint .
|
||||||
|
godot --headless -s addons/gut/gut_cmdln.gd -gdir=res://tests -gexit
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Dependencies and Addons
|
||||||
|
|
||||||
|
- Install editor plugins/addons under `addons/` (via the Asset Library or git submodule)
|
||||||
|
- Enable plugins through Project Settings → Plugins (recorded in `project.godot`)
|
||||||
|
- Keep `addons/` committed so the project opens cleanly on any machine
|
||||||
|
- Document non-trivial addon requirements in `README.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
project/
|
||||||
|
├── project.godot # Engine config and project settings
|
||||||
|
├── icon.svg # Project icon
|
||||||
|
├── autoload/ # Global singletons (Constants, Log, GameState, Audio)
|
||||||
|
├── scenes/ # Game scenes (.tscn), grouped by domain
|
||||||
|
│ ├── actors/ # player, enemies, NPCs
|
||||||
|
│ ├── levels/ # level/world scenes
|
||||||
|
│ └── ui/ # menus, HUD
|
||||||
|
├── scripts/ # Shared scripts not bound to a single scene
|
||||||
|
├── resources/ # .tres data resources (stats, configs)
|
||||||
|
├── assets/ # Art, audio, fonts (raw + imported)
|
||||||
|
├── addons/ # Editor plugins / third-party addons
|
||||||
|
├── tests/ # GUT tests
|
||||||
|
└── docs/ # Detailed documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
Scenes and their attached scripts live together; co-locate `Player.tscn` and `player.gd` under `scenes/actors/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Distribution and Deployment
|
||||||
|
|
||||||
|
When the game is distributed as a standalone build:
|
||||||
|
|
||||||
|
- Configure export presets in `export_presets.cfg` (one preset per target platform)
|
||||||
|
- Build with the headless editor:
|
||||||
|
```bash
|
||||||
|
godot --headless --export-release "Windows Desktop" build/Game.exe
|
||||||
|
```
|
||||||
|
- Compiled builds are stored in `build/` (or `dist/`). Decide per project whether builds are committed — for small internal distribution the repository may serve as the channel; otherwise keep `build/` in `.gitignore`
|
||||||
|
- Strip debug-only nodes and disable `Constants.DEBUG` in release presets
|
||||||
|
|
||||||
|
> This section applies only to projects that produce shippable builds.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Versioning
|
||||||
|
|
||||||
|
- Follow **semantic versioning**: `MAJOR.MINOR.PATCH`
|
||||||
|
- Version is defined in `project.godot` (`application/config/version`) and mirrored in the `Constants` autoload
|
||||||
|
- Always ask before bumping the version — never increment automatically
|
||||||
|
- Update `CHANGELOG.md` before bumping the version
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Documentation and Task Management
|
||||||
|
|
||||||
|
- Keep `PROJECT.md` and `CHANGELOG.md` up to date when making changes
|
||||||
|
- Document architectural changes in this file or in `docs/`
|
||||||
|
|
||||||
|
### Task notation
|
||||||
|
|
||||||
|
Tasks are written as single-line comments directly in code, or in `PROJECT.md` for cross-cutting concerns:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# TODO: one-liner description of a task to be done
|
||||||
|
# FIXME: one-liner description of a known bug to be fixed
|
||||||
|
```
|
||||||
|
|
||||||
|
No other task format is used — no checkboxes, no numbered lists in documentation.
|
||||||
|
|
||||||
|
If a `# TODO:` comment already exists at a specific location in code, do not repeat it in `PROJECT.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Godot-Specific Conventions
|
||||||
|
|
||||||
|
- **Signals over polling** — communicate events upward via signals; call down via direct method calls (`_on_*` callbacks for receiving)
|
||||||
|
- **`@onready` for node references** — cache child node references instead of repeated `get_node`
|
||||||
|
- **`_process` vs `_physics_process`** — gameplay/physics in `_physics_process(delta)`, visual-only/UI in `_process(delta)`
|
||||||
|
- **Groups** for broadcast queries (`add_to_group`, `get_tree().call_group`) instead of manual node lists
|
||||||
|
- **`queue_free()`** to remove nodes; never `free()` a node mid-signal
|
||||||
|
- **Scene instancing** via `PackedScene.instantiate()`; keep scenes self-contained and parametrized through `@export`
|
||||||
|
- **No hard-coded paths to assets in code** — load via `preload`/`@export` of the resource
|
||||||
|
</content>
|
||||||
|
</invoke>
|
||||||
Reference in New Issue
Block a user