135 lines
4.0 KiB
C
135 lines
4.0 KiB
C
#include "player.h"
|
|
#include "SDL_keycode.h"
|
|
#include "SDL_render.h"
|
|
#include "animation_player.h"
|
|
#include "state_machine.h"
|
|
#include <SDL2/SDL_events.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#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 *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_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_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;
|
|
}
|
|
|
|
player->event_data.event = event;
|
|
sm_run(&(player->state_machine), (void *)player);
|
|
}
|
|
|
|
void player_update(Player *player, uint32_t ticks) {
|
|
player->position.x += player->movement.x;
|
|
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);
|
|
}
|
|
|
|
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) {
|
|
const SDL_Event *event = player->event_data.event;
|
|
uint32_t state = PLAYER_STATE_IDLE;
|
|
|
|
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;
|
|
state = PLAYER_STATE_WALK;
|
|
break;
|
|
case SDLK_RIGHT:
|
|
player->movement.x = PLAYER_DIRECTION_RIGHT * player->velocity;
|
|
player->x_direction = PLAYER_DIRECTION_RIGHT;
|
|
state = PLAYER_STATE_WALK;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return update_state(player, state);
|
|
}
|
|
|
|
State *walk_state(StateMachine *sm, Player *player) {
|
|
const SDL_Event *event = player->event_data.event;
|
|
uint32_t state = PLAYER_STATE_WALK;
|
|
|
|
switch (event->type) {
|
|
case SDL_KEYUP:
|
|
switch (event->key.keysym.sym) {
|
|
case SDLK_LCTRL:
|
|
player->movement.x = player->x_direction * player->velocity * 3;
|
|
state = PLAYER_STATE_DASH;
|
|
break;
|
|
case SDLK_LEFT:
|
|
player->movement.x = 0;
|
|
state = PLAYER_STATE_IDLE;
|
|
break;
|
|
case SDLK_RIGHT:
|
|
player->movement.x = 0;
|
|
state = PLAYER_STATE_IDLE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
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 * 3;
|
|
|
|
if (player->animations[PLAYER_STATE_DASH].finished) {
|
|
player->movement.x = 0;
|
|
reset = true;
|
|
state = PLAYER_STATE_IDLE;
|
|
}
|
|
|
|
if (reset) {
|
|
ap_reset(&(player->animations[PLAYER_STATE_DASH]));
|
|
}
|
|
|
|
return update_state(player, state);
|
|
}
|