6 #include "game/level/player/dying_rect.h"
7 #include "game/level/player/rigid_rect.h"
9 #include "math/point.h"
10 #include "platforms.h"
12 #include "system/error.h"
13 #include "system/line_stream.h"
14 #include "system/lt.h"
15 #include "system/nth_alloc.h"
17 #define PLAYER_WIDTH 25.0f
18 #define PLAYER_HEIGHT 25.0f
19 #define PLAYER_SPEED 500.0f
20 #define PLAYER_JUMP 32000.0f
21 #define PLAYER_DEATH_DURATION 0.75f
22 #define PLAYER_MAX_JUMP_COUNT 2
24 typedef enum Player_state {
25 PLAYER_STATE_ALIVE = 0,
33 Rigid_rect *alive_body;
34 Dying_rect *dying_body;
44 Player *create_player(float x, float y, Color color)
52 Player *player = PUSH_LT(lt, nth_alloc(sizeof(Player)), free);
54 throw_error(ERROR_TYPE_LIBC);
58 player->state = PLAYER_STATE_ALIVE;
60 player->alive_body = PUSH_LT(
63 rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
67 if (player->alive_body == NULL) {
71 player->dying_body = PUSH_LT(
75 PLAYER_DEATH_DURATION),
77 if (player->dying_body == NULL) {
82 player->jump_count = 0;
83 player->color = color;
84 player->checkpoint = vec(x, y);
85 player->play_die_cue = 0;
90 Player *create_player_from_line_stream(LineStream *line_stream)
92 float x = 0.0f, y = 0.0f;
96 line_stream_next(line_stream),
98 &x, &y, color) == EOF) {
99 throw_error(ERROR_TYPE_LIBC);
103 return create_player(x, y, color_from_hexstr(color));
106 void destroy_player(Player * player)
108 RETURN_LT0(player->lt);
111 Solid_ref player_as_solid(Player *player)
115 .ptr = (void*) player
121 int player_render(const Player * player,
127 switch (player->state) {
128 case PLAYER_STATE_ALIVE:
129 return rigid_rect_render(player->alive_body, camera);
131 case PLAYER_STATE_DYING:
132 return dying_rect_render(player->dying_body, camera);
140 void player_update(Player *player,
145 switch (player->state) {
146 case PLAYER_STATE_ALIVE: {
147 rigid_rect_update(player->alive_body, delta_time);
149 const Rect hitbox = rigid_rect_hitbox(player->alive_body);
151 if (hitbox.y > 1000.0f) {
156 case PLAYER_STATE_DYING: {
157 dying_rect_update(player->dying_body, delta_time);
159 if (dying_rect_is_dead(player->dying_body)) {
160 rigid_rect_transform_velocity(
162 make_mat3x3(0.0f, 0.0f, 0.0f,
165 rigid_rect_teleport_to(player->alive_body, player->checkpoint);
166 player->state = PLAYER_STATE_ALIVE;
174 void player_collide_with_solid(Player *player, Solid_ref solid)
176 if (player->state == PLAYER_STATE_ALIVE) {
177 rigid_rect_collide_with_solid(player->alive_body, solid);
179 if (rigid_rect_touches_ground(player->alive_body)) {
180 player->jump_count = 0;
185 void player_move_left(Player *player)
188 rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
191 void player_move_right(Player *player)
195 rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
198 void player_stop(Player *player)
202 rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
205 void player_jump(Player *player)
208 if (player->jump_count < PLAYER_MAX_JUMP_COUNT) {
209 rigid_rect_transform_velocity(player->alive_body,
210 make_mat3x3(1.0f, 0.0f, 0.0f,
213 rigid_rect_apply_force(player->alive_body,
214 vec(0.0f, -PLAYER_JUMP));
215 player->jump_count++;
219 void player_die(Player *player)
223 if (player->state == PLAYER_STATE_ALIVE) {
225 rigid_rect_hitbox(player->alive_body);
227 player->play_die_cue = 1;
228 dying_rect_start_dying(player->dying_body, vec(hitbox.x, hitbox.y));
229 player->state = PLAYER_STATE_DYING;
233 void player_focus_camera(Player *player,
239 const Rect player_hitbox = rigid_rect_hitbox(player->alive_body);
244 vec(player_hitbox.x, player_hitbox.y),
245 vec(0.0f, -player_hitbox.h * 0.5f)));
248 void player_hide_goals(const Player *player,
253 goals_hide(goals, rigid_rect_hitbox(player->alive_body));
256 void player_die_from_lava(Player *player,
259 if (lava_overlaps_rect(lava, rigid_rect_hitbox(player->alive_body))) {
264 void player_checkpoint(Player *player, Vec checkpoint)
266 player->checkpoint = checkpoint;
269 int player_sound(Player *player,
270 Sound_samples *sound_samples)
272 if (player->play_die_cue) {
273 player->play_die_cue = 0;
275 if (sound_samples_play_sound(sound_samples, 0, 0) < 0) {
283 void player_touches_rect_sides(Player *player,
285 int sides[RECT_SIDE_N])
287 if (player->state == PLAYER_STATE_ALIVE) {
288 rigid_rect_touches_rect_sides(player->alive_body, object, sides);
292 void player_apply_force(Player *player, Vec force)
294 if (player->state == PLAYER_STATE_ALIVE) {
295 rigid_rect_apply_force(player->alive_body, force);
299 Rigid_rect *player_rigid_rect(Player *player, const char *id)
304 if (player->state == PLAYER_STATE_ALIVE) {
305 if (rigid_rect_has_id(player->alive_body, id)) {
306 return player->alive_body;
313 bool player_overlaps_rect(const Player *player,
318 return player->state == PLAYER_STATE_ALIVE
320 rect, rigid_rect_hitbox(
321 player->alive_body));