X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fplayer.c;h=334061763c78d642a24c42911b02f4f9d0505662;hb=d6dcc416e81e0838642b19b4a4ae98c85d2fc022;hp=2e9476d3a0af9b2039d3b95b3fb9c8790288d2ff;hpb=ae6aa2f72ba09bc49884f0d886ba462dde5c67c8;p=nothing.git diff --git a/src/player.c b/src/player.c index 2e9476d3..33406176 100644 --- a/src/player.c +++ b/src/player.c @@ -3,68 +3,80 @@ #include #include +#include "./lt.h" #include "./player.h" #include "./platforms.h" #include "./point.h" #include "./error.h" +#include "./rigid_rect.h" +#include "./dying_rect.h" -#define PLAYER_WIDTH 50.0f -#define PLAYER_HEIGHT 50.0f +#define PLAYER_WIDTH 25.0f +#define PLAYER_HEIGHT 25.0f #define PLAYER_SPEED 500.0f -#define PLAYER_GRAVITY 1500.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 { - vec_t position; - vec_t velocity; - vec_t movement; - float height; - float width; + lt_t *lt; + player_state_t state; + + rigid_rect_t *alive_body; + dying_rect_t *dying_body; + int jump_count; -}; + color_t color; -static const vec_t opposing_rect_side_forces[RECT_SIDE_N] = { - { .x = 1.0f, .y = 0.0f }, /* RECT_SIDE_LEFT = 0, */ - { .x = -1.0f, .y = 0.0f }, /* RECT_SIDE_RIGHT, */ - { .x = 0.0f, .y = 1.0f, }, /* RECT_SIDE_TOP, */ - { .x = 0.0f, .y = -1.0f, } /* RECT_SIDE_BOTTOM, */ + /* TODO(#110): introduce checkpoints */ + vec_t checkpoint; }; -static vec_t opposing_force_by_sides(int sides[RECT_SIDE_N]) +player_t *create_player(float x, float y, color_t color) { - vec_t opposing_force = { - .x = 0.0f, - .y = 0.0f - }; - - for (rect_side_t side = 0; side < RECT_SIDE_N; ++side) { - if (sides[side]) { - vec_add( - &opposing_force, - opposing_rect_side_forces[side]); - } - } - - return opposing_force; -} + lt_t *lt = create_lt(); -player_t *create_player(float x, float y) -{ - player_t *player = malloc(sizeof(player_t)); + if (lt == NULL) { + return NULL; + } + player_t *player = PUSH_LT(lt, malloc(sizeof(player_t)), free); if (player == NULL) { throw_error(ERROR_TYPE_LIBC); - return NULL; + RETURN_LT(lt, NULL); + } + + 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->alive_body == NULL) { + RETURN_LT(lt, NULL); } - player->position.x = x; - player->position.y = y; - player->velocity.x = 0.0f; - player->velocity.y = 0.0f; - player->movement.x = 0.0f; - player->movement.y = 0.0f; - player->height = PLAYER_HEIGHT; - player->width = PLAYER_WIDTH; - player->jump_count = 2; + 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; } @@ -73,32 +85,21 @@ player_t *create_player_from_stream(FILE *stream) { float x = 0.0f, y = 0.0f; - if (fscanf(stream, "%f%f", &x, &y) == EOF) { + char color[7]; + if (fscanf(stream, "%f%f%6s", &x, &y, color) == EOF) { throw_error(ERROR_TYPE_LIBC); return NULL; } - return create_player(x, y); + return create_player(x, y, color_from_hexstr(color)); } void destroy_player(player_t * player) { - free(player); -} - -rect_t player_hitbox(const player_t *player) -{ - rect_t hitbox = { - .x = player->position.x - player->width / 2, - .y = player->position.y - player->height, - .w = player->width, - .h = player->height - }; - - return hitbox; + RETURN_LT0(player->lt); } -int render_player(const player_t * player, +int player_render(const player_t * player, SDL_Renderer *renderer, const camera_t *camera) { @@ -106,100 +107,103 @@ int render_player(const player_t * player, assert(renderer); assert(camera); - if (SDL_SetRenderDrawColor(renderer, 96, 255, 96, 255) < 0) { - throw_error(ERROR_TYPE_SDL2); - return -1; - } - rect_t player_object = player_hitbox(player); + 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 camera_fill_rect(camera, renderer, &player_object); + return 0; } -void update_player(player_t *player, +void player_update(player_t *player, const platforms_t *platforms, Uint32 delta_time) { assert(player); assert(platforms); - float d = (float) delta_time / 1000.0f; - - player->velocity.y += PLAYER_GRAVITY * d; - player->position = vec_sum( - player->position, - vec_scala_mult( - vec_sum( - player->velocity, - player->movement), - d)); - player->position.y = fmodf(player->position.y, 800.0f); - - int sides[RECT_SIDE_N] = { 0, 0, 0, 0 }; + switch (player->state) { + case PLAYER_STATE_ALIVE: { + rigid_rect_update(player->alive_body, platforms, delta_time); - platforms_rect_object_collide(platforms, player_hitbox(player), sides); - vec_t opposing_force = opposing_force_by_sides(sides); - - if (sides[RECT_SIDE_BOTTOM]) { - player->jump_count = 2; - } + if (rigid_rect_touches_ground(player->alive_body)) { + player->jump_count = 0; + } - for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) { - player->position = vec_sum( - player->position, - vec_scala_mult( - opposing_force, - 1e-2f)); + const rect_t hitbox = rigid_rect_hitbox(player->alive_body); - if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((player->velocity.x + player->movement.x) < 0.0f)) { - player->velocity.x = 0.0f; - player->movement.x = 0.0f; + if (hitbox.y > 1000.0f) { + player_die(player); } - - if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((player->velocity.y + player->movement.y) < 0.0f)) { - player->velocity.y = 0.0f; - player->movement.y = 0.0f; + } 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; - platforms_rect_object_collide( - platforms, - player_hitbox(player), - sides); - opposing_force = opposing_force_by_sides(sides); + default: {} } } void player_move_left(player_t *player) { assert(player); - - player->movement.x = -PLAYER_SPEED; - player->movement.y = 0.0f; + rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f)); } void player_move_right(player_t *player) { assert(player); - player->movement.x = PLAYER_SPEED; - player->movement.y = 0.0f; + rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f)); } void player_stop(player_t *player) { assert(player); - player->movement.x = 0.0f; - player->movement.y = 0.0f; + rigid_rect_move(player->alive_body, vec(0.0f, 0.0f)); } void player_jump(player_t *player) +{ + assert(player); + 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->jump_count > 0) { - player->velocity.y = -550.0f; - --player->jump_count; + 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; } } @@ -209,7 +213,13 @@ void player_focus_camera(player_t *player, assert(player); assert(camera); - camera_center_at(camera, vec_sum(player->position, vec(0.0f, -player->height * 0.5f))); + const rect_t player_hitbox = rigid_rect_hitbox(player->alive_body); + + camera_center_at( + camera, + vec_sum( + vec(player_hitbox.x, player_hitbox.y), + vec(0.0f, -player_hitbox.h * 0.5f))); } void player_hide_goals(const player_t *player, @@ -217,5 +227,13 @@ void player_hide_goals(const player_t *player, { assert(player); assert(goals); - goals_hide(goals, player->position); + 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); + } }