Cache all A* pathfinding results

main
Cameron Murphy Reikes 2 years ago
parent 13dbe9ef27
commit fa1e3c2b18

112
main.c

@ -1,5 +1,5 @@
// you will die someday // you will die someday
#define CURRENT_VERSION 8 // wehenver you change Entity increment this boz #define CURRENT_VERSION 9 // wehenver you change Entity increment this boz
#define SOKOL_IMPL #define SOKOL_IMPL
#if defined(WIN32) || defined(_WIN32) #if defined(WIN32) || defined(_WIN32)
@ -580,6 +580,75 @@ typedef struct GameState {
Entity entities[MAX_ENTITIES]; Entity entities[MAX_ENTITIES];
} GameState; } GameState;
GameState gs = {0}; GameState gs = {0};
PathCache cached_paths[32] = {0};
bool is_path_cache_old(double elapsed_time, PathCache *cache)
{
double time_delta = elapsed_time - cache->elapsed_time;
if(time_delta < 0.0)
{
// path was cached in the future... likely from old save or something. Always invalidate
return true;
}
else
{
return time_delta >= TIME_BETWEEN_PATH_GENS;
}
}
PathCacheHandle cache_path(double elapsed_time, AStarPath *path)
{
ARR_ITER_I(PathCache, cached_paths, i)
{
if(!it->exists || is_path_cache_old(elapsed_time, it))
{
int gen = it->generation;
*it = (PathCache){0};
it->generation = gen + 1;
it->path = *path;
it->elapsed_time = elapsed_time;
it->exists = true;
return (PathCacheHandle){.generation = it->generation, .index = i};
}
}
return (PathCacheHandle){0};
}
// passes in the time to return 0 and invalidate if too old
PathCache *get_path_cache(double elapsed_time, PathCacheHandle handle)
{
if(handle.generation == 0)
{
return 0;
}
else
{
assert(handle.index >= 0);
assert(handle.index < ARRLEN(cached_paths));
PathCache *to_return = &cached_paths[handle.index];
if(to_return->exists && to_return->generation == handle.generation)
{
if(is_path_cache_old(elapsed_time, to_return))
{
to_return->exists = false;
return 0;
}
else
{
return to_return;
}
}
else
{
return 0;
}
}
}
double unprocessed_gameplay_time = 0.0; double unprocessed_gameplay_time = 0.0;
#define MINIMUM_TIMESTEP (1.0/60.0) #define MINIMUM_TIMESTEP (1.0/60.0)
@ -2528,8 +2597,19 @@ G H
SUM SUM
F cost: G + H F cost: G + H
*/ */
Vec2 from = it->pos;
Vec2 to = targeting->pos; Vec2 to = targeting->pos;
PathCache *cached = get_path_cache(elapsed_time, it->cached_path);
AStarPath path = {0};
bool succeeded = false;
if(cached)
{
path = cached->path;
succeeded = true;
}
else
{
Vec2 from = it->pos;
typedef struct AStarNode { typedef struct AStarNode {
bool exists; bool exists;
struct AStarNode * parent; struct AStarNode * parent;
@ -2540,7 +2620,7 @@ F cost: G + H
Vec2 pos; Vec2 pos;
} AStarNode; } AStarNode;
BUFF(AStarNode, 1024) nodes = {0}; BUFF(AStarNode, MAX_ASTAR_NODES) nodes = {0};
struct { Vec2 key; AStarNode *value; } *node_cache = 0; struct { Vec2 key; AStarNode *value; } *node_cache = 0;
#define V2_HASH(v) (FloorV2(v)) #define V2_HASH(v) (FloorV2(v))
const float jump_size = TILE_SIZE/2.0f; const float jump_size = TILE_SIZE/2.0f;
@ -2550,7 +2630,6 @@ F cost: G + H
hmput(node_cache, from_hash, &nodes.data[0]); hmput(node_cache, from_hash, &nodes.data[0]);
bool should_quit = false; bool should_quit = false;
bool succeeded = false;
AStarNode *last_node = 0; AStarNode *last_node = 0;
PROFILE_SCOPE("A* Pathfinding") // astar pathfinding a star PROFILE_SCOPE("A* Pathfinding") // astar pathfinding a star
while(!should_quit) while(!should_quit)
@ -2698,7 +2777,6 @@ F cost: G + H
node_cache = 0; node_cache = 0;
// reconstruct path // reconstruct path
BUFF(Vec2, ARRLEN(nodes.data)) path = {0};
if(succeeded) if(succeeded)
{ {
assert(last_node); assert(last_node);
@ -2710,17 +2788,35 @@ F cost: G + H
} }
} }
if(succeeded)
it->cached_path = cache_path(elapsed_time, &path);
}
Vec2 next_point_on_path = {0}; Vec2 next_point_on_path = {0};
if(succeeded) if(succeeded)
{ {
assert(path.cur_index > 0); float nearest_dist = INFINITY;
if(path.cur_index == 1) int nearest_index = -1;
Entity *from = it;
BUFF_ITER_I(Vec2, &path, i)
{
float dist = LenV2(SubV2(*it, from->pos));
if(dist < nearest_dist)
{
nearest_dist = dist;
nearest_index = i;
}
}
assert(nearest_index >= 0);
int target_index = (nearest_index + 1);
if(target_index >= path.cur_index)
{ {
next_point_on_path = to; next_point_on_path = to;
} }
else else
{ {
next_point_on_path = path.data[1]; next_point_on_path = path.data[target_index];
} }
} }

@ -149,6 +149,25 @@ typedef struct
float alive_for; float alive_for;
} PlayerAfterImage; } PlayerAfterImage;
#define MAX_ASTAR_NODES 1024
typedef BUFF(Vec2, MAX_ASTAR_NODES) AStarPath;
#define TIME_BETWEEN_PATH_GENS (0.5f)
typedef struct
{
bool exists;
int generation;
double elapsed_time;
AStarPath path;
} PathCache;
typedef struct
{
int generation;
int index;
} PathCacheHandle;
typedef struct Entity typedef struct Entity
{ {
bool exists; bool exists;
@ -186,6 +205,7 @@ typedef struct Entity
double characters_said; double characters_said;
NPCPlayerStanding standing; NPCPlayerStanding standing;
NpcKind npc_kind; NpcKind npc_kind;
PathCacheHandle cached_path;
ItemKind last_seen_holding_kind; ItemKind last_seen_holding_kind;
#ifdef WEB #ifdef WEB
int gen_request_id; int gen_request_id;

Loading…
Cancel
Save