Continue working on pathfinding

This commit is contained in:
attilavs2 2024-07-27 14:02:04 +02:00
parent 52da4be1af
commit 21a5659d58
2 changed files with 82 additions and 38 deletions

105
src/npc.c
View file

@ -34,7 +34,7 @@ float length( float x, float y )
int npc_clear_path(NPC *npc) int npc_clear_path(NPC *npc)
{ {
npc->currentPoint = 0; npc->currentPoint = 0;
npc->hasPath = 1; npc->hasPath = 0;
npc->path_length = 0; npc->path_length = 0;
free(npc->xpath); free(npc->xpath);
free(npc->ypath); free(npc->ypath);
@ -46,10 +46,10 @@ int npc_clear_path(NPC *npc)
int npc_append_path(uint16_t x, uint16_t y, NPC *npc) int npc_append_path(uint16_t x, uint16_t y, NPC *npc)
{ {
npc->path_length++; npc->xpath = realloc(npc->xpath, npc->path_length*2+2);
npc->xpath = realloc(npc->xpath, npc->path_length*2); npc->ypath = realloc(npc->ypath, npc->path_length*2+2);
npc->ypath = realloc(npc->ypath, npc->path_length*2);
if(npc->xpath == NULL || npc->ypath == NULL) return 1; if(npc->xpath == NULL || npc->ypath == NULL) return 1;
npc->path_length++;
npc->xpath[npc->path_length-1] = x - npc->x; npc->xpath[npc->path_length-1] = x - npc->x;
npc->ypath[npc->path_length-1] = y - npc->y; npc->ypath[npc->path_length-1] = y - npc->y;
return 0; return 0;
@ -73,12 +73,14 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
for(i = 0; i < 64; i++) for(i = 0; i < 64; i++)
{ {
if(next == -1) goto as_recons_fail; if(npc_append_path((next%w)*T_WIDTH,(next/h)*T_HEIGHT, npc))
if(npc_append_path(next%w, next/h, npc)) goto as_recons_fail; {
goto as_recons_fail;
}
next = came_from[next]; next = came_from[next];
if(next == spos){ if(next == spos){
if(npc_append_path(spos%w, spos/h, npc)) if(npc_append_path((spos%w)*T_WIDTH,(spos/h)*T_HEIGHT, npc))
goto as_recons_fail; goto as_recons_fail;
break; break;
} }
@ -88,18 +90,20 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
//Flip the path because it started from the end //Flip the path because it started from the end
for(i = 1; i < npc->path_length/2; i++) for(i = 0; i < npc->path_length/2; i++)
{ {
tx = npc->xpath[i]; tx = npc->xpath[i];
ty = npc->ypath[i]; ty = npc->ypath[i];
npc->xpath[i] = npc->xpath[npc->path_length-i]; npc->xpath[i] = npc->xpath[npc->path_length-i-1];
npc->ypath[i] = npc->ypath[npc->path_length-i]; npc->ypath[i] = npc->ypath[npc->path_length-i-1];
npc->ypath[npc->path_length-i] = tx; npc->ypath[npc->path_length-i-1] = tx;
npc->ypath[npc->path_length-i] = ty; npc->ypath[npc->path_length-i-1] = ty;
} }
free(came_from); free(came_from);
npc->hasPath = true;
return 0; return 0;
as_recons_fail: as_recons_fail:
@ -112,16 +116,21 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
//Returns non zero error code on failure //Returns non zero error code on failure
//Custom a* implemetation //Custom a* implemetation
//Unoptimized, may become an issue //Unoptimized, may become an issue
int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc)
{ {
uint32_t i, j; int32_t i, j;
int32_t w = full_map->w;
int32_t h = full_map->h;
int32_t x = floor(npc->curx)/T_WIDTH;
int32_t y = floor(npc->cury)/T_HEIGHT;
dest_x /= T_WIDTH;
dest_y /= T_HEIGHT;
int32_t spos = y*w+x;
uint32_t w = full_map->w;
uint32_t h = full_map->h;
uint32_t x = floor(npc->curx);
uint32_t y = floor(npc->cury);
uint32_t spos = y*w+x;
uint8_t *map = full_map->walkable; uint8_t *map = full_map->walkable;
if(dest_x < 0 || dest_x > w || dest_y < 0 || dest_x > h) return 2;
if(map[spos]) return 2; if(map[spos]) return 2;
if(map[dest_y*w+dest_x]) return 2; if(map[dest_y*w+dest_x]) return 2;
@ -134,26 +143,26 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc)
int16_t *came_from = malloc(w*h*2); int16_t *came_from = malloc(w*h*2);
for(i=0; i<w*h; i++) came_from[i] = -1; for(i=0; i<w*h; i++) came_from[i] = -1;
uint8_t *gscore = malloc(w*h); uint8_t *gscore = malloc(w*h*2);
for(i=0; i<w*h; i++) gscore[i] = 255; for(i=0; i<w*h; i++) gscore[i] = 255;
gscore[spos] = 0; gscore[spos] = 0;
uint8_t *fscore = malloc(w*h); uint8_t *fscore = malloc(w*h*2);
for(i=0; i<w*h; i++) fscore[i] = 255; for(i=0; i<w*h; i++) fscore[i] = 255;
fscore[spos] = length(dest_x-x, dest_y-y); fscore[spos] = length(dest_x-x, dest_y-y);
uint8_t bscore; uint8_t bscore;
uint32_t bx = x; int32_t bx = x;
uint32_t by = y; int32_t by = y;
for(int iter=0; iter < 1024; iter++) for(int iter=0; iter < 64; iter++)
{ {
bscore = 255; bscore = 255;
//Cheapest known tile //Cheapest known tile
for(i = 0; i <= w*h; i++) for(i = 0; i <= w*h; i++)
{ {
if(visited[i]) continue; if(visited[i]) continue;
if(map[i]) continue; if(map[i] == 1) continue;
if(fscore[i] > bscore) continue; if(fscore[i] > bscore) continue;
bx = i%w; bx = i%w;
by = i/w; by = i/w;
@ -162,7 +171,8 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc)
if(bx == dest_x && by == dest_y) if(bx == dest_x && by == dest_y)
{ {
as_clean(visited, gscore, fscore); as_clean(visited, gscore, fscore);
return as_reconstruct_path(came_from, w, h, spos, dest_y*w+dest_x, npc); return as_reconstruct_path(came_from, w, h, spos,
dest_y*w+dest_x, npc);
} }
visited[by*w+bx] = 1; visited[by*w+bx] = 1;
@ -174,14 +184,16 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc)
if(i > w) break; if(i > w) break;
for(j = by-1; j < by+2; j++) for(j = by-1; j < by+2; j++)
{ {
if(j > h ) break; if(j > h) break;
if(map[j*w+i]) continue; if(map[j*w+i] == 1) continue;
att_score = gscore[by*w+bx] + ceil(length(bx-i,by-j)); if(i == bx && j == by) continue;
att_score = gscore[by*w+bx] + round(length(bx-i,by-j));
if(att_score < gscore[j*w+i]) if(att_score < gscore[j*w+i])
{ {
came_from[j*w+i] = by*w+bx; came_from[j*w+i] = by*w+bx;
gscore[j*w+i] = att_score; gscore[j*w+i] = att_score;
fscore[j*w+i] = att_score + ceil(length(dest_x-i, dest_y-j)); fscore[j*w+i] = att_score + round(
length(dest_x-i, dest_y-j));
if(visited[j*w+i]) visited[j*w+i] = 0; if(visited[j*w+i]) visited[j*w+i] = 0;
} }
} }
@ -194,11 +206,34 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc)
return 3; return 3;
} }
NPC *npc_create()
{
//Use temp pointer to avoid breaking the whole npcRPG on failure
void *temp = realloc(npcRPG, (nbNPC+1)*sizeof(NPC));
if(temp == NULL) return NULL;
npcRPG = temp;
nbNPC++;
NPC *npc = &npcRPG[nbNPC-1];
npc->xpath = malloc(2);
npc->ypath = malloc(2);
return npc;
}
void npc_remove(NPC *npc)
{
uint32_t pos = ((uint32_t)npc - (uint32_t)npcRPG)/sizeof(NPC);
if(pos > nbNPC-1) return;
if(pos == nbNPC-1)
{
nbNPC--;
return;
}
memmove(npc, &npc[1], (nbNPC-pos-1)*sizeof(NPC));
}
//Refactoring to make adding complexity cleaner //Refactoring to make adding complexity cleaner
void update_npcs([[maybe_unused]] Game *game) void update_npcs([[maybe_unused]] Game *game)
{ {
//npc_pathfind(game->player.x, game->player.y, game->map_level, &npcRPG[0]);
for( uint32_t u=0; u<nbNPC; u++ ) for( uint32_t u=0; u<nbNPC; u++ )
{ {
update_npc(&npcRPG[u]); update_npc(&npcRPG[u]);
@ -207,8 +242,8 @@ void update_npcs([[maybe_unused]] Game *game)
void update_npc(NPC *npc) void update_npc(NPC *npc)
{ {
/* if the NPC has no path and is paused, skip it */ /* if the NPC has no path or is paused, skip it */
if (!npc->hasPath && npc->paused==true) return; if (!npc->hasPath || npc->paused==true) return;
float vecX = (float) (npc->xpath[ npc->currentPoint ] + float vecX = (float) (npc->xpath[ npc->currentPoint ] +
npc->x) - npc->curx; npc->x) - npc->curx;
@ -232,7 +267,6 @@ void update_npc(NPC *npc)
} }
//TODO ; Add malloc() failure case
void reload_npc(Game *game) void reload_npc(Game *game)
{ {
if (npcRPG!=NULL) if (npcRPG!=NULL)
@ -256,6 +290,7 @@ void reload_npc(Game *game)
} }
npcRPG = (NPC*) malloc( nbNPC * sizeof(NPC) ); npcRPG = (NPC*) malloc( nbNPC * sizeof(NPC) );
if(npcRPG == NULL) return;
int currentNPC=0; int currentNPC=0;
for (uint32_t u=0; u<game->map_level->nbextradata; u++) for (uint32_t u=0; u<game->map_level->nbextradata; u++)

View file

@ -38,12 +38,14 @@ typedef struct
int16_t *xpath; int16_t *xpath;
int16_t *ypath; int16_t *ypath;
int type;
int8_t current_group;
int8_t hostile_to_group; int8_t hostile_to_group;
/* is the current NPC in pause (during dialog) */ /* is the current NPC in pause (during dialog) */
bool paused; bool paused;
} NPC; } NPC;
//Frees then malloc()s a new path to npc //Frees then malloc()s a new path to npc
@ -57,7 +59,14 @@ int npc_append_path(uint16_t x, uint16_t y, NPC *npc);
//Clears the NPCs path and creates a new one going to dest, //Clears the NPCs path and creates a new one going to dest,
//avoiding non-walkable tiles //avoiding non-walkable tiles
//Returns non-zero on failure //Returns non-zero on failure
int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc); int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc);
//realloc()s npcRPG to adequate size and returns a pointer to the new element
//Returns NULL on failure
NPC *npc_create();
//Pops the NPC from npcRPG
void npc_remove(NPC *npc);
/* Draws the player player. This function should be called after drawing the /* Draws the player player. This function should be called after drawing the
* map! */ * map! */