npc : Simplification de npc_pathfinding + tentative collision de npcs + suppression de map_draw

This commit is contained in:
attilavs2 2024-08-06 15:36:34 +02:00
parent 1767643da1
commit ee3b25a366
5 changed files with 87 additions and 143 deletions

View file

@ -14,105 +14,6 @@ extern Map level4;
Map *worldRPG[] = {&level0, &level1, &level2, &level3, &level4, NULL}; 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) { void map_render_by_layer(Game *game, int layer) {
Map *map_level = game->map_level; Map *map_level = game->map_level;

120
src/npc.c
View file

@ -4,6 +4,7 @@
#include "dialogs.h" #include "dialogs.h"
#include "game.h" #include "game.h"
#include "map.h" #include "map.h"
#include "player.h"
#include <gint/display.h> #include <gint/display.h>
#include <gint/hardware.h> #include <gint/hardware.h>
@ -20,6 +21,9 @@ extern bopti_image_t tiny_npc_police;
NPC npc_stack[NPC_STACK_SIZE]; NPC npc_stack[NPC_STACK_SIZE];
uint32_t npc_count; uint32_t npc_count;
extern const char one_px_mov[8];
extern const short int walkable_speed[WALKABLE_TILE_MAX];
NPC *npc_create() { NPC *npc_create() {
if(npc_count == NPC_STACK_SIZE) if(npc_count == NPC_STACK_SIZE)
return NULL; return NULL;
@ -54,6 +58,33 @@ void npc_remove(NPC *npc) {
void npc_remove_pos(uint32_t pos) { npc_remove(&npc_stack[pos]); } 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); } float length(float x, float y) { return sqrtf(x * x + y * y); }
int npc_clear_path(NPC *npc) { int npc_clear_path(NPC *npc) {
@ -73,7 +104,7 @@ int npc_clear_path(NPC *npc) {
npc->owns_path = true; npc->owns_path = true;
return 0; return 0;
} }
/*Takes input as absolute pixel position (/PXSIZE)*/
int npc_append_path(int16_t x, int16_t y, NPC *npc) { int npc_append_path(int16_t x, int16_t y, NPC *npc) {
npc->xpath = realloc(npc->xpath, npc->path_length * 2 + 2); npc->xpath = realloc(npc->xpath, npc->path_length * 2 + 2);
npc->ypath = realloc(npc->ypath, 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); 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; uint8_t *map = full_map->walkable;
uint32_t w = full_map->w; uint32_t w = full_map->w;
uint32_t h = full_map->h; 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_x /= PXSIZE;
dest_y /= 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; return 2;
/*if(map[dest_y*w + dest_x]) /*if(map[(dest_y/T_HEIGHT)*w + dest_x/T_WIDTH])
return 2; return 2;
if(map[sy*w + sx]) if(map[sy*w + sx])
return 2;*/ 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) if(!npc->owns_path || npc->path_length > 64)
npc_clear_path(npc); npc_clear_path(npc);
/*int bx; if(npc_append_path(dest_x, dest_y, npc))
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))
return 1; return 1;
npc->hasPath = true; 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; int x, y;
for(i = 0; i < PATHFIND_MAX_ITER; i++) { for(i = 0; i < PATHFIND_MAX_ITER; i++) {
x = ((prev%w)*T_WIDTH + T_WIDTH/2) << PRECISION; x = ((prev % w) * T_WIDTH + T_WIDTH / 2) << PRECISION;
y = ((prev/w)*T_HEIGHT + T_HEIGHT/2) << PRECISION; y = ((prev / w) * T_HEIGHT + T_HEIGHT / 2) << PRECISION;
if(npc_append_path(x,y,npc)) { if(npc_append_path(x, y, npc)) {
goto as_recons_fail; goto as_recons_fail;
} }
prev = came_from[prev]; prev = came_from[prev];
if(prev == start){ if(prev == start) {
x = ((prev%w)*T_WIDTH + T_WIDTH/2) << PRECISION; x = ((prev % w) * T_WIDTH + T_WIDTH / 2) << PRECISION;
y = ((prev/w)*T_HEIGHT + T_HEIGHT/2) << PRECISION; y = ((prev / w) * T_HEIGHT + T_HEIGHT / 2) << PRECISION;
if(npc_append_path(x,y,npc)) if(npc_append_path(x, y, npc))
goto as_recons_fail; goto as_recons_fail;
break; 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) { int __npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) {
int32_t i, j; int32_t i, j;
int32_t w = full_map->w/T_WIDTH/PXSIZE; int32_t w = full_map->w / T_WIDTH / PXSIZE;
int32_t h = full_map->h/T_HEIGHT/PXSIZE; int32_t h = full_map->h / T_HEIGHT / PXSIZE;
int32_t x = (npc->curx >> PRECISION) / T_WIDTH; int32_t x = (npc->curx >> PRECISION) / T_WIDTH;
int32_t y = (npc->cury >> PRECISION) / T_HEIGHT; int32_t y = (npc->cury >> PRECISION) / T_HEIGHT;
dest_x /= T_WIDTH; 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]; bscore = fscore[i];
} }
if(bx == dest_x && by == dest_y) { 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, return 0; /*as_reconstruct_path(came_from, w, h, spos,
dest_y * w + dest_x, is_alloc npc)*/ 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); as_clean(visited, gscore, fscore);
free(came_from); 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) { void update_npcs(Game *game) {
uint32_t i; uint32_t i;
for(i = 0; i < game->map_level->nbNPC; 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++) { for(i = 0; i < npc_count; i++) {
update_npc(&npc_stack[i]); update_npc(&npc_stack[i], game);
/*Temp debug*/ /*Temp debug*/
game->mana = npc_pathfind(game->player.x, game->player.y, game->map_level, game->mana = npc_pathfind(game->player.x, game->player.y,
&npc_stack[i]); 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 the NPC has no path or is paused, skip it */
if(!npc->hasPath || npc->paused == true) if(!npc->hasPath || npc->paused == true)
return; return;
@ -358,8 +377,29 @@ void update_npc(NPC *npc) {
npc->currentPoint = npc->currentPoint % npc->path_length; npc->currentPoint = npc->currentPoint % npc->path_length;
} }
npc->curx += vecX * (float)(1 << PRECISION); int32_t new_x = npc->curx + (vecX * (float)(1 << PRECISION));
npc->cury += vecY * (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, bopti_image_t *npc_sprites[FACES] = {&tiny_npc_male, &tiny_npc_female,

View file

@ -10,9 +10,11 @@
/*Maximum iterations before the pathfinding considers the target unreacheable*/ /*Maximum iterations before the pathfinding considers the target unreacheable*/
#define PATHFIND_MAX_ITER 64 #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)<<PRECISION) #define npc_to_curxy(a) (((a)*PXSIZE) << PRECISION)
enum { enum {
@ -59,7 +61,7 @@ void npc_draw(Game *game);
/* Updates the static NPCs and the NPC stack */ /* Updates the static NPCs and the NPC stack */
void update_npcs(Game *game); void update_npcs(Game *game);
/* Updates the singular NPC npc. Be careful with it ! */ /* Updates the singular NPC npc. Be careful with it ! */
void update_npc(NPC *npc); void update_npc(NPC *npc, Game *game);
/* Inits/Clears the NPC stack*/ /* Inits/Clears the NPC stack*/
void npc_reload(Game *game); void npc_reload(Game *game);

View file

@ -31,7 +31,6 @@ const char one_px_mov[8] = {
/* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their /* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their
* IDs */ * IDs */
/* The speed of the player on the diffrent tiles in the walkable layer. */ /* The speed of the player on the diffrent tiles in the walkable layer. */
#define WALKABLE_TILE_MAX 4
const short int walkable_speed[WALKABLE_TILE_MAX] = {SPEED, 0, PXSIZE, PXSIZE}; const short int walkable_speed[WALKABLE_TILE_MAX] = {SPEED, 0, PXSIZE, PXSIZE};
/* How much damage the player takes on the diffrent tiles in the walkable /* How much damage the player takes on the diffrent tiles in the walkable

View file

@ -14,6 +14,8 @@ typedef struct {
#define FACES 4 #define FACES 4
#define WALKABLE_TILE_MAX 4
/* Structure 'Player' has been moved to game.h */ /* Structure 'Player' has been moved to game.h */
/* to avoid circular references between map.h, game.h and player.h */ /* to avoid circular references between map.h, game.h and player.h */
/* only methods propotypes are now in dedicated header files */ /* only methods propotypes are now in dedicated header files */