fp: Precalculate the collision grid before the A* process
This commit is contained in:
parent
eceb4a3a21
commit
f431be1b29
@ -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)
|
||||
|
@ -159,4 +159,5 @@ struct FP_GameAStarNode
|
||||
Dqn_usize cost;
|
||||
Dqn_usize heuristic;
|
||||
Dqn_V2I came_from;
|
||||
bool non_traversable;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user