From 4bb3e710c11fa78965a0673716289463ec3e84ab Mon Sep 17 00:00:00 2001 From: codegirl-007 Date: Tue, 23 Jun 2026 21:44:50 -0700 Subject: [PATCH] Add different enemy types (Runner) --- game/enemy.odin | 58 +++++++++++++++++++++++++++++++++++++++---------- game/wave.odin | 6 ++++- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/game/enemy.odin b/game/enemy.odin index 54be1a2..5a7a77d 100644 --- a/game/enemy.odin +++ b/game/enemy.odin @@ -12,8 +12,41 @@ Enemy :: struct { path_index: int, base_speed: f32, slow_timer: f32, + kind: Enemy_Kind, } +Enemy_Kind :: enum { + Grunt, + Runner, +} + +Enemy_Archetype :: struct { + kind: Enemy_Kind, + health: int, + speed: f32, + color: rl.Color, +} + +get_enemy_archetype :: proc(kind: Enemy_Kind, wave: int) -> Enemy_Archetype { + switch kind { + case .Grunt: + return { + kind = .Grunt, + health = 15 + wave * 5, + speed = 55 + f32(wave) * 5, + color = rl.MAROON, + } + case .Runner: + return { + kind = .Runner, + health = 10 + wave * 2, + speed = 95 + f32(wave) * 3, + color = rl.ORANGE, + } + } + + return {} +} 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 { @@ -25,29 +58,25 @@ acquire_enemy :: proc(world: ^World) -> ^Enemy { return nil } -spawn_enemy :: proc(world: ^World, health: int, speed: f32) { +spawn_enemy :: proc(world: ^World, kind: Enemy_Kind) { if len(world.path) == 0 do return // don't spawn enemies if no paths exist e := acquire_enemy(world) // grab a free slot if e == nil do return // if there are no slots, skil spawning + arch := get_enemy_archetype(kind, world.wave) e^ = Enemy { position = world.path[0], - health = health, - max_health = health, - base_speed = speed, + health = arch.health, + max_health = arch.health, + base_speed = arch.speed, slow_timer = 0, path_index = 1, + kind = kind, active = true, } } -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] @@ -90,7 +119,14 @@ render_enemies :: proc(world: ^World) { 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) + color := rl.MAROON + switch e.kind { + case .Grunt: + color = rl.MAROON + case .Runner: + color = rl.ORANGE + } + rl.DrawCircle(i32(e.position.x), i32(e.position.y), 11, color) if e.slow_timer > 0 { rl.DrawCircleLines(i32(e.position.x), i32(e.position.y), 14, rl.SKYBLUE) } diff --git a/game/wave.odin b/game/wave.odin index 816a22a..1536534 100644 --- a/game/wave.odin +++ b/game/wave.odin @@ -11,6 +11,7 @@ Wave_Spawner :: struct { enemies_to_spawn: int, spawn_timer: f32, spawn_interval: f32, + spawn_count: int, } start_wave :: proc(world: ^World) { @@ -30,10 +31,13 @@ update_wave :: proc(world: ^World, dt: f32) { if len(world.path) < 2 do return world.spawner.spawn_timer -= dt + kind := Enemy_Kind.Grunt + if world.spawner.spawn_count % 3 == 2 do kind = .Runner if world.spawner.spawn_timer <= 0 { health := 15 + world.wave * 5 speed := 55 + f32(world.wave) * 5 - spawn_enemy(world, health, speed) + spawn_enemy(world, kind) + world.spawner.spawn_count += 1 world.spawner.enemies_to_spawn -= 1 world.spawner.spawn_timer = world.spawner.spawn_interval }