diff --git a/src/enemy.odin b/src/enemy.odin index 1d6f318..778e450 100644 --- a/src/enemy.odin +++ b/src/enemy.odin @@ -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.. 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.. 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..