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