#include "./point.h"
#include "./error.h"
#include "./rigid_rect.h"
+#include "./dying_rect.h"
#define PLAYER_WIDTH 25.0f
#define PLAYER_HEIGHT 25.0f
#define PLAYER_SPEED 500.0f
#define PLAYER_JUMP 550.0f
+#define PLAYER_DEATH_DURATION 500
+
+typedef enum player_state_t {
+ PLAYER_STATE_ALIVE = 0,
+ PLAYER_STATE_DYING
+} player_state_t;
struct player_t {
lt_t *lt;
- rigid_rect_t *player_body;
- /* TODO(#105): fix player jump_count */
+ player_state_t state;
+
+ rigid_rect_t *alive_body;
+ dying_rect_t *dying_body;
+
int jump_count;
+ color_t color;
+
+ /* TODO(#110): introduce checkpoints */
+ vec_t checkpoint;
};
player_t *create_player(float x, float y, color_t color)
RETURN_LT(lt, NULL);
}
- player->player_body = PUSH_LT(
+ player->state = PLAYER_STATE_ALIVE;
+
+ player->alive_body = PUSH_LT(
lt,
create_rigid_rect(
rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
color),
destroy_rigid_rect);
- if (player->player_body == NULL) {
+ if (player->alive_body == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ player->dying_body = PUSH_LT(
+ lt,
+ create_dying_rect(
+ rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
+ color,
+ PLAYER_DEATH_DURATION),
+ destroy_dying_rect);
+ if (player->dying_body == NULL) {
RETURN_LT(lt, NULL);
}
player->lt = lt;
player->jump_count = 0;
+ player->color = color;
+ player->checkpoint = vec(x, y);
return player;
}
assert(player);
assert(renderer);
assert(camera);
- return rigid_rect_render(player->player_body, renderer, camera);
+
+ switch (player->state) {
+ case PLAYER_STATE_ALIVE:
+ return rigid_rect_render(player->alive_body, renderer, camera);
+
+ case PLAYER_STATE_DYING:
+ return dying_rect_render(player->dying_body, renderer, camera);
+
+ default: {}
+ }
+
+ return 0;
}
void player_update(player_t *player,
{
assert(player);
assert(platforms);
- rigid_rect_update(player->player_body, platforms, delta_time);
+
+ switch (player->state) {
+ case PLAYER_STATE_ALIVE: {
+ rigid_rect_update(player->alive_body, platforms, delta_time);
+
+ if (rigid_rect_touches_ground(player->alive_body)) {
+ player->jump_count = 0;
+ }
+
+ const rect_t hitbox = rigid_rect_hitbox(player->alive_body);
+
+ if (hitbox.y > 1000.0f) {
+ player_die(player);
+ }
+ } break;
+
+ case PLAYER_STATE_DYING: {
+ dying_rect_update(player->dying_body, delta_time);
+
+ if (dying_rect_is_dead(player->dying_body)) {
+ player->alive_body = RESET_LT(
+ player->lt,
+ player->alive_body,
+ create_rigid_rect(
+ rect_from_vecs(
+ player->checkpoint,
+ vec(PLAYER_WIDTH, PLAYER_HEIGHT)),
+ player->color));
+ player->state = PLAYER_STATE_ALIVE;
+ }
+ } break;
+
+ default: {}
+ }
}
void player_move_left(player_t *player)
{
assert(player);
- rigid_rect_move(player->player_body, vec(-PLAYER_SPEED, 0.0f));
+ rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
}
void player_move_right(player_t *player)
{
assert(player);
- rigid_rect_move(player->player_body, vec(PLAYER_SPEED, 0.0f));
+ rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
}
void player_stop(player_t *player)
{
assert(player);
- rigid_rect_move(player->player_body, vec(0.0f, 0.0f));
+ rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
}
void player_jump(player_t *player)
{
assert(player);
- rigid_rect_jump(player->player_body, PLAYER_JUMP);
+ if (player->jump_count < 2) {
+ rigid_rect_jump(player->alive_body, PLAYER_JUMP);
+ player->jump_count++;
+ }
+}
+
+void player_die(player_t *player)
+{
+ assert(player);
+
+ if (player->state == PLAYER_STATE_ALIVE) {
+ player->dying_body = RESET_LT(
+ player->lt,
+ player->dying_body,
+ create_dying_rect(
+ rigid_rect_hitbox(player->alive_body),
+ player->color,
+ PLAYER_DEATH_DURATION));
+ player->state = PLAYER_STATE_DYING;
+ }
}
void player_focus_camera(player_t *player,
assert(player);
assert(camera);
- const rect_t player_hitbox = rigid_rect_hitbox(player->player_body);
+ const rect_t player_hitbox = rigid_rect_hitbox(player->alive_body);
camera_center_at(
camera,
{
assert(player);
assert(goals);
- goals_hide(goals, rigid_rect_hitbox(player->player_body));
+ goals_hide(goals, rigid_rect_hitbox(player->alive_body));
+}
+
+void player_die_from_lava(player_t *player,
+ const lava_t *lava)
+{
+ if (lava_overlaps_rect(lava, rigid_rect_hitbox(player->alive_body))) {
+ player_die(player);
+ }
}