From 2e09dbe65dcffe2b8fcb3cb37b0ab293a50e22bb Mon Sep 17 00:00:00 2001 From: codegirl-007 Date: Wed, 10 Jun 2026 00:08:02 -0700 Subject: [PATCH] enemy movement and object pool --- game/constants.odin | 6 ++++ game/enemy.odin | 82 +++++++++++++++++++++++++++++++++++---------- game/render.odin | 9 +++-- game/world.odin | 6 ++-- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/game/constants.odin b/game/constants.odin index 54839b9..2a85e20 100644 --- a/game/constants.odin +++ b/game/constants.odin @@ -7,3 +7,9 @@ TILE_SIZE :: 32 // size of tiles in pixels SCREEN_W :: MAP_W * TILE_SIZE SCREEN_H :: MAP_H * TILE_SIZE +MAX_ENEMIES :: 64 +MAX_WAVES :: 5 +MAX_TOWERS :: 32 + +TOWER_COST :: 50 + diff --git a/game/enemy.odin b/game/enemy.odin index 7709242..221d54d 100644 --- a/game/enemy.odin +++ b/game/enemy.odin @@ -1,29 +1,77 @@ package game Enemy :: struct { - position: Vec2, - health: int, - active: bool, - speed: f32, + position: Vec2, + health: int, + max_health: int, + active: bool, + path_index: int, + speed: f32, } -spawn_enemy :: proc(world: ^World) { +acquire_enemy :: proc(world: ^World) -> ^Enemy { + // create an object pool with fixed slots to reuse instead of allocate/free every spawn + for i in 0 ..< MAX_ENEMIES { + if !world.enemies[i].active { + return &world.enemies[i] + } + } + + return nil +} + +spawn_enemy :: proc(world: ^World, health: int, speed: f32) { if len(world.path) == 0 do return // don't spawn enemies if no paths exist - world.enemy = Enemy { - position = world.path[0], - health = 40, - speed = 60, - active = true, + e := acquire_enemy(world) // grab a free slot + if e == nil do return // if there are no slots, skil spawning + + e^ = Enemy { + position = world.path[0], + health = health, + max_health = health, + speed = speed, + path_index = 1, + active = true, } } -update_enemy :: proc(world: ^World, dt: f32) { - e := &world.enemy - if !e.active do return - if len(world.path) == 0 do return - - target := world.path[len(world.path) - 1] - move_toward(&e.position, target, e.speed, dt) +spawn_group :: proc(world: ^World, count: int) { + for _ in 0 ..< count { + spawn_enemy(world, 20, 60) + } +} + +update_enemies :: proc(world: ^World, dt: f32) { + for i in 0 ..< MAX_ENEMIES { + e := &world.enemies[i] + if !e.active do continue + + if len(world.path) == 2 do return + + if e.path_index >= len(world.path) { + world.base_health -= 1 + e.active = false + continue + } + + target := world.path[e.path_index] + move_toward(&e.position, target, e.speed, dt) + + dx := target.x - e.position.x + dy := target.y - e.position.y + if dx * dx + dy * dy < 16.0 { + e.path_index += 1 + } + } +} + +active_enemy_count :: proc(world: ^World) -> int { + count := 0 + for i in 0 ..< MAX_ENEMIES { + if world.enemies[i].active do count += 1 + } + + return count } diff --git a/game/render.odin b/game/render.odin index 925c44f..d9befed 100644 --- a/game/render.odin +++ b/game/render.odin @@ -15,8 +15,9 @@ render_world :: proc(world: ^World) { rl.DrawCircle(i32(p.x), i32(p.y), 3, rl.GOLD) } - if world.enemy.active { - e := world.enemy + for i in 0 ..< MAX_ENEMIES { + e := world.enemies[i] + if !e.active do continue rl.DrawCircle(i32(e.position.x), i32(e.position.y), 11, rl.MAROON) rl.DrawText( fmt.ctprintf("%d", e.health), @@ -25,9 +26,13 @@ render_world :: proc(world: ^World) { 12, rl.WHITE, ) + } + if (world.base_health == 0) { + rl.DrawText("**GAME OVER**", 20, 20, 20, rl.RED) } rl.DrawText(fmt.ctprintf("Gold: %d", world.gold), 10, 10, 20, rl.BLACK) // Gold HUD rl.DrawText(fmt.ctprintf("Base HP: %d", world.base_health), 10, 32, 20, rl.BLACK) // HP HUD + rl.DrawText(fmt.ctprintf("Enemies: %d", active_enemy_count(world)), 10, 54, 18, rl.DARKGRAY) } diff --git a/game/world.odin b/game/world.odin index 7f07d77..2f26b04 100644 --- a/game/world.odin +++ b/game/world.odin @@ -7,7 +7,7 @@ World :: struct { base_health: int, world_map: Map, path: [dynamic]Vec2, - enemy: Enemy, + enemies: [MAX_ENEMIES]Enemy, } init_world :: proc() -> World { @@ -27,9 +27,9 @@ update_world :: proc(world: ^World, dt: f32) { } if rl.IsKeyPressed(.SPACE) { - spawn_enemy(world) + spawn_group(world, 3) } - update_enemy(world, dt) + update_enemies(world, dt) }