#include "player.h" #include "SDL_keycode.h" #include "SDL_render.h" #include "animation_player.h" #include "state_machine.h" #include #include #include #define SPRITE_WIDTH 100 #define SPRITE_HEIGHT 64 State *update_state(Player *player, uint32_t state); State *idle_state(StateMachine *sm, Player *player); State *walk_state(StateMachine *sm, Player *player); State *jump_state(StateMachine *sm, Player *player); State *fall_state(StateMachine *sm, Player *player); State *dash_state(StateMachine *sm, Player *player); void player_init(Player *player, SDL_Renderer *renderer, SDL_Rect position) { 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_JUMP] = ap_init(renderer, "knight_player/Jump_KG_2.png", 125, SPRITE_WIDTH, SPRITE_HEIGHT, false); player->animations[PLAYER_STATE_FALL] = ap_init(renderer, "knight_player/Fall_KG_2.png", 125, SPRITE_WIDTH, SPRITE_HEIGHT, false); player->animations[PLAYER_STATE_DASH] = ap_init(renderer, "knight_player/Dashing_KG_1.png", 125, 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_JUMP] = (State){ .state_func = (StateFunc *)jump_state }; player->states[PLAYER_STATE_FALL] = (State){ .state_func = (StateFunc *)fall_state }; player->states[PLAYER_STATE_DASH] = (State){ .state_func = (StateFunc *)dash_state }; player->event_data = (PlayerEventData){0}; player->state_machine = (StateMachine){ .current_state = &(player->states[PLAYER_STATE_IDLE]) }; player->current_state = PLAYER_STATE_IDLE; } void player_events(Player *player, const SDL_Event *event) { if (!player || !event) { return; } switch (event->type) { case SDL_KEYDOWN: switch (event->key.keysym.sym) { case SDLK_LEFT: player->movement.x = PLAYER_DIRECTION_LEFT * player->velocity; player->x_direction = PLAYER_DIRECTION_LEFT; player->event_data.key = PLAYER_CONTROL_LEFT_DOWN; break; case SDLK_RIGHT: player->movement.x = PLAYER_DIRECTION_RIGHT * player->velocity; player->x_direction = PLAYER_DIRECTION_RIGHT; player->event_data.key = PLAYER_CONTROL_RIGHT_DOWN; break; } break; case SDL_KEYUP: switch (event->key.keysym.sym) { case SDLK_LEFT: player->movement.x = 0; player->event_data.key = PLAYER_CONTROL_LEFT_UP; break; case SDLK_RIGHT: player->movement.x = 0; player->event_data.key = PLAYER_CONTROL_RIGHT_UP; break; case SDLK_SPACE: player->event_data.key = PLAYER_CONTROL_SPACE; break; case SDLK_LCTRL: player->movement.x = player->x_direction * player->velocity * 3; player->event_data.key = PLAYER_CONTROL_LCTRL; if (player->current_state == PLAYER_STATE_JUMP) { player->event_data.dash_in_air = true; } else { player->event_data.dash_in_air = false; } break; } break; } } void player_update(Player *player, uint32_t ticks) { player->position.x += player->movement.x; sm_run(&(player->state_machine), (void *)player); ap_update(&(player->animations[player->current_state]), ticks); player->event_data.key = PLAYER_CONTROL_NONE; } 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); } 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) { switch (player->event_data.key) { case PLAYER_CONTROL_LEFT_DOWN: case PLAYER_CONTROL_RIGHT_DOWN: return update_state(player, PLAYER_STATE_WALK); case PLAYER_CONTROL_SPACE: return update_state(player, PLAYER_STATE_JUMP); } return update_state(player, PLAYER_STATE_IDLE); } State *walk_state(StateMachine *sm, Player *player) { switch (player->event_data.key) { case PLAYER_CONTROL_LEFT_UP: case PLAYER_CONTROL_RIGHT_UP: return update_state(player, PLAYER_STATE_IDLE); case PLAYER_CONTROL_SPACE: return update_state(player, PLAYER_STATE_JUMP); case PLAYER_CONTROL_LCTRL: return update_state(player, PLAYER_STATE_DASH); } return update_state(player, PLAYER_STATE_WALK); } State *jump_state(StateMachine *sm, Player *player) { bool reset = false; uint32_t state = PLAYER_STATE_JUMP; if (player->animations[PLAYER_STATE_JUMP].finished) { reset = true; state = PLAYER_STATE_FALL; } else if (player->event_data.key == PLAYER_CONTROL_LCTRL) { reset = true; state = PLAYER_STATE_DASH; } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_JUMP])); } 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) { reset = true; state = PLAYER_STATE_IDLE; } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_FALL])); } 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 * 10; if (player->animations[PLAYER_STATE_DASH].finished) { reset = true; player->movement.x = 0; if (player->event_data.dash_in_air) { state = PLAYER_STATE_FALL; } else { state = PLAYER_STATE_IDLE; } } if (reset) { ap_reset(&(player->animations[PLAYER_STATE_DASH])); } return update_state(player, state); }