Setup awareness for walls and other entities.
This commit is contained in:
+88
-9
@@ -76,6 +76,10 @@ get_spawn_rect :: proc(max_x, max_y: f32) -> rl.Rectangle {
|
||||
return rand_pos
|
||||
}
|
||||
|
||||
// true when the enemy's candidate rect overlaps the player
|
||||
check_player_collision :: proc(rect: rl.Rectangle, player: ^Player) -> bool {
|
||||
return rl.CheckCollisionRecs(rect, get_player_collider(player, player.position))
|
||||
}
|
||||
|
||||
// @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) {
|
||||
@@ -92,7 +96,7 @@ spawn_enemy :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, ene
|
||||
|
||||
for attempt := 0; !valid_pos && attempt < MAX_ATTEMPTS; attempt += 1 {
|
||||
enemy_rect = get_spawn_rect(max_x, max_y)
|
||||
valid_pos = !check_map_collision(enemy_rect, game_map) && !check_enemy_collision(enemy_rect, cnt, enemy_array)
|
||||
valid_pos = !check_map_collision(enemy_rect, game_map) && !check_enemy_collision(enemy_rect, -1, cnt, enemy_array)
|
||||
}
|
||||
if !valid_pos {
|
||||
return // couldn't find a spot this call, skip spawning
|
||||
@@ -105,7 +109,7 @@ 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, game_map: Game_Map, dt: f32) {
|
||||
update_enemies :: proc(player: ^Player, enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets, enemy_cnt: int, game_map: Game_Map, dt: f32) {
|
||||
for idx in 0..<enemy_cnt {
|
||||
enemy := &enemy_array[idx]
|
||||
moving := false
|
||||
@@ -115,19 +119,25 @@ update_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets,
|
||||
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
|
||||
// get dir from flow field already normalized
|
||||
flow_dir := game_map.flow_field[enemy_grid_index]
|
||||
|
||||
// wall avoidance steering
|
||||
// check around enemies for separation of neighbors
|
||||
enemy_push := get_enemy_separation(idx, enemy_cnt, enemy_array)
|
||||
wall_push := get_wall_separation(enemy, game_map)
|
||||
steer_dir := rl.Vector2Normalize(flow_dir + enemy_push + wall_push)
|
||||
target_velocity := steer_dir * enemy.speed
|
||||
|
||||
target_velocity := flow_dir * enemy.speed
|
||||
|
||||
enemy.velocity = rl.Vector2MoveTowards(enemy.velocity, target_velocity, enemy.accel * dt)
|
||||
// Check for collisions
|
||||
// target_velocity := flow_dir * enemy.speed
|
||||
enemy.velocity = rl.Vector2MoveTowards(enemy.velocity, target_velocity, enemy.accel * dt)
|
||||
|
||||
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)
|
||||
!check_map_collision(get_enemy_collider(enemy^, new_x_pos), game_map) &&
|
||||
!check_enemy_collision(get_enemy_collider(enemy^, new_x_pos), idx, enemy_cnt, enemy_array) &&
|
||||
!check_player_collision(get_enemy_collider(enemy^, new_x_pos), player)
|
||||
{
|
||||
enemy.position.x = new_x_pos.x
|
||||
moving = true
|
||||
@@ -136,9 +146,12 @@ update_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets,
|
||||
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)
|
||||
!check_map_collision(get_enemy_collider(enemy^, new_y_pos), game_map) &&
|
||||
!check_enemy_collision(get_enemy_collider(enemy^, new_y_pos), idx, enemy_cnt, enemy_array) &&
|
||||
!check_player_collision(get_enemy_collider(enemy^, new_y_pos), player)
|
||||
{
|
||||
enemy.position.y = new_y_pos.y
|
||||
moving = true
|
||||
@@ -154,6 +167,72 @@ update_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, assets: ^Enemy_Assets,
|
||||
}
|
||||
}
|
||||
|
||||
get_wall_separation:: proc(enemy: ^Enemy, game_map: Game_Map) -> rl.Vector2 {
|
||||
// how close another enemy needs to be before we push away from them
|
||||
distance_check: f32 = TILE_SIZE
|
||||
total_push := rl.Vector2{}
|
||||
|
||||
current_enemy_center := get_enemy_center(enemy^, enemy.position)
|
||||
enemy_grid := world_to_grid(current_enemy_center)
|
||||
min_grid := Grid_Pos(rl.Vector2{f32(enemy_grid.x - 1), f32(enemy_grid.y - 1)})
|
||||
max_grid := Grid_Pos(rl.Vector2{f32(enemy_grid.x + 1), f32(enemy_grid.y + 1)})
|
||||
|
||||
for gy := min_grid[1]; gy <= max_grid[1]; gy += 1 {
|
||||
for gx := min_grid[0]; gx <= max_grid[0]; gx += 1 {
|
||||
|
||||
// bounds check
|
||||
if gx < 0 || gx >= game_map.width || gy < 0 || gy >= game_map.height do continue
|
||||
|
||||
idx := (gy * game_map.width) + gx
|
||||
tile := Tile_Type(game_map.data[idx])
|
||||
def := tile_defs[tile]
|
||||
|
||||
if def.solid {
|
||||
tile_grid := grid_to_world(gx, gy)
|
||||
tile_grid.x += TILE_SIZE / 2
|
||||
tile_grid.y += TILE_SIZE / 2
|
||||
|
||||
distance_between := rl.Vector2Distance(tile_grid, current_enemy_center)
|
||||
|
||||
if distance_between < distance_check {
|
||||
// vector pointing away from the other enemy, stronger the closer they are
|
||||
// (not normalized — closer enemies naturally produce a bigger vector here)
|
||||
total_push += (current_enemy_center - tile_grid)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return total_push
|
||||
}
|
||||
|
||||
get_enemy_separation :: proc(self_idx: int, active_enemies: int, enemies: ^[MAX_ENEMIES]Enemy) -> rl.Vector2 {
|
||||
// how close another enemy needs to be before we push away from them
|
||||
distance_check: f32 = TILE_SIZE / 2
|
||||
|
||||
current_enemy := enemies[self_idx]
|
||||
current_enemy_center := get_enemy_center(current_enemy, current_enemy.position)
|
||||
|
||||
// adds the combined push-away value of every nearby enemy
|
||||
total_push := rl.Vector2{}
|
||||
|
||||
for idx in 0..<active_enemies {
|
||||
if idx == self_idx do continue
|
||||
|
||||
other_enemy := enemies[idx]
|
||||
other_enemy_center := get_enemy_center(other_enemy, other_enemy.position)
|
||||
distance_between := rl.Vector2Distance(current_enemy_center, other_enemy_center)
|
||||
|
||||
if distance_between < distance_check {
|
||||
// vector pointing away from the other enemy, stronger the closer they are
|
||||
// (not normalized — closer enemies naturally produce a bigger vector here)
|
||||
total_push += (current_enemy_center - other_enemy_center)
|
||||
}
|
||||
}
|
||||
|
||||
return total_push
|
||||
}
|
||||
|
||||
draw_enemies :: proc(enemy_array: ^[MAX_ENEMIES]Enemy, enemy_cnt: int) {
|
||||
for idx in 0..<enemy_cnt {
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ game_update :: proc(game: ^Game) {
|
||||
update_camera(&game.player, &game.camera, game.current_map.width_px, game.current_map.height_px)
|
||||
|
||||
if update_timer(&game.enenmy_spawn_timer, dt) do spawn_enemy(&game.enemies, &game.assets.enemy, &game.enemy_count, game.current_map)
|
||||
update_enemies(&game.enemies, &game.assets.enemy, game.enemy_count, game.current_map, dt)
|
||||
update_enemies(&game.player, &game.enemies, &game.assets.enemy, game.enemy_count, game.current_map, dt)
|
||||
}
|
||||
|
||||
// @ DEBUG
|
||||
|
||||
+2
-1
@@ -184,8 +184,9 @@ check_map_collision :: proc(rect: rl.Rectangle, game_map: Game_Map) -> bool {
|
||||
}
|
||||
|
||||
// true when collision found
|
||||
check_enemy_collision :: proc(rect_a: rl.Rectangle, active_enemies: int, enemies: ^[MAX_ENEMIES]Enemy) -> bool {
|
||||
check_enemy_collision :: proc(rect_a: rl.Rectangle, self_idx: int, active_enemies: int, enemies: ^[MAX_ENEMIES]Enemy) -> bool {
|
||||
for idx in 0..<active_enemies {
|
||||
if idx == self_idx do continue
|
||||
e := enemies[idx]
|
||||
enemy_rect := get_enemy_collider(e, e.position)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user