Todo List
0 Open
0 Closed

[x] Separate-axis collision resolution (X then Y independently)

  • done — player vs map tile collision, per-axis, with collider offset separate from sprite size

[x] Clamp camera to map bounds

  • prevent camera showing area outside the map when target nears edges
  • clamp after lerp so it still feels smooth, not clamp-then-lerp

[x] Per-tile collider rect (not always full-tile)

  • parameterize get_world_tile_rect with an offset/size, defaulting to full TILE_SIZE

[x] Tile Definitions and tile structs

  • tile_defs table (solid + collider offset/w/h) keyed by Tile_Type
  • check_map_collision reads shape from the def instead of hardcoded full-tile

[x] Basic entity/game object pattern

  • Enemy as its own struct, Player/Enemy/Prop kept separate rather than unified ECS
  • fixed-size arrays (MAX_ENEMIES 150, MAX_PROPS 100) + count-tracked active slots

[x] Spawn a basic enemy

  • spawn_enemy: random valid position via map-collision re-roll, attempt-capped, writes back count
  • @TODO in code: enemy-vs-enemy self-exclusion — needed once enemies move/collide with each other, not needed for spawning or player-vs-enemy

[x] Entity/entity collision (player vs enemy)

  • check_enemy_collision wired into update_player alongside check_map_collision, per axis (&&, both must be clear to move)

[x] Timer struct

  • reusable duration/elapsed/fired type — ticked with dt, one-shot or repeating
  • first use: gate spawn_enemy behind an interval instead of calling it once
  • will also cover future timed things (cooldowns, invincibility windows) without reinventing per-system

[x] Create enemy flow field algorithm.

  • using a BFS get all the costs per grid tile.
  • using the costs find the best direction to the players tile

[x] Enemies Consume the Flow Field (Each frame, per enemy)

  • Convert enemy world pos → grid pos (world_to_grid)
  • Convert grid pos → flat index
  • Read flow_directions[idx]
  • Use that vector as movement direction (same as input_dir → velocity for player)

[ ] Wall avoidance steering for enemies (flow field consumption)

  • enemies get stuck pressed against wall corners — flow field direction is correct, but raw direction alone drives straight into walls with no anticipation
  • add a repulsion vector: check enemy's neighboring tiles for solids, build a push-away vector from any found, blend with flow_dir before computing target_velocity
  • only applies near walls (skip when no solid neighbors) — open floor movement stays pure flow field
  • same mechanism will likely double as enemy-vs-enemy separation later

[ ] Basic game state/scene management

  • enum: menu, playing, paused, game_over
  • gates update/draw calls per state
  • gives a place to route to on death/win

[ ] Basic sound manager

  • build once there are real events to hook (hit, hurt, wave start, death)

--- STOP. Playtest here. See what breaks or feels bad before adding more. ---
=== Deferred until the above is proven out ===

[ ] Y-sort draw order (entities in front/behind each other)

  • sort dynamic sprites (player, enemies, props) by base/feet Y each frame, not sprite top
  • static floor tiles stay a separate layer drawn first, unaffected by this sort

[ ] Tiled (.tmx/.json) map loader

  • swap flat array for real authored maps
  • tileset's per-tile collision shapes (Tiled's Collision Editor) feed the existing Tile_Def table
  • decide rects-only vs polygon colliders when you get here

[ ] Multi-layer map rendering (background/foreground)

  • depends on Tiled loader
  • draw order: background -> entities (Y-sorted) -> foreground

[ ] Input abstraction (action mapping instead of raw key checks)

  • pays off once you add more player actions (dash, attack, interact)

Notes/thinking.

  1. Currently all movement is handled in the file ie Player/Enemy etc
  2. Try to keep everything basic and simple to use