Mercurial > molko
diff libmlk-rpg/rpg/map.c @ 250:8ef7fb7f14ad
rpg: add support for collisions with actions
While here, minimal cleanup in maps.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 01 Dec 2020 19:24:11 +0100 |
parents | 71b3b7036de7 |
children | 16be1ad3ddba |
line wrap: on
line diff
--- a/libmlk-rpg/rpg/map.c Tue Dec 01 17:18:12 2020 +0100 +++ b/libmlk-rpg/rpg/map.c Tue Dec 01 19:24:11 2020 +0100 @@ -42,7 +42,7 @@ * SPEED represents the number of pixels it must move per SEC. * SEC simply represends the number of milliseconds in one second. */ -#define SPEED 220 +#define SPEED 150 #define SEC 1000 /* @@ -92,15 +92,16 @@ [0xC] = 5 }; -struct collision { - int x; - int y; - unsigned int w; - unsigned int h; -}; - +/* + * Check if this block is usable for collision detection. For example if the + * player is moving upwards but the collision shape is below it is unnecessary + * to check. + */ static bool -is_collision_out(const struct map *map, struct collision *block, int drow, int dcol) +is_block_relevant(const struct map *map, + const struct map_block *block, + int drow, + int dcol) { if (drow) { /* Object outside of left-right bounds. */ @@ -125,6 +126,23 @@ return true; } +/* + * Determine if this collision shape is "closer" to the player by checking the + * new block coordinates with the previous one. + */ +static bool +is_block_better(const struct map_block *now, + const struct map_block *new, + int drow, + int dcol) +{ + return ((drow < 0 && new->y + new->h > now->y + now->h) || + (drow > 0 && new->y < now->y) || + (dcol < 0 && new->x + new->w > now->x + now->w) || + (dcol > 0 && new->x < now->x)); + +} + static void center(struct map *map) { @@ -263,7 +281,7 @@ static void find_block_iterate(const struct map *map, - struct collision *block, + struct map_block *block, int rowstart, int rowend, int colstart, @@ -274,10 +292,11 @@ assert(map); assert(block); + /* First, check with tiledefs. */ for (int r = rowstart; r <= rowend; ++r) { for (int c = colstart; c <= colend; ++c) { struct tileset_tiledef *td; - struct collision tmp; + struct map_block tmp; if (!(td = find_tiledef_by_row_column(map, r, c))) continue; @@ -289,13 +308,10 @@ tmp.h = td->h; /* This tiledef is out of context. */ - if (!is_collision_out(map, &tmp, drow, dcol)) + if (!is_block_relevant(map, &tmp, drow, dcol)) continue; - if ((drow < 0 && tmp.y + tmp.h > block->y + block->h) || - (drow > 0 && tmp.y < block->y) || - (dcol < 0 && tmp.x + tmp.w > block->x + block->w) || - (dcol > 0 && tmp.x < block->x)) { + if (is_block_better(block, &tmp, drow, dcol)) { block->x = tmp.x; block->y = tmp.y; block->w = tmp.w; @@ -303,10 +319,23 @@ } } } + + /* Now check if there are objects closer than tiledefs. */ + for (size_t i = 0; i < map->blocksz; ++i) { + const struct map_block *new = &map->blocks[i]; + + if (is_block_relevant(map, new, drow, dcol) && + is_block_better(block, new, drow, dcol)) { + block->x = new->x; + block->y = new->y; + block->w = new->w; + block->h = new->h; + } + } } static void -find_collision(const struct map *map, struct collision *block, int drow, int dcolumn) +find_collision(const struct map *map, struct map_block *block, int drow, int dcolumn) { assert((drow && !dcolumn) || (dcolumn && !drow)); @@ -360,7 +389,7 @@ static void move_x(struct map *map, int delta) { - struct collision block; + struct map_block block; find_collision(map, &block, 0, delta < 0 ? -1 : +1); @@ -384,7 +413,7 @@ static void move_y(struct map *map, int delta) { - struct collision block; + struct map_block block; find_collision(map, &block, delta < 0 ? -1 : +1, 0); @@ -562,10 +591,48 @@ { assert(map); - action_stack_update(&map->actions, ticks); + action_stack_update(&map->astack_par, ticks); + action_stack_update(&map->astack_seq, ticks); tileset_update(map->tileset, ticks); - move(map, ticks); + + /* No movements if the sequential actions are running. */ + if (action_stack_completed(&map->astack_seq)) + move(map, ticks); +} + +static void +draw_collide(const struct map *map) +{ + struct texture box = {0}; + + if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&box, 64, 64)) { + /* Draw collide box around player if requested. */ + texture_set_alpha_mod(&box, 100); + texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND); + PAINTER_BEGIN(&box); + painter_set_color(0x4f8fbaff); + painter_clear(); + PAINTER_END(); + texture_scale(&box, 0, 0, 64, 64, + map->player_x - map->view_x, map->player_y - map->view_y, + map->player_sprite->cellw, map->player_sprite->cellh, 0.f); + + /* Do the same for every objects. */ + PAINTER_BEGIN(&box); + painter_set_color(0xa8ca58ff); + painter_clear(); + PAINTER_END(); + + for (size_t i = 0; i < map->blocksz; ++i) { + texture_scale(&box, 0, 0, 64, 64, + map->blocks[i].x - map->view_x, map->blocks[i].y - map->view_y, + map->blocks[i].w, map->blocks[i].h, + 0.f); + } + + texture_finish(&box); + } } void @@ -573,8 +640,6 @@ { assert(map); - struct texture box = {0}; - /* Draw the texture about background/foreground. */ draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]); draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]); @@ -586,21 +651,10 @@ map->player_y - map->view_y); draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]); - - action_stack_draw(&map->actions); + draw_collide(map); - /* Draw collide box around player if requested. */ - if (map->flags & MAP_FLAGS_SHOW_COLLIDE && - texture_new(&box, map->player_sprite->cellw, map->player_sprite->cellh)) { - texture_set_alpha_mod(&box, 100); - texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND); - PAINTER_BEGIN(&box); - painter_set_color(0x4f8fbaff); - painter_clear(); - PAINTER_END(); - texture_draw(&box, map->player_x - map->view_x, map->player_y - map->view_y); - texture_finish(&box); - } + action_stack_draw(&map->astack_par); + action_stack_draw(&map->astack_seq); } void @@ -608,7 +662,8 @@ { assert(map); - action_stack_finish(&map->actions); + action_stack_finish(&map->astack_par); + action_stack_finish(&map->astack_seq); memset(map, 0, sizeof (*map)); }