From ee3b25a3663bf193613b3ee8d83fd32f857045a4 Mon Sep 17 00:00:00 2001 From: attilavs2 Date: Tue, 6 Aug 2024 15:36:34 +0200 Subject: [PATCH] npc : Simplification de npc_pathfinding + tentative collision de npcs + suppression de map_draw --- src/map.c | 99 ------------------------------------------ src/npc.c | 120 ++++++++++++++++++++++++++++++++++----------------- src/npc.h | 8 ++-- src/player.c | 1 - src/player.h | 2 + 5 files changed, 87 insertions(+), 143 deletions(-) diff --git a/src/map.c b/src/map.c index f4b2fc7..220fd16 100644 --- a/src/map.c +++ b/src/map.c @@ -14,105 +14,6 @@ extern Map level4; Map *worldRPG[] = {&level0, &level1, &level2, &level3, &level4, NULL}; -// extern ExtraData *extraRPG[]; - -void map_render(Game *game) { - - Map *map_level = game->map_level; - Player *player = &game->player; - - /* for all Layer (2 in the current configuration: Background is layer 0 and - * foreground is layer 1 ) */ - /* x and y will contain the position in the loop. */ - unsigned char x, y; - /* The positions where we start drawing the tiles will be in tx and - * ty. */ - unsigned short int tx, ty; - /* mx and my will contain how many pixels will be hidden on x and on - * y. */ - unsigned char mx, my; - /* dw and dh contain the amount of tiles that will be drawn on x and on - * y. */ - unsigned char dw = DWIDTH / T_WIDTH + 2, dh = DHEIGHT / T_HEIGHT + 1; - /* mw and mh will contain the height and the width of the map. */ - unsigned short int mw = map_level->w * T_WIDTH, - mh = map_level->h * T_HEIGHT; - /* tile contains the tile to draw. */ - short int tile; - /* The position where I start drawing */ - unsigned short int sx, sy; - /* The position of the tile in the tileset. */ - unsigned short int xtile, ytile; - /* The layer we're drawing */ - unsigned char l; - /* The index of the current tile we're drawing in the layer. */ - int current_index; - /* Fix sx. */ - if(player->x < DWIDTH / 2) { - /* If I can't center the player because I'm near the left border of - * the map. */ - player->px = player->x; - sx = 0; - } else if(player->x + DWIDTH / 2 > mw) { - /* If I can't center the player because I'm near the right border of - * the map. */ - sx = mw - DWIDTH; - player->px = player->x - sx; - } else { - /* I can center the player. */ - player->px = DWIDTH / 2; - sx = player->x - player->px; - } - /* Fix sy. */ - if(player->y < DHEIGHT / 2) { - /* If I can't center the player because I'm near the top border of - * the map. */ - player->py = player->y; - sy = 0; - } else if(player->y + DHEIGHT / 2 > mh) { - /* If I can't center the player because I'm near the bottom border - * of the map. */ - sy = mh - DHEIGHT; - player->py = player->y - sy; - } else { - /* I can center the player. */ - player->py = DHEIGHT / 2; - sy = player->y - player->py; - } - tx = sx / T_WIDTH; - ty = sy / T_HEIGHT; - mx = sx - tx * T_WIDTH; - my = sy - ty * T_HEIGHT; - for(l = 0; l < map_level->nblayers - 1; l++) { - /* Draw a layer of the map on screen. */ - for(y = 0; y < dh; y++) { - for(x = 0; x < dw; x++) { - /* I get the tile number if his position is inside the map. Then - * I draw it. */ - if(tx + x >= 0 && tx + x < map_level->w && ty + y >= 0 && - ty + y < map_level->h) { - /* index of the current tile */ - current_index = (y + ty) * map_level->w + tx + x; - /* we get the ID of the tile in the current drawable layers - */ - tile = map_level->layers[l][current_index]; - - /* tile == -1 means nothing to be drawn */ - if(tile >= 0) { - /* get x and y position in the tileset image */ - xtile = (tile % map_level->tileset_size) * T_WIDTH; - ytile = (tile / map_level->tileset_size) * T_HEIGHT; - /* render */ - dsubimage(x * T_WIDTH - mx, y * T_HEIGHT - my, - map_level->tileset, xtile, ytile, T_WIDTH, - T_HEIGHT, DIMAGE_NONE); - } - } - } - } - } -} - void map_render_by_layer(Game *game, int layer) { Map *map_level = game->map_level; diff --git a/src/npc.c b/src/npc.c index 4442246..50bbaea 100644 --- a/src/npc.c +++ b/src/npc.c @@ -4,6 +4,7 @@ #include "dialogs.h" #include "game.h" #include "map.h" +#include "player.h" #include #include @@ -20,6 +21,9 @@ extern bopti_image_t tiny_npc_police; NPC npc_stack[NPC_STACK_SIZE]; uint32_t npc_count; +extern const char one_px_mov[8]; +extern const short int walkable_speed[WALKABLE_TILE_MAX]; + NPC *npc_create() { if(npc_count == NPC_STACK_SIZE) return NULL; @@ -54,6 +58,33 @@ void npc_remove(NPC *npc) { void npc_remove_pos(uint32_t pos) { npc_remove(&npc_stack[pos]); } +/*Takes input in curx/cury*/ +bool npc_collision(Game *game, NPC *npc, int32_t dx, int32_t dy) { + /* Handle a negative position differently than a positive one. */ + if(dx < 0) + dx = dx / T_WIDTH - 1; + else + dx = dx / T_WIDTH; + + if(dy < 0) + dy = dy / T_HEIGHT - 1; + else + dy = dy / T_HEIGHT; + + int on_walkable = map_get_walkable(game, dx, dy); + + int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) + ? walkable_speed[on_walkable] + : 0; + + /* if he's on a hard tile */ + if(!speed) { + return true; /* He will collide with it. */ + } + + return false; /* He won't collide with a hard tile. */ +} + float length(float x, float y) { return sqrtf(x * x + y * y); } int npc_clear_path(NPC *npc) { @@ -73,7 +104,7 @@ int npc_clear_path(NPC *npc) { npc->owns_path = true; return 0; } - +/*Takes input as absolute pixel position (/PXSIZE)*/ int npc_append_path(int16_t x, int16_t y, NPC *npc) { npc->xpath = realloc(npc->xpath, npc->path_length * 2 + 2); npc->ypath = realloc(npc->ypath, npc->path_length * 2 + 2); @@ -91,7 +122,8 @@ void as_clean(uint8_t *visited, uint8_t *gscore, uint8_t *fscore) { free(fscore); } -int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc){ +/*Takes input as pixel position*/ +int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { uint8_t *map = full_map->walkable; uint32_t w = full_map->w; uint32_t h = full_map->h; @@ -100,10 +132,11 @@ int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc){ dest_x /= PXSIZE; dest_y /= PXSIZE; - if(dest_x < 0 || dest_y < 0 || dest_x >= w*T_WIDTH || dest_y >= h*T_HEIGHT) + if(dest_x < 0 || dest_y < 0 || dest_x >= w * T_WIDTH || + dest_y >= h * T_HEIGHT) return 2; - /*if(map[dest_y*w + dest_x]) + /*if(map[(dest_y/T_HEIGHT)*w + dest_x/T_WIDTH]) return 2; if(map[sy*w + sx]) return 2;*/ @@ -111,24 +144,7 @@ int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc){ if(!npc->owns_path || npc->path_length > 64) npc_clear_path(npc); - /*int bx; - int by; - int bscore = 0x7FFFFFFF; - - for(int i = sx-1; i < sx+2; i++){ - for(int j = sy-1; j < sy+2; j++){ - int tscore = (dest_x-sx)*(dest_x-sx) + (dest_y-sy)*(dest_y-sy); - if(tscore < bscore){ - bscore = tscore; - bx = i; - by = j; - } - } - } - - if(bscore == 0x7FFFFFFF) return 3;*/ - - if(npc_append_path(dest_x,dest_y, npc)) + if(npc_append_path(dest_x, dest_y, npc)) return 1; npc->hasPath = true; @@ -146,16 +162,16 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t start, int x, y; for(i = 0; i < PATHFIND_MAX_ITER; i++) { - x = ((prev%w)*T_WIDTH + T_WIDTH/2) << PRECISION; - y = ((prev/w)*T_HEIGHT + T_HEIGHT/2) << PRECISION; - if(npc_append_path(x,y,npc)) { + x = ((prev % w) * T_WIDTH + T_WIDTH / 2) << PRECISION; + y = ((prev / w) * T_HEIGHT + T_HEIGHT / 2) << PRECISION; + if(npc_append_path(x, y, npc)) { goto as_recons_fail; } prev = came_from[prev]; - if(prev == start){ - x = ((prev%w)*T_WIDTH + T_WIDTH/2) << PRECISION; - y = ((prev/w)*T_HEIGHT + T_HEIGHT/2) << PRECISION; - if(npc_append_path(x,y,npc)) + if(prev == start) { + x = ((prev % w) * T_WIDTH + T_WIDTH / 2) << PRECISION; + y = ((prev / w) * T_HEIGHT + T_HEIGHT / 2) << PRECISION; + if(npc_append_path(x, y, npc)) goto as_recons_fail; break; } @@ -198,8 +214,8 @@ uint32_t xyram = 0xe500e000 + 32; int __npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { int32_t i, j; - int32_t w = full_map->w/T_WIDTH/PXSIZE; - int32_t h = full_map->h/T_HEIGHT/PXSIZE; + int32_t w = full_map->w / T_WIDTH / PXSIZE; + int32_t h = full_map->h / T_HEIGHT / PXSIZE; int32_t x = (npc->curx >> PRECISION) / T_WIDTH; int32_t y = (npc->cury >> PRECISION) / T_HEIGHT; dest_x /= T_WIDTH; @@ -286,7 +302,8 @@ int __npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { bscore = fscore[i]; } if(bx == dest_x && by == dest_y) { - if(is_alloc) as_clean(visited, gscore, fscore); + if(is_alloc) + as_clean(visited, gscore, fscore); return 0; /*as_reconstruct_path(came_from, w, h, spos, dest_y * w + dest_x, is_alloc npc)*/ } @@ -318,7 +335,7 @@ int __npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { } } - if(is_alloc){ + if(is_alloc) { as_clean(visited, gscore, fscore); free(came_from); } @@ -329,17 +346,19 @@ int __npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { void update_npcs(Game *game) { uint32_t i; for(i = 0; i < game->map_level->nbNPC; i++) { - update_npc(&game->map_level->npcs[i]); + update_npc(&game->map_level->npcs[i], game); } for(i = 0; i < npc_count; i++) { - update_npc(&npc_stack[i]); + update_npc(&npc_stack[i], game); /*Temp debug*/ - game->mana = npc_pathfind(game->player.x, game->player.y, game->map_level, - &npc_stack[i]); + game->mana = npc_pathfind(game->player.x, game->player.y, + game->map_level, &npc_stack[i]); } } -void update_npc(NPC *npc) { +extern const short int walkable_speed[WALKABLE_TILE_MAX]; + +void update_npc(NPC *npc, Game *game) { /* if the NPC has no path or is paused, skip it */ if(!npc->hasPath || npc->paused == true) return; @@ -358,8 +377,29 @@ void update_npc(NPC *npc) { npc->currentPoint = npc->currentPoint % npc->path_length; } - npc->curx += vecX * (float)(1 << PRECISION); - npc->cury += vecY * (float)(1 << PRECISION); + int32_t new_x = npc->curx + (vecX * (float)(1 << PRECISION)); + int32_t new_y = npc->cury + (vecY * (float)(1 << PRECISION)); + + /*If the NPC has a static path, let him do as he wants*/ + if(!npc->owns_path) { + npc->curx = new_x; + npc->cury = new_y; + return; + } + /*Otherwise check if he is colliding*/ + + /*Pos in tiles*/ + int32_t mpos_x = new_x; + if(vecX > 0) + mpos_x += 1 << PRECISION; + int32_t mpos_y = new_y; + if(vecY > 0) + mpos_y += 1 << PRECISION; + + if(!npc_collision(game, npc, mpos_x, mpos_x)) { + npc->curx = new_x; + npc->cury = new_y; + } } bopti_image_t *npc_sprites[FACES] = {&tiny_npc_male, &tiny_npc_female, diff --git a/src/npc.h b/src/npc.h index cc3f70c..b1d14e4 100644 --- a/src/npc.h +++ b/src/npc.h @@ -10,9 +10,11 @@ /*Maximum iterations before the pathfinding considers the target unreacheable*/ #define PATHFIND_MAX_ITER 64 -#define npc_from_curxy(a) (((a)>>PRECISION)/PXSIZE) +/*The following macros take a curx/y format int, and convert them + *to and from absolute pixel positon (pixel position/ PXSIZE)*/ +#define npc_from_curxy(a) (((a) >> PRECISION) / PXSIZE) -#define npc_to_curxy(a) (((a)*PXSIZE)<