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