Mercurial > molko
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 } |