Setup basic enemy information and make enemy use flow field.

This commit is contained in:
2026-08-03 06:40:17 +02:00
parent 5a0256d60d
commit beec7c23cd
+55 -4
View File
@@ -16,7 +16,9 @@ Enemy :: struct {
// movement // movement
velocity: rl.Vector2, velocity: rl.Vector2,
speed: f32, speed: f32, // max move speed
accel: f32, // how fast to reach speed
friction: f32, // how fast to stop
// collision // collision
collider_offset: rl.Vector2, collider_offset: rl.Vector2,
@@ -27,10 +29,14 @@ Enemy :: struct {
enemy_init :: proc(assets: ^Enemy_Assets, pos: [2]f32) -> Enemy { enemy_init :: proc(assets: ^Enemy_Assets, pos: [2]f32) -> Enemy {
enemy := Enemy{} enemy := Enemy{}
enemy.position = {pos.x, pos.y} enemy.position = {pos.x, pos.y}
enemy.speed = 100
enemy.accel = 720
enemy.friction = 640
enemy.state = .IDLE enemy.state = .IDLE
enemy.collider_offset = rl.Vector2{8, 15} enemy.collider_offset = rl.Vector2{8, 15}
enemy.collider_w = 16 enemy.collider_w = 12
enemy.collider_h = 10 enemy.collider_h = 8
animation_play(&enemy.animation, &assets.clips[.IDLE]) animation_play(&enemy.animation, &assets.clips[.IDLE])
return enemy return enemy
@@ -45,6 +51,13 @@ get_enemy_collider :: proc(enemy: Enemy, pos: rl.Vector2) -> rl.Rectangle {
} }
} }
get_enemy_center :: proc(enemy: Enemy, pos: rl.Vector2) -> rl.Vector2 {
collider := get_enemy_collider(enemy, pos)
return rl.Vector2{
collider.x + collider.width * 0.5,
collider.y + collider.height * 0.5,
}
}
get_spawn_rect :: proc(max_x, max_y: f32) -> rl.Rectangle { get_spawn_rect :: proc(max_x, max_y: f32) -> rl.Rectangle {
enemy_spawn_points: [4]rl.Rectangle = { enemy_spawn_points: [4]rl.Rectangle = {
@@ -63,6 +76,7 @@ get_spawn_rect :: proc(max_x, max_y: f32) -> rl.Rectangle {
return rand_pos return rand_pos
} }
// @TODO consider a self check, ie pass the enemy in question index and make sure to skip that // @TODO consider a self check, ie pass the enemy in question index and make sure to skip that
spawn_enemy :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, enemy_count: ^int, game_map: Game_Map) { spawn_enemy :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, enemy_count: ^int, game_map: Game_Map) {
max_x := game_map.width_px max_x := game_map.width_px
@@ -91,10 +105,47 @@ spawn_enemy :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, ene
} }
} }
update_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, enemy_cnt: int, dt: f32) { update_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, enemy_cnt: int, game_map: Game_Map, dt: f32) {
for idx in 0..<enemy_cnt { for idx in 0..<enemy_cnt {
enemy := &enemy_array[idx] enemy := &enemy_array[idx]
moving := false moving := false
dir := rl.Vector2{}
enemy_center := get_enemy_center(enemy^, enemy.position)
enemy_grid_pos := world_to_grid(enemy_center)
enemy_grid_index := grid_to_index(enemy_grid_pos.x, enemy_grid_pos.y, game_map.width)
// already normalized
flow_dir := game_map.flow_field[enemy_grid_index]
// wall avoidance steering
target_velocity := flow_dir * enemy.speed
enemy.velocity = rl.Vector2MoveTowards(enemy.velocity, target_velocity, enemy.accel * dt)
// Check for collisions
new_position := enemy.velocity * dt
new_x_pos := rl.Vector2{enemy.position.x + new_position.x, enemy.position.y}
if
!check_map_collision(get_enemy_collider(enemy^, new_x_pos), game_map)
{
enemy.position.x = new_x_pos.x
moving = true
} else {
enemy.velocity.x = 0
moving = false
}
new_y_pos := rl.Vector2{enemy.position.x, enemy.position.y + new_position.y}
if
!check_map_collision(get_enemy_collider(enemy^, new_y_pos), game_map)
{
enemy.position.y = new_y_pos.y
moving = true
} else {
enemy.velocity.y = 0
moving = false
}
enemy.state = moving ? .WALK : .IDLE enemy.state = moving ? .WALK : .IDLE
animation_play(&enemy.animation, &assets.clips[enemy.state]) animation_play(&enemy.animation, &assets.clips[enemy.state])