]> git.lizzy.rs Git - nothing.git/blob - src/game/level/player/rigid_rect.c
(#189) Fix standing on the boxes
[nothing.git] / src / game / level / player / rigid_rect.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <stdio.h>
4
5 #include "color.h"
6 #include "rigid_rect.h"
7 #include "system/error.h"
8 #include "system/lt.h"
9 #include "game/level/boxes.h"
10
11 #define RIGID_RECT_GRAVITY 1500.0f
12
13 struct rigid_rect_t {
14     lt_t *lt;
15     vec_t position;
16     vec_t velocity;
17     vec_t movement;
18     vec_t size;
19     color_t color;
20     int touches_ground;
21 };
22
23 static const vec_t opposing_rect_side_forces[RECT_SIDE_N] = {
24     { .x = 1.0f,  .y =  0.0f  },  /* RECT_SIDE_LEFT = 0, */
25     { .x = -1.0f, .y =  0.0f  },  /* RECT_SIDE_RIGHT, */
26     { .x = 0.0f,  .y =  1.0f, },  /* RECT_SIDE_TOP, */
27     { .x = 0.0f,  .y = -1.0f, }   /* RECT_SIDE_BOTTOM, */
28 };
29
30 static vec_t opposing_force_by_sides(int sides[RECT_SIDE_N])
31 {
32     vec_t opposing_force = {
33         .x = 0.0f,
34         .y = 0.0f
35     };
36
37     for (rect_side_t side = 0; side < RECT_SIDE_N; ++side) {
38         if (sides[side]) {
39             vec_add(
40                 &opposing_force,
41                 opposing_rect_side_forces[side]);
42         }
43     }
44
45     return opposing_force;
46 }
47
48 rigid_rect_t *create_rigid_rect(rect_t rect, color_t color)
49 {
50     lt_t *lt = create_lt();
51
52     if (lt == NULL) {
53         return NULL;
54     }
55
56     rigid_rect_t *rigid_rect = PUSH_LT(lt, malloc(sizeof(rigid_rect_t)), free);
57     if (rigid_rect == NULL) {
58         throw_error(ERROR_TYPE_LIBC);
59         RETURN_LT(lt, NULL);
60     }
61
62     rigid_rect->lt = lt;
63     rigid_rect->position = vec(rect.x, rect.y);
64     rigid_rect->velocity = vec(0.0f, 0.0f);
65     rigid_rect->movement = vec(0.0f, 0.0f);
66     rigid_rect->size = vec(rect.w, rect.h);
67     rigid_rect->color = color;
68     rigid_rect->touches_ground = 0;
69
70     return rigid_rect;
71 }
72
73 rigid_rect_t *create_rigid_rect_from_stream(FILE *stream)
74 {
75     assert(stream);
76
77     char color[7];
78     rect_t rect;
79
80     if (fscanf(stream, "%f%f%f%f%6s\n",
81                &rect.x, &rect.y,
82                &rect.w, &rect.h,
83                color) < 0) {
84         throw_error(ERROR_TYPE_LIBC);
85         return NULL;
86     }
87
88     return create_rigid_rect(rect, color_from_hexstr(color));
89 }
90
91 void destroy_rigid_rect(rigid_rect_t *rigid_rect)
92 {
93     RETURN_LT0(rigid_rect->lt);
94 }
95
96 int rigid_rect_render(const rigid_rect_t *rigid_rect,
97                       const camera_t *camera)
98 {
99     return camera_fill_rect(
100         camera,
101         rigid_rect_hitbox(rigid_rect),
102         rigid_rect->color);
103
104 }
105
106 int rigid_rect_update(rigid_rect_t * rigid_rect,
107                       float delta_time)
108 {
109     assert(rigid_rect);
110
111     rigid_rect->touches_ground = 0;
112
113     rigid_rect->velocity.y += RIGID_RECT_GRAVITY * delta_time;
114     rigid_rect->position = vec_sum(
115         rigid_rect->position,
116         vec_scala_mult(
117             vec_sum(
118                 rigid_rect->velocity,
119                 rigid_rect->movement),
120             delta_time));
121
122     return 0;
123 }
124
125 void rigid_rect_collide_with_platforms(rigid_rect_t * rigid_rect,
126                                        const platforms_t *platforms)
127 {
128     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
129
130     platforms_rect_object_collide(platforms, rigid_rect_hitbox(rigid_rect), sides);
131
132     if (sides[RECT_SIDE_BOTTOM]) {
133         rigid_rect->touches_ground = 1;
134     }
135
136     vec_t opposing_force = opposing_force_by_sides(sides);
137
138     for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
139         rigid_rect->position = vec_sum(
140             rigid_rect->position,
141             vec_scala_mult(
142                 opposing_force,
143                 1e-2f));
144
145         if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
146             rigid_rect->velocity.x = 0.0f;
147             rigid_rect->movement.x = 0.0f;
148         }
149
150         if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
151             rigid_rect->velocity.y = 0.0f;
152             rigid_rect->movement.y = 0.0f;
153         }
154
155         platforms_rect_object_collide(
156             platforms,
157             rigid_rect_hitbox(rigid_rect),
158             sides);
159         opposing_force = opposing_force_by_sides(sides);
160     }
161 }
162
163 void rigid_rect_collide_with_rect(rigid_rect_t * rigid_rect,
164                                   rect_t rect)
165 {
166     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
167
168     const rect_t object = rect_from_vecs(rigid_rect->position, rigid_rect->size);
169     rect_object_impact(&object, &rect, sides);
170
171     if (sides[RECT_SIDE_BOTTOM]) {
172         rigid_rect->touches_ground = 1;
173     }
174
175     vec_t opposing_force = opposing_force_by_sides(sides);
176
177     for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
178         rigid_rect->position = vec_sum(
179             rigid_rect->position,
180             vec_scala_mult(
181                 opposing_force,
182                 1e-2f));
183
184         if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
185             rigid_rect->velocity.x = 0.0f;
186             rigid_rect->movement.x = 0.0f;
187         }
188
189         if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
190             rigid_rect->velocity.y = 0.0f;
191             rigid_rect->movement.y = 0.0f;
192         }
193
194         rect_object_impact(&object, &rect, sides);
195         opposing_force = opposing_force_by_sides(sides);
196     }
197 }
198
199 void rigid_rect_collide_with_boxes(rigid_rect_t * rigid_rect,
200                                    const boxes_t *boxes)
201 {
202     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
203
204     boxes_rect_object_collide(boxes, rigid_rect_hitbox(rigid_rect), sides);
205
206     if (sides[RECT_SIDE_BOTTOM]) {
207         rigid_rect->touches_ground = 1;
208     }
209
210     vec_t opposing_force = opposing_force_by_sides(sides);
211
212     for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
213         rigid_rect->position = vec_sum(
214             rigid_rect->position,
215             vec_scala_mult(
216                 opposing_force,
217                 1e-2f));
218
219         if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
220             rigid_rect->velocity.x = 0.0f;
221             rigid_rect->movement.x = 0.0f;
222         }
223
224         if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
225             rigid_rect->velocity.y = 0.0f;
226             rigid_rect->movement.y = 0.0f;
227         }
228
229         boxes_rect_object_collide(
230             boxes,
231             rigid_rect_hitbox(rigid_rect),
232             sides);
233         opposing_force = opposing_force_by_sides(sides);
234     }
235 }
236
237 void rigid_rect_impact_rigid_rect(rigid_rect_t * rigid_rect,
238                                  rigid_rect_t *another_rect)
239 {
240     if (rects_overlap(rigid_rect_hitbox(rigid_rect), rigid_rect_hitbox(another_rect))) {
241         rigid_rect_move(another_rect,
242                         vec_sum(
243                             rigid_rect->velocity,
244                             rigid_rect->movement));
245     }
246 }
247
248 rect_t rigid_rect_hitbox(const rigid_rect_t *rigid_rect)
249 {
250     return rect_from_vecs(
251         rigid_rect->position,
252         rigid_rect->size);
253 }
254
255 void rigid_rect_move(rigid_rect_t *rigid_rect,
256                            vec_t movement)
257 {
258     rigid_rect->movement = movement;
259 }
260
261 void rigid_rect_jump(rigid_rect_t *rigid_rect,
262                      float force)
263 {
264     rigid_rect->velocity.y = -force;
265 }
266
267 int rigid_rect_touches_ground(const rigid_rect_t *rigid_rect)
268 {
269     return rigid_rect->touches_ground;
270 }