fp: Precalculate the collision grid before the A* process

This commit is contained in:
doyle 2023-09-23 15:52:26 +10:00
parent eceb4a3a21
commit f431be1b29
2 changed files with 19 additions and 22 deletions

View File

@ -468,6 +468,8 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
FP_GameEntityHandle entity,
Dqn_V2I dest_tile)
{
Dqn_DSMap<FP_GameAStarNode> astar_info = Dqn_DSMap_Init<FP_GameAStarNode>(128);
DQN_DEFER { Dqn_DSMap_Deinit(&astar_info); };
// NOTE: Enumerate the entities that are collidable ============================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
@ -480,16 +482,25 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
if ((walk_entity->flags & FP_GameEntityFlag_NonTraversable) == 0)
continue;
Dqn_List_Add(&colliders, walk_entity);
// NOTE: Mark tiles that the entity is on as non-traversable
Dqn_Rect bounding_box = FP_Game_CalcEntityWorldBoundingBox(game, walk_entity->handle);
Dqn_RectMinMax min_max = Dqn_Rect_MinMax(bounding_box);
Dqn_V2I min_tile = FP_Game_WorldPosToTilePos(game, min_max.min);
Dqn_V2I max_tile = FP_Game_WorldPosToTilePos(game, min_max.max);
for (int32_t y = min_tile.y; y < max_tile.y; y++) {
for (int32_t x = min_tile.x; x < max_tile.x; x++) {
uint64_t tile_u64 = (DQN_CAST(uint64_t)y << 32) | (DQN_CAST(uint64_t)x << 0);
FP_GameAStarNode *node = Dqn_DSMap_MakeKeyU64(&astar_info, tile_u64).value;
node->non_traversable = true;
}
}
}
// NOTE: Setup A* state ========================================================================
Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity);
Dqn_V2I src_tile = FP_Game_WorldPosToTilePos(game, entity_world_pos);
Dqn_DSMap<FP_GameAStarNode> astar_info = Dqn_DSMap_Init<FP_GameAStarNode>(128);
DQN_DEFER { Dqn_DSMap_Deinit(&astar_info); };
Dqn_FArray<Dqn_V2I, 128> frontier = {};
Dqn_FArray_Add(&frontier, src_tile);
@ -535,26 +546,11 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
uint64_t next_tile_u64 = (DQN_CAST(uint64_t)next_tile.y << 32) | (DQN_CAST(uint64_t)next_tile.x << 0);
Dqn_DSMapResult<FP_GameAStarNode> next_cost_result = Dqn_DSMap_MakeKeyU64(&astar_info, next_tile_u64);
// NOTE: If we have already visited this node before, we only keep the cost if it's cheaper
if (next_cost_result.found && new_cost >= next_cost_result.value->cost)
if (next_cost_result.value->non_traversable)
continue;
// NOTE: Check if the neighbour is a non-traversable tile, if so we skip it
bool tile_is_non_traversable = false;
for (Dqn_ListIterator<FP_GameEntity const *> it = {}; Dqn_List_Iterate(&colliders, &it, 0); ) {
FP_GameEntity const *collider = *it.data;
Dqn_Rect bounding_box = FP_Game_CalcEntityWorldBoundingBox(game, collider->handle);
Dqn_RectMinMax min_max = Dqn_Rect_MinMax(bounding_box);
Dqn_V2I min_tile = FP_Game_WorldPosToTilePos(game, min_max.min);
Dqn_V2I max_tile = FP_Game_WorldPosToTilePos(game, min_max.max);
if ((next_tile.x >= min_tile.x && next_tile.x <= max_tile.x) &&
(next_tile.y >= min_tile.y && next_tile.y <= max_tile.y)) {
tile_is_non_traversable = true;
}
}
if (tile_is_non_traversable)
// NOTE: If we have already visited this node before, we only keep the cost if it's cheaper
if (next_cost_result.found && new_cost >= next_cost_result.value->cost)
continue;
// NOTE: Update the node cost value and the heuristic (estimated cost to the end)

View File

@ -159,4 +159,5 @@ struct FP_GameAStarNode
Dqn_usize cost;
Dqn_usize heuristic;
Dqn_V2I came_from;
bool non_traversable;
};