#include "player.h" #include "animation_player.h" #include "state_machine.h" #include #include #include #include #include #include #define SPRITE_WIDTH 100 #define SPRITE_HEIGHT 64 void get_player_controls(Player *player); void set_x_movement (Player *player); void player_move (Player *player); void player_dash (Player *player); void player_jump (Player *player); void player_fall (Player *player); bool player_on_ground (Player *player); int32_t player_gravity (Player *player); State *update_state (Player *player, uint32_t state); State *idle_state (StateMachine *sm, Player *player); State *walk_state (StateMachine *sm, Player *player); State *dash_state (StateMachine *sm, Player *player); State *jump_state (StateMachine *sm, Player *player); State *fall_state (StateMachine *sm, Player *player); void player_init(Player *player, SDL_Renderer *renderer, SDL_Rect position) { player->base_y = position.y; player->position = position; player->movement = (Movement){0}; player->x_direction = PLAYER_DIRECTION_RIGHT; player->velocity = 4; player->animations[PLAYER_STATE_IDLE] = ap_init(renderer, "knight_player/Idle_KG_2.png", 125, SPRITE_WIDTH, SPRITE_HEIGHT, true); player->animations[PLAYER_STATE_WALK] = ap_init(renderer, "knight_player/Walking_KG_2.png", 125, SPRITE_WIDTH, SPRITE_HEIGHT, true); player->animations[PLAYER_STATE_DASH] = ap_init(renderer, "knight_player/Dashing_KG_1.png", 125, SPRITE_WIDTH, SPRITE_HEIGHT, false); player->animations[PLAYER_STATE_JUMP] = ap_init(renderer, "knight_player/Jump_KG_2.png", 100, SPRITE_WIDTH, SPRITE_HEIGHT, false); player->animations[PLAYER_STATE_FALL] = ap_init(renderer, "knight_player/Fall_KG_2.png", 50, SPRITE_WIDTH, SPRITE_HEIGHT, false); player->states[PLAYER_STATE_IDLE] = (State){ .state_func = (StateFunc *)idle_state }; player->states[PLAYER_STATE_WALK] = (State){ .state_func = (StateFunc *)walk_state }; player->states[PLAYER_STATE_DASH] = (State){ .state_func = (StateFunc *)dash_state }; player->states[PLAYER_STATE_JUMP] = (State){ .state_func = (StateFunc *)jump_state }; player->states[PLAYER_STATE_FALL] = (State){ .state_func = (StateFunc *)fall_state }; player->state_machine = (StateMachine){ .current_state = &(player->states[PLAYER_STATE_IDLE]) }; player->current_state = PLAYER_STATE_IDLE; player->controls = (PlayerControl){0}; } void player_update(Player *player, uint32_t ticks) { get_player_controls(player); sm_run(&(player->state_machine), (void *)player); player_move(player); ap_update(&(player->animations[player->current_state]), ticks); } void player_draw(const Player *player, SDL_Renderer *renderer) { ap_draw(renderer, &(player->animations[player->current_state]), &(player->position), player->x_direction == PLAYER_DIRECTION_LEFT); } void get_player_controls(Player *player) { const uint8_t *keys = SDL_GetKeyboardState(NULL); player->controls.walk_left = keys[SDL_SCANCODE_LEFT] == SDL_PRESSED; player->controls.walk_right = keys[SDL_SCANCODE_RIGHT] == SDL_PRESSED; player->controls.space_last = player->controls.space_pressed; player->controls.space_pressed = keys[SDL_SCANCODE_SPACE] == SDL_PRESSED; player->controls.jump = player->controls.space_last && !(player->controls.space_pressed); player->controls.lctrl_last = player->controls.lctrl_pressed; player->controls.lctrl_pressed = keys[SDL_SCANCODE_LCTRL] == SDL_PRESSED; player->controls.dash = player->controls.lctrl_last && !(player->controls.lctrl_pressed); } void set_x_movement(Player *player) { if (player->controls.walk_left) { player->movement.x = PLAYER_DIRECTION_LEFT * player->velocity; player->x_direction = PLAYER_DIRECTION_LEFT; } else if (player->controls.walk_right) { player->movement.x = PLAYER_DIRECTION_RIGHT * player->velocity; player->x_direction = PLAYER_DIRECTION_RIGHT; } else if (!(player->controls.walk_left) && !(player->controls.walk_right)) { player->movement.x = 0; } } void player_move(Player *player) { player->position.x += player->movement.x; player->position.y += player->movement.y; if (player->position.y > player->base_y) { player->position.y = player->base_y; } } void player_dash(Player *player) { player->movement.x = player->x_direction * player->velocity * 2; } void player_jump(Player *player) { player->movement.y = player->velocity * 7 * -1; } void player_fall(Player *player) { player->movement.y = player->velocity * 6; } bool player_on_ground(Player *player) { return player->position.y == player->base_y; } int32_t player_gravity(Player *player) { return player->velocity * 0.5; } bool player_falling(Player *player) { return player->movement.y > 0; } State *update_state(Player *player, uint32_t state) { if (state >= COUNT_PLAYER_STATES) { return &(player->states[player->current_state]); } player->current_state = state; return &(player->states[state]); } State *idle_state(StateMachine *sm, Player *player) { uint32_t state = PLAYER_STATE_IDLE; if (player->controls.jump) { player_jump(player); state = PLAYER_STATE_JUMP; } else if (player->controls.walk_left) { state = PLAYER_STATE_WALK; } else if (player->controls.walk_right) { state = PLAYER_STATE_WALK; } set_x_movement(player); return update_state(player, state); } State *walk_state(StateMachine *sm, Player *player) { uint32_t state = PLAYER_STATE_WALK; if (player->controls.jump) { player_jump(player); state = PLAYER_STATE_JUMP; } else if (player->controls.dash) { player_dash(player); player->controls.jump_dash = false; state = PLAYER_STATE_DASH; } if (!(player->controls.walk_left) && !(player->controls.walk_right)) { state = PLAYER_STATE_IDLE; } set_x_movement(player); return update_state(player, state); } State *dash_state(StateMachine *sm, Player *player) { bool reset = false; uint32_t state = PLAYER_STATE_DASH; player->movement.x += player->x_direction * (int32_t)player->velocity * 0.5; if (player->animations[PLAYER_STATE_DASH].finished) { if (player->controls.jump_dash) { player_fall(player); state = PLAYER_STATE_FALL; } else { player->movement.x = 0; state = PLAYER_STATE_IDLE; } reset = true; } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_DASH])); } return update_state(player, state); } State *jump_state(StateMachine *sm, Player *player) { bool reset = false; uint32_t state = PLAYER_STATE_JUMP; player->movement.y += player_gravity(player); if (player->controls.dash) { player_dash(player); player->controls.jump_dash = true; player->movement.y = player_gravity(player); reset = true; state = PLAYER_STATE_DASH; } else if (player->animations[PLAYER_STATE_JUMP].finished) { player_fall(player); reset = true; state = PLAYER_STATE_FALL; } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_JUMP])); } set_x_movement(player); return update_state(player, state); } State *fall_state(StateMachine *sm, Player *player) { bool reset = false; uint32_t state = PLAYER_STATE_FALL; if (player->animations[PLAYER_STATE_FALL].finished && player_on_ground(player)) { player->movement.y = 0; reset = true; state = PLAYER_STATE_IDLE; } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_FALL])); } set_x_movement(player); return update_state(player, state); }