]> git.lizzy.rs Git - nothing.git/blob - src/player.c
7421dad6c171d36c3ee9ec28997ecb17d8256ca0
[nothing.git] / src / player.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <SDL2/SDL.h>
5
6 #include "./player.h"
7 #include "./platforms.h"
8 #include "./point.h"
9 #include "./error.h"
10
11 #define PLAYER_WIDTH 50.0f
12 #define PLAYER_HEIGHT 50.0f
13 #define PLAYER_SPEED 500.0f
14 #define PLAYER_JUMP 550.0f
15 #define PLAYER_GRAVITY 1500.0f
16
17 struct player_t {
18     vec_t position;
19     vec_t velocity;
20     vec_t movement;
21     float height;
22     float width;
23     int jump_count;
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 player_t *create_player(float x, float y)
52 {
53     player_t *player = malloc(sizeof(player_t));
54
55     if (player == NULL) {
56         throw_error(ERROR_TYPE_LIBC);
57         return NULL;
58     }
59
60     player->position.x = x;
61     player->position.y = y;
62     player->velocity.x = 0.0f;
63     player->velocity.y = 0.0f;
64     player->movement.x = 0.0f;
65     player->movement.y = 0.0f;
66     player->height = PLAYER_HEIGHT;
67     player->width = PLAYER_WIDTH;
68     player->jump_count = 2;
69
70     return player;
71 }
72
73 player_t *create_player_from_stream(FILE *stream)
74 {
75     float x = 0.0f, y = 0.0f;
76
77     if (fscanf(stream, "%f%f", &x, &y) == EOF) {
78         throw_error(ERROR_TYPE_LIBC);
79         return NULL;
80     }
81
82     return create_player(x, y);
83 }
84
85 void destroy_player(player_t * player)
86 {
87     free(player);
88 }
89
90 rect_t player_hitbox(const player_t *player)
91 {
92     rect_t hitbox = {
93         .x = player->position.x - player->width / 2,
94         .y = player->position.y - player->height,
95         .w = player->width,
96         .h = player->height
97     };
98
99     return hitbox;
100 }
101
102 int render_player(const player_t * player,
103                   SDL_Renderer *renderer,
104                   const camera_t *camera)
105 {
106     assert(player);
107     assert(renderer);
108     assert(camera);
109
110     if (SDL_SetRenderDrawColor(renderer, 96, 255, 96, 255) < 0) {
111         throw_error(ERROR_TYPE_SDL2);
112         return -1;
113     }
114     rect_t player_object = player_hitbox(player);
115
116
117     return camera_fill_rect(camera, renderer, &player_object);
118 }
119
120 void update_player(player_t *player,
121                    const platforms_t *platforms,
122                    Uint32 delta_time)
123 {
124     assert(player);
125     assert(platforms);
126
127     float d = (float) delta_time / 1000.0f;
128
129     player->velocity.y += PLAYER_GRAVITY * d;
130     player->position = vec_sum(
131         player->position,
132         vec_scala_mult(
133             vec_sum(
134                 player->velocity,
135                 player->movement),
136             d));
137     player->position.y = fmodf(player->position.y, 800.0f);
138
139     int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
140
141     platforms_rect_object_collide(platforms, player_hitbox(player), sides);
142     vec_t opposing_force = opposing_force_by_sides(sides);
143
144     if (sides[RECT_SIDE_BOTTOM]) {
145         player->jump_count = 2;
146     }
147
148     for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
149         player->position = vec_sum(
150             player->position,
151             vec_scala_mult(
152                 opposing_force,
153                 1e-2f));
154
155         if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((player->velocity.x + player->movement.x) < 0.0f)) {
156             player->velocity.x = 0.0f;
157             player->movement.x = 0.0f;
158         }
159
160         if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((player->velocity.y + player->movement.y) < 0.0f)) {
161             player->velocity.y = 0.0f;
162             player->movement.y = 0.0f;
163         }
164
165         platforms_rect_object_collide(
166             platforms,
167             player_hitbox(player),
168             sides);
169         opposing_force = opposing_force_by_sides(sides);
170     }
171 }
172
173 void player_move_left(player_t *player)
174 {
175     assert(player);
176
177     player->movement.x = -PLAYER_SPEED;
178     player->movement.y = 0.0f;
179 }
180
181 void player_move_right(player_t *player)
182 {
183     assert(player);
184
185     player->movement.x = PLAYER_SPEED;
186     player->movement.y = 0.0f;
187 }
188
189 void player_stop(player_t *player)
190 {
191     assert(player);
192
193     player->movement.x = 0.0f;
194     player->movement.y = 0.0f;
195 }
196
197 void player_jump(player_t *player)
198 {
199     assert(player);
200
201     if (player->jump_count > 0) {
202         player->velocity.y = -PLAYER_JUMP;
203         --player->jump_count;
204     }
205 }
206
207 void player_focus_camera(player_t *player,
208                          camera_t *camera)
209 {
210     assert(player);
211     assert(camera);
212
213     camera_center_at(camera, vec_sum(player->position, vec(0.0f, -player->height * 0.5f)));
214 }
215
216 void player_hide_goals(const player_t *player,
217                        goals_t *goals)
218 {
219     assert(player);
220     assert(goals);
221     goals_hide(goals, player->position);
222 }