]> git.lizzy.rs Git - nothing.git/blob - src/game/level/player/rigid_rect.c
Factor out duplicate memsets
[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 #define RIGID_RECT_GRAVITY 1500.0f
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 };
23
24 static const vec_t opposing_rect_side_forces[RECT_SIDE_N] = {
25     { .x = 1.0f,  .y =  0.0f  },  /* RECT_SIDE_LEFT = 0, */
26     { .x = -1.0f, .y =  0.0f  },  /* RECT_SIDE_RIGHT, */
27     { .x = 0.0f,  .y =  1.0f, },  /* RECT_SIDE_TOP, */
28     { .x = 0.0f,  .y = -1.0f, }   /* RECT_SIDE_BOTTOM, */
29 };
30
31 static vec_t opposing_force_by_sides(int sides[RECT_SIDE_N])
32 {
33     vec_t opposing_force = {
34         .x = 0.0f,
35         .y = 0.0f
36     };
37
38     for (rect_side_t side = 0; side < RECT_SIDE_N; ++side) {
39         if (sides[side]) {
40             vec_add(
41                 &opposing_force,
42                 opposing_rect_side_forces[side]);
43         }
44     }
45
46     return opposing_force;
47 }
48
49 rigid_rect_t *create_rigid_rect(rect_t rect, color_t color)
50 {
51     lt_t *lt = create_lt();
52
53     if (lt == NULL) {
54         return NULL;
55     }
56
57     rigid_rect_t *rigid_rect = PUSH_LT(lt, malloc(sizeof(rigid_rect_t)), free);
58     if (rigid_rect == NULL) {
59         throw_error(ERROR_TYPE_LIBC);
60         RETURN_LT(lt, NULL);
61     }
62
63     rigid_rect->lt = lt;
64     rigid_rect->position = vec(rect.x, rect.y);
65     rigid_rect->velocity = vec(0.0f, 0.0f);
66     rigid_rect->movement = vec(0.0f, 0.0f);
67     rigid_rect->size = vec(rect.w, rect.h);
68     rigid_rect->color = color;
69     rigid_rect->touches_ground = 0;
70
71     return rigid_rect;
72 }
73
74 rigid_rect_t *create_rigid_rect_from_stream(FILE *stream)
75 {
76     assert(stream);
77
78     char color[7];
79     rect_t rect;
80
81     if (fscanf(stream, "%f%f%f%f%6s\n",
82                &rect.x, &rect.y,
83                &rect.w, &rect.h,
84                color) < 0) {
85         throw_error(ERROR_TYPE_LIBC);
86         return NULL;
87     }
88
89     return create_rigid_rect(rect, color_from_hexstr(color));
90 }
91
92 void destroy_rigid_rect(rigid_rect_t *rigid_rect)
93 {
94     RETURN_LT0(rigid_rect->lt);
95 }
96
97 solid_ref_t rigid_rect_as_solid(rigid_rect_t *rigid_rect)
98 {
99     const solid_ref_t ref = {
100         .tag = SOLID_RIGID_RECT,
101         .ptr = rigid_rect
102     };
103
104     return ref;
105 }
106
107 void rigid_body_object_collide(rigid_rect_t *rigid_rect,
108                                rect_t object,
109                                int sides[RECT_SIDE_N])
110 {
111     rect_object_impact(object, rigid_rect_hitbox(rigid_rect), sides);
112 }
113
114 int rigid_rect_render(const rigid_rect_t *rigid_rect,
115                       const camera_t *camera)
116 {
117     return camera_fill_rect(
118         camera,
119         rigid_rect_hitbox(rigid_rect),
120         rigid_rect->color);
121
122 }
123
124 int rigid_rect_update(rigid_rect_t * rigid_rect,
125                       float delta_time)
126 {
127     assert(rigid_rect);
128
129     rigid_rect->touches_ground = 0;
130
131     rigid_rect->velocity.y += RIGID_RECT_GRAVITY * delta_time;
132     rigid_rect->position = vec_sum(
133         rigid_rect->position,
134         vec_scala_mult(
135             vec_sum(
136                 rigid_rect->velocity,
137                 rigid_rect->movement),
138             delta_time));
139
140     return 0;
141 }
142
143 void rigid_rect_collide_with_solid(rigid_rect_t * rigid_rect,
144                                    solid_ref_t solid)
145 {
146     assert(rigid_rect);
147     assert(rigid_rect != solid.ptr);
148
149     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
150
151     solid_rect_object_collide(solid, rigid_rect_hitbox(rigid_rect), sides);
152
153     if (sides[RECT_SIDE_BOTTOM]) {
154         rigid_rect->touches_ground = 1;
155     }
156
157     vec_t opposing_force = opposing_force_by_sides(sides);
158
159     for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
160         rigid_rect->position = vec_sum(
161             rigid_rect->position,
162             vec_scala_mult(
163                 opposing_force,
164                 1e-2f));
165
166         if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((rigid_rect->velocity.x + rigid_rect->movement.x) < 0.0f)) {
167             rigid_rect->velocity.x = 0.0f;
168             rigid_rect->movement.x = 0.0f;
169         }
170
171         if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((rigid_rect->velocity.y + rigid_rect->movement.y) < 0.0f)) {
172             rigid_rect->velocity.y = 0.0f;
173             rigid_rect->movement.y = 0.0f;
174         }
175
176         memset(sides, 0, sizeof(int) * RECT_SIDE_N);
177         solid_rect_object_collide(
178             solid,
179             rigid_rect_hitbox(rigid_rect),
180             sides);
181         opposing_force = opposing_force_by_sides(sides);
182     }
183 }
184
185 void rigid_rect_impact_rigid_rect(rigid_rect_t * rigid_rect,
186                                  rigid_rect_t *another_rect)
187 {
188     if (rects_overlap(rigid_rect_hitbox(rigid_rect), rigid_rect_hitbox(another_rect))) {
189         rigid_rect_move(another_rect,
190                         vec_sum(
191                             rigid_rect->velocity,
192                             rigid_rect->movement));
193     }
194 }
195
196 rect_t rigid_rect_hitbox(const rigid_rect_t *rigid_rect)
197 {
198     return rect_from_vecs(
199         rigid_rect->position,
200         rigid_rect->size);
201 }
202
203 void rigid_rect_move(rigid_rect_t *rigid_rect,
204                            vec_t movement)
205 {
206     rigid_rect->movement = movement;
207 }
208
209 void rigid_rect_jump(rigid_rect_t *rigid_rect,
210                      float force)
211 {
212     rigid_rect->velocity.y = -force;
213 }
214
215 int rigid_rect_touches_ground(const rigid_rect_t *rigid_rect)
216 {
217     return rigid_rect->touches_ground;
218 }