Tutorial-Level.
[hackover2013-badge-firmware.git] / badge / jumpnrun / collision.c
1 #include "collision.h"
2
3 uint8_t collision_displace(vec2d *desired_pos,
4 jumpnrun_moveable *current,
5 rectangle const *obstacle,
6 vec2d *inertia_mod) {
7 rectangle desired = current->hitbox;
8 rectangle_move_to(&desired, *desired_pos);
9
10 if(!rectangle_intersect(obstacle, &desired)) {
11 return 0;
12 }
13
14 fixed_point x = FIXED_INT(1000), y = FIXED_INT(1000);
15 fixed_point dx = desired_pos->x, dy = desired_pos->y;
16 bool bottom_collision = false;
17
18 uint8_t coll_x = 0;
19 uint8_t coll_y = 0;
20 uint8_t coll = 0;
21
22 if(fixed_point_le(rectangle_top ( obstacle), rectangle_top(&desired)) &&
23 fixed_point_gt(rectangle_bottom( obstacle), rectangle_top(&desired)) &&
24 fixed_point_lt(rectangle_top (&desired ), rectangle_top(&current->hitbox))) {
25
26 coll_y = JUMPNRUN_COLLISION_BOTTOM;
27 y = fixed_point_sub(rectangle_bottom(obstacle), rectangle_top(&desired));
28 dy = rectangle_bottom(obstacle);
29
30 } else if(fixed_point_gt(rectangle_bottom( obstacle), rectangle_bottom(&desired)) &&
31 fixed_point_le(rectangle_top ( obstacle), rectangle_bottom(&desired)) &&
32 fixed_point_gt(rectangle_top (&desired ), rectangle_top (&current->hitbox))) {
33
34 coll_y = JUMPNRUN_COLLISION_TOP;
35 y = fixed_point_sub(rectangle_bottom(&desired ), rectangle_top ( obstacle));
36 dy = fixed_point_sub(rectangle_top ( obstacle), rectangle_height(&desired ));
37 bottom_collision = true;
38
39 }
40
41 if(fixed_point_le(rectangle_left ( obstacle), rectangle_left(&desired)) &&
42 fixed_point_gt(rectangle_right( obstacle), rectangle_left(&desired)) &&
43 fixed_point_lt(rectangle_left (&desired ), rectangle_left(&current->hitbox))) {
44
45 coll_x = JUMPNRUN_COLLISION_RIGHT;
46 x = fixed_point_sub(rectangle_right(obstacle), rectangle_left(&desired));
47 dx = rectangle_right(obstacle);
48
49 } else if(fixed_point_gt(rectangle_right( obstacle), rectangle_right(&desired)) &&
50 fixed_point_le(rectangle_left ( obstacle), rectangle_right(&desired)) &&
51 fixed_point_gt(rectangle_left (&desired ), rectangle_left (&current->hitbox))) {
52
53 coll_x = JUMPNRUN_COLLISION_LEFT;
54 x = fixed_point_sub(rectangle_right(&desired ), rectangle_left ( obstacle));
55 dx = fixed_point_sub(rectangle_left ( obstacle), rectangle_width(&desired ));
56
57 }
58
59 if(fixed_point_eq(x, y)) {
60 desired_pos->x = dx;
61 desired_pos->y = dy;
62 coll = coll_x | coll_y;
63 } else if(fixed_point_gt(x, y)) {
64 desired_pos->y = dy;
65 inertia_mod->y = FIXED_INT(0);
66
67 if(bottom_collision) {
68 current->flags |= JUMPNRUN_MOVEABLE_TOUCHING_GROUND;
69 } else {
70 current->flags &= ~JUMPNRUN_MOVEABLE_TOUCHING_GROUND;
71 }
72
73 coll = coll_y;
74 } else {
75 desired_pos->x = dx;
76 inertia_mod->x = FIXED_INT(0);
77 coll = coll_x;
78 }
79
80 return coll;
81 }
82
83 bool collisions_tiles_displace(vec2d *desired_position,
84 jumpnrun_moveable *thing,
85 jumpnrun_level const *lv,
86 jumpnrun_tile_range const *visible_tiles,
87 vec2d *inertia_mod)
88 {
89 int collision_tile[] = { -1, -1, -1,
90 -1, -1, -1,
91 -1, -1, -1
92 };
93 static int const collision_order[] = { 7, 1, 3, 5, 6, 8, 0, 2 };
94
95 vec2d midpoint = rectangle_mid(&thing->hitbox);
96
97 jumpnrun_tile_position midtile_pos = {
98 fixed_point_cast_int(fixed_point_div(midpoint.x, FIXED_INT(JUMPNRUN_TILE_PIXEL_WIDTH ))),
99 fixed_point_cast_int(fixed_point_div(midpoint.y, FIXED_INT(JUMPNRUN_TILE_PIXEL_HEIGHT)))
100 };
101
102 int tile;
103
104 for(tile = visible_tiles->first; (size_t) tile < visible_tiles->last && lv->tiles[tile].pos.x < midtile_pos.x - 1; ++tile)
105 ;
106 for(; (size_t) tile < visible_tiles->last && lv->tiles[tile].pos.x < midtile_pos.x + 2; ++tile) {
107 int xdiff = lv->tiles[tile].pos.x - midtile_pos.x;
108 int ydiff = lv->tiles[tile].pos.y - midtile_pos.y;
109
110 switch(xdiff) {
111 case -1:
112 {
113 switch(ydiff) {
114 case -1: collision_tile[0] = tile; break;
115 case 0: collision_tile[1] = tile; break;
116 case 1: collision_tile[2] = tile; break;
117 }
118 break;
119 }
120 case 0:
121 {
122 switch(ydiff) {
123 case -1: collision_tile[3] = tile; break;
124 case 0: collision_tile[4] = tile; break;
125 case 1: collision_tile[5] = tile; break;
126 }
127 break;
128 }
129 case 1:
130 {
131 switch(ydiff) {
132 case -1: collision_tile[6] = tile; break;
133 case 0: collision_tile[7] = tile; break;
134 case 1: collision_tile[8] = tile; break;
135 }
136 break;
137 }
138 }
139 }
140
141 /* collision: sort by priority (top/bottom, left/right, then diagonal) */
142 bool lethal = false;
143 thing->flags &= ~JUMPNRUN_MOVEABLE_TOUCHING_GROUND;
144
145 for(size_t collision_index = 0; collision_index < ARRAY_SIZE(collision_order); ++collision_index) {
146 if(collision_tile[collision_order[collision_index]] == -1) {
147 continue;
148 }
149
150 jumpnrun_tile *tile_obj = &lv->tiles[collision_tile[collision_order[collision_index]]];
151 rectangle tile_rect = rect_from_tile(tile_obj);
152
153 uint8_t coll = collision_displace(desired_position, thing, &tile_rect, inertia_mod);
154 if(coll & tile_type(tile_obj)->lethal_sides) {
155 lethal = true;
156 }
157 }
158
159 rectangle_move_to(&thing->hitbox, *desired_position);
160
161 return lethal;
162 }
This page took 0.064734 seconds and 5 git commands to generate.