Todo List
[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.
- Currently all movement is handled in the file ie Player/Enemy etc
- Try to keep everything basic and simple to use