comparison 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
comparison
equal deleted inserted replaced
249:f4dc208aa1e3 250:8ef7fb7f14ad
40 * This is the speed the player moves on the map. 40 * This is the speed the player moves on the map.
41 * 41 *
42 * SPEED represents the number of pixels it must move per SEC. 42 * SPEED represents the number of pixels it must move per SEC.
43 * SEC simply represends the number of milliseconds in one second. 43 * SEC simply represends the number of milliseconds in one second.
44 */ 44 */
45 #define SPEED 220 45 #define SPEED 150
46 #define SEC 1000 46 #define SEC 1000
47 47
48 /* 48 /*
49 * Those are margins within the edge of the screen. The camera always try to 49 * Those are margins within the edge of the screen. The camera always try to
50 * keep those padding between the player and the screen. 50 * keep those padding between the player and the screen.
90 [0x8] = 6, 90 [0x8] = 6,
91 [0x9] = 7, 91 [0x9] = 7,
92 [0xC] = 5 92 [0xC] = 5
93 }; 93 };
94 94
95 struct collision { 95 /*
96 int x; 96 * Check if this block is usable for collision detection. For example if the
97 int y; 97 * player is moving upwards but the collision shape is below it is unnecessary
98 unsigned int w; 98 * to check.
99 unsigned int h; 99 */
100 };
101
102 static bool 100 static bool
103 is_collision_out(const struct map *map, struct collision *block, int drow, int dcol) 101 is_block_relevant(const struct map *map,
102 const struct map_block *block,
103 int drow,
104 int dcol)
104 { 105 {
105 if (drow) { 106 if (drow) {
106 /* Object outside of left-right bounds. */ 107 /* Object outside of left-right bounds. */
107 if (block->x + (int)block->w <= map->player_x || 108 if (block->x + (int)block->w <= map->player_x ||
108 block->x >= map->player_x + (int)map->player_sprite->cellw) 109 block->x >= map->player_x + (int)map->player_sprite->cellw)
123 } 124 }
124 125
125 return true; 126 return true;
126 } 127 }
127 128
129 /*
130 * Determine if this collision shape is "closer" to the player by checking the
131 * new block coordinates with the previous one.
132 */
133 static bool
134 is_block_better(const struct map_block *now,
135 const struct map_block *new,
136 int drow,
137 int dcol)
138 {
139 return ((drow < 0 && new->y + new->h > now->y + now->h) ||
140 (drow > 0 && new->y < now->y) ||
141 (dcol < 0 && new->x + new->w > now->x + now->w) ||
142 (dcol > 0 && new->x < now->x));
143
144 }
145
128 static void 146 static void
129 center(struct map *map) 147 center(struct map *map)
130 { 148 {
131 map->view_x = map->player_x - (int)(map->view_w / 2); 149 map->view_x = map->player_x - (int)(map->view_w / 2);
132 map->view_y = map->player_y - (int)(map->view_h / 2); 150 map->view_y = map->player_y - (int)(map->view_h / 2);
261 return tile; 279 return tile;
262 } 280 }
263 281
264 static void 282 static void
265 find_block_iterate(const struct map *map, 283 find_block_iterate(const struct map *map,
266 struct collision *block, 284 struct map_block *block,
267 int rowstart, 285 int rowstart,
268 int rowend, 286 int rowend,
269 int colstart, 287 int colstart,
270 int colend, 288 int colend,
271 int drow, 289 int drow,
272 int dcol) 290 int dcol)
273 { 291 {
274 assert(map); 292 assert(map);
275 assert(block); 293 assert(block);
276 294
295 /* First, check with tiledefs. */
277 for (int r = rowstart; r <= rowend; ++r) { 296 for (int r = rowstart; r <= rowend; ++r) {
278 for (int c = colstart; c <= colend; ++c) { 297 for (int c = colstart; c <= colend; ++c) {
279 struct tileset_tiledef *td; 298 struct tileset_tiledef *td;
280 struct collision tmp; 299 struct map_block tmp;
281 300
282 if (!(td = find_tiledef_by_row_column(map, r, c))) 301 if (!(td = find_tiledef_by_row_column(map, r, c)))
283 continue; 302 continue;
284 303
285 /* Convert to absolute values. */ 304 /* Convert to absolute values. */
287 tmp.y = td->y + r * map->tileset->sprite->cellh; 306 tmp.y = td->y + r * map->tileset->sprite->cellh;
288 tmp.w = td->w; 307 tmp.w = td->w;
289 tmp.h = td->h; 308 tmp.h = td->h;
290 309
291 /* This tiledef is out of context. */ 310 /* This tiledef is out of context. */
292 if (!is_collision_out(map, &tmp, drow, dcol)) 311 if (!is_block_relevant(map, &tmp, drow, dcol))
293 continue; 312 continue;
294 313
295 if ((drow < 0 && tmp.y + tmp.h > block->y + block->h) || 314 if (is_block_better(block, &tmp, drow, dcol)) {
296 (drow > 0 && tmp.y < block->y) ||
297 (dcol < 0 && tmp.x + tmp.w > block->x + block->w) ||
298 (dcol > 0 && tmp.x < block->x)) {
299 block->x = tmp.x; 315 block->x = tmp.x;
300 block->y = tmp.y; 316 block->y = tmp.y;
301 block->w = tmp.w; 317 block->w = tmp.w;
302 block->h = tmp.h; 318 block->h = tmp.h;
303 } 319 }
304 } 320 }
305 } 321 }
306 } 322
307 323 /* Now check if there are objects closer than tiledefs. */
308 static void 324 for (size_t i = 0; i < map->blocksz; ++i) {
309 find_collision(const struct map *map, struct collision *block, int drow, int dcolumn) 325 const struct map_block *new = &map->blocks[i];
326
327 if (is_block_relevant(map, new, drow, dcol) &&
328 is_block_better(block, new, drow, dcol)) {
329 block->x = new->x;
330 block->y = new->y;
331 block->w = new->w;
332 block->h = new->h;
333 }
334 }
335 }
336
337 static void
338 find_collision(const struct map *map, struct map_block *block, int drow, int dcolumn)
310 { 339 {
311 assert((drow && !dcolumn) || (dcolumn && !drow)); 340 assert((drow && !dcolumn) || (dcolumn && !drow));
312 341
313 const int playercol = map->player_x / map->tileset->sprite->cellw; 342 const int playercol = map->player_x / map->tileset->sprite->cellw;
314 const int playerrow = map->player_y / map->tileset->sprite->cellh; 343 const int playerrow = map->player_y / map->tileset->sprite->cellh;
358 } 387 }
359 388
360 static void 389 static void
361 move_x(struct map *map, int delta) 390 move_x(struct map *map, int delta)
362 { 391 {
363 struct collision block; 392 struct map_block block;
364 393
365 find_collision(map, &block, 0, delta < 0 ? -1 : +1); 394 find_collision(map, &block, 0, delta < 0 ? -1 : +1);
366 395
367 if (delta < 0 && map->player_x + delta < (int)(block.x + block.w)) 396 if (delta < 0 && map->player_x + delta < (int)(block.x + block.w))
368 delta = map->player_x - block.x - block.w; 397 delta = map->player_x - block.x - block.w;
382 } 411 }
383 412
384 static void 413 static void
385 move_y(struct map *map, int delta) 414 move_y(struct map *map, int delta)
386 { 415 {
387 struct collision block; 416 struct map_block block;
388 417
389 find_collision(map, &block, delta < 0 ? -1 : +1, 0); 418 find_collision(map, &block, delta < 0 ? -1 : +1, 0);
390 419
391 if (delta < 0 && map->player_y + delta < (int)(block.y + block.h)) 420 if (delta < 0 && map->player_y + delta < (int)(block.y + block.h))
392 delta = map->player_y - block.y - block.h; 421 delta = map->player_y - block.y - block.h;
560 void 589 void
561 map_update(struct map *map, unsigned int ticks) 590 map_update(struct map *map, unsigned int ticks)
562 { 591 {
563 assert(map); 592 assert(map);
564 593
565 action_stack_update(&map->actions, ticks); 594 action_stack_update(&map->astack_par, ticks);
595 action_stack_update(&map->astack_seq, ticks);
566 596
567 tileset_update(map->tileset, ticks); 597 tileset_update(map->tileset, ticks);
568 move(map, ticks); 598
569 } 599 /* No movements if the sequential actions are running. */
570 600 if (action_stack_completed(&map->astack_seq))
571 void 601 move(map, ticks);
572 map_draw(const struct map *map) 602 }
573 { 603
574 assert(map); 604 static void
575 605 draw_collide(const struct map *map)
606 {
576 struct texture box = {0}; 607 struct texture box = {0};
577 608
578 /* Draw the texture about background/foreground. */ 609 if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&box, 64, 64)) {
579 draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]); 610 /* Draw collide box around player if requested. */
580 draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]);
581
582 walksprite_draw(
583 &map->player_ws,
584 map->player_angle,
585 map->player_x - map->view_x,
586 map->player_y - map->view_y);
587
588 draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]);
589
590 action_stack_draw(&map->actions);
591
592 /* Draw collide box around player if requested. */
593 if (map->flags & MAP_FLAGS_SHOW_COLLIDE &&
594 texture_new(&box, map->player_sprite->cellw, map->player_sprite->cellh)) {
595 texture_set_alpha_mod(&box, 100); 611 texture_set_alpha_mod(&box, 100);
596 texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND); 612 texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND);
597 PAINTER_BEGIN(&box); 613 PAINTER_BEGIN(&box);
598 painter_set_color(0x4f8fbaff); 614 painter_set_color(0x4f8fbaff);
599 painter_clear(); 615 painter_clear();
600 PAINTER_END(); 616 PAINTER_END();
601 texture_draw(&box, map->player_x - map->view_x, map->player_y - map->view_y); 617 texture_scale(&box, 0, 0, 64, 64,
618 map->player_x - map->view_x, map->player_y - map->view_y,
619 map->player_sprite->cellw, map->player_sprite->cellh, 0.f);
620
621 /* Do the same for every objects. */
622 PAINTER_BEGIN(&box);
623 painter_set_color(0xa8ca58ff);
624 painter_clear();
625 PAINTER_END();
626
627 for (size_t i = 0; i < map->blocksz; ++i) {
628 texture_scale(&box, 0, 0, 64, 64,
629 map->blocks[i].x - map->view_x, map->blocks[i].y - map->view_y,
630 map->blocks[i].w, map->blocks[i].h,
631 0.f);
632 }
633
602 texture_finish(&box); 634 texture_finish(&box);
603 } 635 }
636 }
637
638 void
639 map_draw(const struct map *map)
640 {
641 assert(map);
642
643 /* Draw the texture about background/foreground. */
644 draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]);
645 draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]);
646
647 walksprite_draw(
648 &map->player_ws,
649 map->player_angle,
650 map->player_x - map->view_x,
651 map->player_y - map->view_y);
652
653 draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]);
654 draw_collide(map);
655
656 action_stack_draw(&map->astack_par);
657 action_stack_draw(&map->astack_seq);
604 } 658 }
605 659
606 void 660 void
607 map_finish(struct map *map) 661 map_finish(struct map *map)
608 { 662 {
609 assert(map); 663 assert(map);
610 664
611 action_stack_finish(&map->actions); 665 action_stack_finish(&map->astack_par);
666 action_stack_finish(&map->astack_seq);
612 667
613 memset(map, 0, sizeof (*map)); 668 memset(map, 0, sizeof (*map));
614 } 669 }