geometry-tower-defense/AGENTS.md

356 lines
6.2 KiB
Markdown

# Project Philosophy
This project prioritizes **clarity, correctness, and maintainability** over defensive boilerplate or unnecessary abstraction.
AI-generated code should:
* follow existing architecture
* keep logic simple and explicit
* avoid hiding bugs
* avoid speculative abstractions
If uncertain, prefer **simple direct code** over generalized frameworks.
## Repository Guidelines
### Project Structure & Module Organization
- `Assets/` contains all Unity assets and code. Game-specific content lives under `Assets/GameMain/`.
- `Assets/GameMain/Scripts/` holds gameplay code organized by domain (`Procedure/`, `Entity/`, `UI/`, `Scene/`, `Sound/`, `Utility/`).
- `Assets/GameMain/Scenes/` stores Unity scenes (start from `Assets/Launcher.unity`).
- `Assets/GameMain/Configs/` and `Assets/GameMain/DataTables/` store runtime configuration and data tables.
- `StreamingAssets/` is for runtime-loaded files that must be preserved on build.
- `docs/` contains design notes (see `docs/GameDesign.md`).
- `数据表/` is a top-level data table workspace; keep it in sync with `Assets/GameMain/DataTables/` when exporting.
### Build, Test, and Development Commands
- Open the project with Unity Hub and load `GeometryTD` as a Unity project.
- Play locally via the Unity Editor Play button (no custom CLI runner is defined in this repo).
- Build via Unity: `File > Build Settings...` then choose target and build.
- IDE support: open `GeometryTD.sln` or `Assembly-CSharp.csproj` for C# navigation and tooling.
### Coding Style & Naming Conventions
- C# uses 4-space indentation and Allman braces (see `Assets/GameMain/Scripts/Procedure/ProcedureLaunch.cs`).
- Types, methods, and public members use `PascalCase`; locals and parameters use `camelCase`.
- Namespaces follow `GeometryTD.*` by feature area (example: `GeometryTD.Procedure`).
- Keep Unity `.meta` files with their assets; do not delete or regenerate them manually.
---
## Code Design Principles
### 1. Prefer explicit logic over abstraction
Do not introduce abstractions unless they are clearly justified.
Avoid creating layers such as:
```
Manager
Service
Provider
Repository
Coordinator
Bridge
```
unless the architecture explicitly requires them.
Simple gameplay logic should remain simple.
Bad example:
```
EnemyService -> EnemyManager -> EnemyRepository
```
Good example:
```
EnemySpawner
Enemy
EnemyAI
```
---
### 2. Do not create abstractions for a single implementation
Avoid introducing interfaces unless multiple implementations are expected.
Bad:
```
IEnemyService
EnemyService
```
Good:
```
EnemySystem
```
Interfaces are only appropriate when:
* multiple implementations are required
* plugin/mod systems are involved
* testing requires mocking
* architecture explicitly defines extension points
---
### 3. Avoid speculative generalization
Do not design systems for hypothetical future use.
Implement only what the current feature requires.
Avoid:
* generic service layers
* premature plugin systems
* unnecessary configuration frameworks
---
## Defensive Programming Policy
### Boundary validation only
Validation is appropriate only at **true system boundaries**, such as:
* user input
* network input
* file/config loading
* inspector/external data
* public API boundaries
Internal gameplay logic should assume that invariants are already satisfied.
Do not add redundant validation inside internal code.
---
### Do not hide errors
Do not silently ignore invalid states.
Avoid code such as:
```
if (enemy == null)
return;
```
or
```
if (config == null)
continue;
```
unless the behavior is intentionally designed.
Unexpected states should be **visible**, not hidden.
---
### Prefer fail-fast over silent failure
If a condition should never happen in correct execution:
Use assertions.
Example:
```
Debug.Assert(config != null);
```
Do not convert invariant violations into no-op behavior.
Bad:
```
if (config == null)
return;
```
Good:
```
Debug.Assert(config != null);
```
---
### Do not weaken required dependencies
Required references must remain required.
Do not turn required dependencies into optional ones by adding defensive checks.
Bad:
```
if (enemy.Config == null)
return;
```
If a dependency is required by design, assume it exists.
---
## Error Handling
Do not introduce `try/catch` blocks unless there is a **clear recovery strategy**.
Avoid:
```
try
{
DoSomething();
}
catch (Exception e)
{
Debug.LogError(e);
}
```
Exceptions should generally propagate during development so bugs are visible.
---
## Early Return Policy
Early returns are acceptable for **normal control flow simplification**.
However, do not use early returns to hide invariant violations or missing required state.
Bad:
```
if (enemy == null)
return;
```
Good:
```
if (!enemy.IsAlive)
return;
```
---
## Logging
Avoid excessive logging.
Do not log inside per-frame loops unless necessary.
Avoid logs like:
```
Debug.Log("Updating enemy");
```
Use logging only when it provides meaningful debugging value.
---
## Utility Classes
Avoid creating generic utility classes such as:
```
GameUtils
CommonHelper
MathHelper
```
Prefer placing behavior in the domain object responsible for it.
Example:
Bad:
```
DamageHelper.CalculateDamage(...)
```
Good:
```
enemy.CalculateDamage(...)
```
---
## Data Structures
Avoid large context objects with many loosely related fields.
Bad:
```
EffectContext
{
int value;
int count;
float rate;
object source;
object target;
}
```
Prefer explicit parameters or strongly typed structures.
---
## Code Generation Rules for AI
Before adding any of the following:
* null check
* range check
* fallback default
* try/catch
* abstraction layer
First determine:
1. Is this a boundary input?
2. Is the value optional by design?
3. Is there a real recovery strategy?
If the answer is **no**, do not add defensive code.
---
## Preferred Coding Style
Prefer:
* simple classes
* explicit logic
* minimal indirection
* clear ownership of behavior
Avoid:
* unnecessary patterns
* speculative architecture
* defensive boilerplate
---
## Guiding Principle
Prefer:
**clear failure over hidden corruption**
A bug should surface near its source rather than being silently ignored.