From c25cae9a322860b38cb0ca1c22952989c9486589 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 21 Jun 2026 10:47:20 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20update=20AGENTS.md=20=E2=80=94=20slime,?= =?UTF-8?q?=20combat,=20BodyTemplate,=20122=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f520602..a45fde0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,13 +12,14 @@ cargo run -- --mode test # run all JSON scenarios cargo run -- --mode headless --headless-ticks 60 # dump to headless_dump.txt ``` -Rust edition 2024, requires rustc ≥ 1.96. Vulkan 1.2+ required for `ascii`/`graphics` modes (falls back to terminal). +Rust edition 2024, requires rustc >= 1.96. Vulkan 1.2+ required for `ascii`/`graphics` modes (falls back to terminal). ## Tests ```sh -cargo test # all 109 integration tests +cargo test # all 122 integration tests cargo test --test physics_sand # single test file +cargo test --test slime # slime-specific tests cargo run -- --mode test --scenario-dir scenarios # 14 JSON scenarios ``` @@ -39,15 +40,21 @@ SPV files are committed. `include_bytes!` embeds them at compile time. ## Architecture -**Source of truth**: `Grid` (250×250) of `Cell` structs. Each `Cell` stores `material`, `temp`, `fg`/`bg` color, `variant` inline. No double buffer — `Grid::next` was removed. +**Source of truth**: `Grid` (250x250) of `Cell` structs. Each `Cell` stores `material`, `temp`, `fg`/`bg` color, `variant` inline. No double buffer. -**Three entity types**: cellular (CA materials in grid), rigid (alive entities, AABB + slope stepping), ragdoll (corpses, Verlet constraints). +**Four entity kinds**: `Player`, `Goblin`, `Slime`, `Corpse`. Three physics types: cellular (CA materials in grid), rigid (alive entities, AABB + slope stepping), ragdoll (corpses, Verlet constraints). **Three render modes**: `terminal` (crossterm ANSI), `ascii` (Vulkan glyph atlas + instanced), `graphics` (Vulkan colored quads). All three read the same `Grid` + `EntityManager`. **GpuRenderer trait** (`main.rs`): unifies `VulkanRenderer` and `GraphicsRenderer` behind `run_gpu_mode()`. Both have identical event loops; only shader/instance format differs. -**Game loop**: `Game::fixed_update()` = CA step → rigid update → ragdoll update → damage. Called from event loop with fixed 16ms accumulator. `Game::run()` is terminal-only (uses `InputHandler` with crossterm). GPU modes use `run_gpu_mode` with `WindowInput` (winit PhysicalKey, layout-agnostic). +**Game loop**: `Game::fixed_update()` = CA step -> rigid update -> ragdoll update -> slime AI -> combat -> damage. Called from event loop with fixed 16ms accumulator. `Game::run()` is terminal-only (uses `InputHandler` with crossterm). GPU modes use `run_gpu_mode` with `WindowInput` (winit PhysicalKey, layout-agnostic). + +**BodyTemplate** (`entity/body_template.rs`): data-driven entity body definitions. JSON-serializable. `build_humanoid()` delegates to `template_for_kind().apply_to()`. To add a new creature shape, add a `BodyTemplate` constructor + match arm in `template_for_kind`. Each `SubBody` has a `color: [u8; 4]` field for per-part coloring. + +**Combat**: `update_combat()` checks AABB overlap between player and all alive enemies. Goblin = 8 dmg, Slime = 5 dmg per 20 ticks on contact. Knockback applied to player. Player combat style is ranged (projectiles planned, not yet implemented). + +**Slime AI**: `update_slime_ai()` makes slimes jump toward player every 60 ticks when within 40 cells. Jump power scales with proximity. ## Key Conventions @@ -55,24 +62,25 @@ SPV files are committed. `include_bytes!` embeds them at compile time. - **Cell colors are inline** — renderers read `cell.fg`/`cell.bg` directly, never lookup `MaterialRegistry` in render path. Registry is for physics properties only (density, solid, flammable, etc.). - **Vector movement** — `Player::move_left/right` sets velocity directly (`set_horizontal_vel`), no accumulation. `stop_horizontal` zeroes it. Jump is edge-triggered (press only, not held). - **Slope stepping** — `update_rigid_entity` tries stepping up 1 cell before resolving X collision, enabling walking up slopes without jumping. -- **Adaptive viewport** — `check_resize()` in both Vulkan renderers recreates swapchain on window resize. `grid_w`/`grid_h` recalculated from extent / 16. Wayland uses `window.inner_size()` (surface extent is undefined). +- **Adaptive viewport** — `check_resize()` in both Vulkan renderers recreates swapchain on window resize. `grid_w`/`grid_h` recalculated from extent / 10 (cell size = 10x10 px). Wayland uses `window.inner_size()` (surface extent is undefined). - **`Cell::new()` copies colors from `MaterialRegistry`** at creation time. Per-cell color variation is possible by modifying `cell.fg`/`cell.bg` after creation. +- **Auto-constraints** — `BodyTemplate::auto_constraints(n)` connects all parts to all others (n^2). Works for any template shape. Simpler than manual constraint lists. ## Module Layout ``` src/ - main.rs # CLI, GpuRenderer trait, run_gpu_mode(), event loops - lib.rs # pub mod declarations - game.rs # Game struct, world gen, fixed_update, collision (AABB + slope) - input.rs # Terminal input (crossterm, InputHandler) — terminal mode only - world/ # Cell, MaterialId, MaterialRegistry, Grid, CellularAutomaton - physics/ # VerletSolver, SubBody, Constraint, resolve_grid_collision - entity/ # Entity (rigid/ragdoll), EntityManager, Player - render/ # terminal.rs, vulkan.rs (ASCII), graphics.rs (cells), window_input.rs - ai/ # GameSession, AiAction, pipe protocol, replay, scenarios + main.rs # CLI, GpuRenderer trait, run_gpu_mode(), event loops + lib.rs # pub mod declarations + game.rs # Game struct, world gen, fixed_update, collision, combat, slime AI + input.rs # Terminal input (crossterm, InputHandler) — terminal mode only + world/ # Cell, MaterialId, MaterialRegistry, Grid, CellularAutomaton + physics/ # VerletSolver, SubBody (with color field), Constraint, resolve_grid_collision + entity/ # Entity (rigid/ragdoll), EntityManager, Player, BodyTemplate + render/ # terminal.rs, vulkan.rs (ASCII), graphics.rs (cells), window_input.rs + ai/ # GameSession, AiAction, pipe protocol, replay, scenarios ``` ## PLAN.md -Detailed roadmap with 8 phases, architecture decisions, milestones, and cross-platform support table. Read it for design context before making architectural changes. +Detailed roadmap with 8 phases, architecture decisions, milestones, and cross-platform support table. Read it for design context before making architectural changes. Player combat is ranged (projectiles), not melee — this is a design decision recorded in Phase 1.