]> git.lizzy.rs Git - nothing.git/blob - src/game/level/player/rigid_rect.c
find -type f -exec sed -i "s/\b\(\w\)\(\w*\)_t\b/\U\1\E\2/g" {} \;
[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 "game/level/boxes.h"
7 #include "game/level/solid.h"
8 #include "rigid_rect.h"
9 #include "system/error.h"
10 #include "system/lt.h"
11
12
13
14 struct Rigid_rect {
15     Lt *lt;
16     Vec position;
17     Vec velocity;
18     Vec movement;
19     Vec size;
20     Color color;
21     int touches_ground;
22     Vec forces;
23 };
24
25 static const Vec opposing_rect_side_forces[RECT_SIDE_N] = {
26     { .x = 1.0f,  .y =  0.0f  },  /* RECT_SIDE_LEFT = 0, */
27     { .x = -1.0f, .y =  0.0f  },  /* RECT_SIDE_RIGHT, */
28     { .x = 0.0f,  .y =  1.0f, },  /* RECT_SIDE_TOP, */
29     { .x = 0.0f,  .y = -1.0f, }   /* RECT_SIDE_BOTTOM, */
30 };
31
32 static Vec opposing_force_by_sides(int sides[RECT_SIDE_N])
33 {
34     Vec opposing_force = {
35         .x = 0.0f,
36         .y = 0.0f
37     };
38
39     for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
40         if (sides[side]) {
41             vec_add(
42                 &opposing_force,
43                 opposing_rect_side_forces[side]);
44         }
45     }
46
47     return opposing_force;
48 }
49
50 Rigid_rect *create_rigid_rect(Rect rect, Color color)
51 {
52     Lt *lt = create_lt();
53
54     if (lt == NULL) {
55         return NULL;
56     }
57
58     Rigid_rect *rigid_rect = PUSH_LT(lt, malloc(sizeof(Rigid_rect)), free);
59     if (rigid_rect == NULL) {
60         throw_error(ERROR_TYPE_LIBC);
61         RETURN_LT(lt, NULL);
62     }
63
64     rigid_rect->lt = lt;
65     rigid_rect->position = vec(rect.x, rect.y);
66     rigid_rect->velocity = vec(0.0f, 0.0f);
67     rigid_rect->movement = vec(0.0f, 0.0f);
68     rigid_rect->size = vec(rect.w, rect.h);
69     rigid_rect->color = color;
70     rigid_rect->touches_ground = 0;
71     rigid_rect->forces = vec(0.0f, 0.0f);
72
73     return rigid_rect;
74 }
75
76 Rigid_rect *create_rigid_rect_from_stream(FILE *stream)
77 {
78     assert(stream);
79
80     char color[7];
81     Rect rect;
82
83     if (fscanf(stream, "%f%f%f%f%6s\n",
84                &rect.x, &rect.y,
85                &rect.w, &rect.h,
86                color) < 0) {
87         throw_error(ERROR_TYPE_LIBC);
88         return NULL;
89     }
90
91     return create_rigid_rect(rect, color_from_hexstr(color));
92 }
93
94 void destroy_rigid_rect(Rigid_rect *rigid_rect)
95 {
96     RETURN_LT0(rigid_rect->lt);
97 }
98
99 Solid_ref rigid_rect_as_solid(Rigid_rect *rigid_rect)
100 {
101     const Solid_ref ref = {
102         .tag = SOLID_RIGID_RECT,
103         .ptr = rigid_rect
104     };
105
106     return ref;
107 }
108
109 void rigid_rect_touches_rect_sides(Rigid_rect *rigid_rect,
110                                    Rect object,
111                                    int sides[RECT_SIDE_N])
112 {
113     rect_object_impact(object, rigid_rect_hitbox(rigid_rect), sides);
114 }
115
116 int rigid_rect_render(const Rigid_rect *rigid_rect,
117                       Camera *camera)
118 {
119     return camera_fill_rect(
120         camera,
121         rigid_rect_hitbox(rigid_rect),
122         rigid_rect->color);
123 }
124
125 int rigid_rect_update(Rigid_rect * rigid_rect,
126                       float delta_time)
127 {
128     assert(rigid_rect);
129
130     rigid_rect->touches_ground = 0;
131
132     /* TODO(#207): rigid_rect floating in lava is broken */
133     rigid_rect->velocity = vec_sum(
134         rigid_rect->velocity,
135         vec_scala_mult(
136             rigid_rect->forces,
137             delta_time));
138
139     rigid_rect->position = vec_sum(
140         rigid_rect->position,
141         vec_scala_mult(
142             vec_sum(
143                 rigid_rect->velocity,
144                 rigid_rect->movement),
145             delta_time));
146
147     rigid_rect->forces = vec(0.0f, 0.0f);
148
149     return 0;
150 }
151
152 void rigid_rect_collide_with_solid(Rigid_rect * rigid_rect,
153                                    Solid_ref solid)
154 {
155     assert(rigid_rect);
156     assert(rigid_rect != solid.ptr);
157
158     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
159
160     solid_touches_rect_sides(solid, rigid_rect_hitbox(rigid_rect), sides);
161
162     if (sides[RECT_SIDE_BOTTOM]) {
163         rigid_rect->touches_ground = 1;
164     }
165
166     Vec opforce_direction = opposing_force_by_sides(sides);
167
168     solid_apply_force(
169         solid,
170         vec_scala_mult(
171             vec_neg(vec_norm(opforce_direction)),
172             vec_length(
173                 vec_sum(
174                     rigid_rect->velocity,
175                     rigid_rect->movement)) * 8.0f));
176
177     if (fabs(opforce_direction.x) > 1e-6 && (opforce_direction.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
178         rigid_rect->velocity.x = 0.0f;
179         rigid_rect->movement.x = 0.0f;
180     }
181
182     if (fabs(opforce_direction.y) > 1e-6 && (opforce_direction.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
183         rigid_rect->velocity.y = 0.0f;
184         rigid_rect->movement.y = 0.0f;
185
186         if (vec_length(rigid_rect->velocity) > 1e-6) {
187             rigid_rect_apply_force(
188                 rigid_rect,
189                 vec_scala_mult(
190                     vec_neg(rigid_rect->velocity),
191                     16.0f));
192         }
193     }
194
195
196     for (int i = 0; i < 1000 && vec_length(opforce_direction) > 1e-6; ++i) {
197         rigid_rect->position = vec_sum(
198             rigid_rect->position,
199             vec_scala_mult(
200                 opforce_direction,
201                 1e-2f));
202
203         memset(sides, 0, sizeof(int) * RECT_SIDE_N);
204         solid_touches_rect_sides(
205             solid,
206             rigid_rect_hitbox(rigid_rect),
207             sides);
208         opforce_direction = opposing_force_by_sides(sides);
209     }
210 }
211
212 Rect rigid_rect_hitbox(const Rigid_rect *rigid_rect)
213 {
214     return rect_from_vecs(
215         rigid_rect->position,
216         rigid_rect->size);
217 }
218
219 void rigid_rect_move(Rigid_rect *rigid_rect,
220                            Vec movement)
221 {
222     rigid_rect->movement = movement;
223 }
224
225 int rigid_rect_touches_ground(const Rigid_rect *rigid_rect)
226 {
227     return rigid_rect->touches_ground;
228 }
229
230 void rigid_rect_apply_force(Rigid_rect * rigid_rect,
231                             Vec force)
232 {
233     rigid_rect->forces = vec_sum(rigid_rect->forces, force);
234 }
235
236 void rigid_rect_transform_velocity(Rigid_rect *rigid_rect,
237                                    mat3x3 trans_mat)
238 {
239     rigid_rect->velocity = point_mat3x3_product(rigid_rect->velocity,
240                                                 trans_mat);
241 }
242
243 void rigid_rect_teleport_to(Rigid_rect *rigid_rect,
244                             Vec position)
245 {
246     rigid_rect->position = position;
247 }
248
249 void rigid_rect_damper(Rigid_rect *rigid_rect, Vec v)
250 {
251     rigid_rect_apply_force(
252         rigid_rect,
253         vec(rigid_rect->velocity.x * v.x, rigid_rect->velocity.y * v.y));
254 }