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