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