3 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof*(arr))
5 void collision_displace(vec2d
*desired_pos
,
6 rectangle
const *current
,
7 rectangle
const *obstacle
,
9 bool *touching_ground
) {
10 rectangle desired
= *current
;
11 rectangle_move_to(&desired
, *desired_pos
);
13 if(!rectangle_intersect(obstacle
, &desired
)) {
17 fixed_point x
= FIXED_POINT(1000, 0), y
= FIXED_POINT(1000, 0);
18 fixed_point dx
= desired_pos
->x
, dy
= desired_pos
->y
;
19 bool bottom_collision
= false;
21 if(fixed_point_le(rectangle_top ( obstacle
), rectangle_top(&desired
)) &&
22 fixed_point_gt(rectangle_bottom( obstacle
), rectangle_top(&desired
)) &&
23 fixed_point_lt(rectangle_top (&desired
), rectangle_top( current
))) {
25 y
= fixed_point_sub(rectangle_bottom(obstacle
), rectangle_top(&desired
));
26 dy
= rectangle_bottom(obstacle
);
28 } else if(fixed_point_gt(rectangle_bottom( obstacle
), rectangle_bottom(&desired
)) &&
29 fixed_point_le(rectangle_top ( obstacle
), rectangle_bottom(&desired
)) &&
30 fixed_point_gt(rectangle_top (&desired
), rectangle_top ( current
))) {
32 y
= fixed_point_sub(rectangle_bottom(&desired
), rectangle_top ( obstacle
));
33 dy
= fixed_point_sub(rectangle_top ( obstacle
), rectangle_height(&desired
));
34 bottom_collision
= true;
39 if(fixed_point_le(rectangle_left ( obstacle
), rectangle_left(&desired
)) &&
40 fixed_point_gt(rectangle_right( obstacle
), rectangle_left(&desired
)) &&
41 fixed_point_lt(rectangle_left (&desired
), rectangle_left( current
))) {
43 x
= fixed_point_sub(rectangle_right(obstacle
), rectangle_left(&desired
));
44 dx
= rectangle_right(obstacle
);
46 } else if(fixed_point_gt(rectangle_right( obstacle
), rectangle_right(&desired
)) &&
47 fixed_point_le(rectangle_left ( obstacle
), rectangle_right(&desired
)) &&
48 fixed_point_gt(rectangle_left (&desired
), rectangle_left ( current
))) {
50 x
= fixed_point_sub(rectangle_right(&desired
), rectangle_left ( obstacle
));
51 dx
= fixed_point_sub(rectangle_left ( obstacle
), rectangle_width(&desired
));
55 if(fixed_point_eq(x
, y
)) {
58 } else if(fixed_point_gt(x
, y
)) {
60 inertia
->y
= FIXED_POINT(0, 0);
62 *touching_ground
= bottom_collision
;
65 inertia
->x
= FIXED_POINT(0, 0);
71 void collisions_tiles_displace(vec2d
*desired_position
,
72 rectangle
const *current
,
73 jumpnrun_level
const *lv
,
74 jumpnrun_tile_range
const *visible_tiles
,
76 bool *touching_ground
)
78 int collision_tile
[] = { -1, -1, -1,
82 static int const collision_order
[] = { 7, 1, 3, 5, 6, 8, 0, 2 };
84 vec2d midpoint
= rectangle_mid(current
);
86 jumpnrun_tile_position midtile_pos
= {
87 fixed_point_cast_int(fixed_point_div(midpoint
.x
, FIXED_POINT(JUMPNRUN_TILE_PIXEL_WIDTH
, 0))),
88 fixed_point_cast_int(fixed_point_div(midpoint
.y
, FIXED_POINT(JUMPNRUN_TILE_PIXEL_HEIGHT
, 0)))
93 for(tile
= visible_tiles
->first
; (size_t) tile
< visible_tiles
->last
&& lv
->tiles
[tile
].pos
.x
< midtile_pos
.x
- 1; ++tile
)
95 for(; (size_t) tile
< visible_tiles
->last
&& lv
->tiles
[tile
].pos
.x
< midtile_pos
.x
+ 2; ++tile
) {
96 int xdiff
= lv
->tiles
[tile
].pos
.x
- midtile_pos
.x
;
97 int ydiff
= lv
->tiles
[tile
].pos
.y
- midtile_pos
.y
;
103 case -1: collision_tile
[0] = tile
; break;
104 case 0: collision_tile
[1] = tile
; break;
105 case 1: collision_tile
[2] = tile
; break;
112 case -1: collision_tile
[3] = tile
; break;
113 case 0: collision_tile
[4] = tile
; break;
114 case 1: collision_tile
[5] = tile
; break;
121 case -1: collision_tile
[6] = tile
; break;
122 case 0: collision_tile
[7] = tile
; break;
123 case 1: collision_tile
[8] = tile
; break;
130 /* collision: sort by priority (top/bottom, left/right, then diagonal) */
131 *touching_ground
= false;
133 // printf("mid: %d, %d\n", midtile_pos.x, midtile_pos.y);
134 for(size_t collision_index
= 0; collision_index
< ARRAY_SIZE(collision_order
); ++collision_index
) {
135 if(collision_tile
[collision_order
[collision_index
]] == -1) {
139 rectangle tile_rect
= rect_from_tile(&lv
->tiles
[collision_tile
[collision_order
[collision_index
]]]);
141 collision_displace(desired_position
, current
, &tile_rect
, inertia
, touching_ground
);