enemy movement and object pool
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
+65
-17
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user