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