From 6182a2db85ba210f4c91e90ffe4449733f7b08aa Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 10 Nov 2024 00:27:33 +0000 Subject: [PATCH] Add player jump and fall states --- player.c | 196 +++++++++++++++++++++++++++++++++++++++---------------- player.h | 19 ++++-- 2 files changed, 156 insertions(+), 59 deletions(-) diff --git a/player.c b/player.c index 0c02963..2d1d76d 100644 --- a/player.c +++ b/player.c @@ -1,21 +1,45 @@ #include "player.h" -#include "SDL_keycode.h" -#include "SDL_render.h" #include "animation_player.h" #include "state_machine.h" #include +#include +#include +#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 *dash_state(StateMachine *sm, Player *player); +void print_state (Player *player) { + switch(player->current_state) { + case PLAYER_STATE_IDLE: + printf("IDLE\n"); + break; + case PLAYER_STATE_WALK: + printf("WALK\n"); + break; + case PLAYER_STATE_DASH: + printf("DASH\n"); + break; + case PLAYER_STATE_JUMP: + printf("JUMP\n"); + break; + case PLAYER_STATE_FALL: + printf("FALL\n"); + break; + } +} +void get_player_controls(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; @@ -27,27 +51,42 @@ void player_init(Player *player, SDL_Renderer *renderer, SDL_Rect position) { 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", 80, 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->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); + player->controls = (PlayerControl){0}; } void player_update(Player *player, uint32_t ticks) { + get_player_controls(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; + } + + sm_run(&(player->state_machine), (void *)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; + } ap_update(&(player->animations[player->current_state]), ticks); } @@ -55,6 +94,21 @@ 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); +} + State *update_state(Player *player, uint32_t state) { if (state >= COUNT_PLAYER_STATES) { return &(player->states[player->current_state]); @@ -65,50 +119,34 @@ State *update_state(Player *player, uint32_t state) { } State *idle_state(StateMachine *sm, Player *player) { - const SDL_Event *event = player->event_data.event; - uint32_t state = PLAYER_STATE_IDLE; + 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; + if (player->controls.jump) { + player->movement.y = player->velocity * 6 * -1; + state = PLAYER_STATE_JUMP; + } else if (player->controls.walk_left) { + state = PLAYER_STATE_WALK; + } else if (player->controls.walk_right) { + state = PLAYER_STATE_WALK; } 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; + if (player->controls.jump) { + player->movement.y = player->velocity * 6 * -1; + state = PLAYER_STATE_JUMP; + } else if (player->controls.dash) { + player->controls.dash_in_air = false; + player->movement.x = player->x_direction * player->velocity * 2; + state = PLAYER_STATE_DASH; + } + + if (!(player->controls.walk_left) && !(player->controls.walk_right)) { + state = PLAYER_STATE_IDLE; } return update_state(player, state); @@ -118,12 +156,18 @@ State *dash_state(StateMachine *sm, Player *player) { bool reset = false; uint32_t state = PLAYER_STATE_DASH; - player->movement.x += player->x_direction * 3; + player->movement.x += player->x_direction * 20; if (player->animations[PLAYER_STATE_DASH].finished) { - player->movement.x = 0; - reset = true; - state = PLAYER_STATE_IDLE; + if (player->controls.dash_in_air) { + player->movement.y = player->velocity * 6; + state = PLAYER_STATE_FALL; + } else { + player->movement.x = 0; + state = PLAYER_STATE_IDLE; + } + + reset = true; } if (reset) { @@ -132,3 +176,45 @@ State *dash_state(StateMachine *sm, Player *player) { 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->velocity * 0.5; + + if (player->controls.dash) { + player->controls.dash_in_air = true; + player->movement.x = player->x_direction * player->velocity * 2; + player->movement.y = player->velocity * 0.5; + reset = true; + state = PLAYER_STATE_DASH; + } else if (player->animations[PLAYER_STATE_JUMP].finished) { + player->movement.y = player->velocity * 6; + reset = true; + state = PLAYER_STATE_FALL; + } + + 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) { + player->movement.y = 0; + reset = true; + state = PLAYER_STATE_IDLE; + } + + if (reset) { + ap_reset(&(player->animations[PLAYER_STATE_FALL])); + } + + return update_state(player, state); +} diff --git a/player.h b/player.h index 25df80c..3cf475a 100644 --- a/player.h +++ b/player.h @@ -12,6 +12,8 @@ enum player_states { PLAYER_STATE_IDLE, PLAYER_STATE_WALK, PLAYER_STATE_DASH, + PLAYER_STATE_JUMP, + PLAYER_STATE_FALL, COUNT_PLAYER_STATES, }; @@ -23,9 +25,17 @@ enum player_direction { PLAYER_DIRECTION_DOWN = 1, }; -typedef struct player_event_data PlayerEventData; -struct player_event_data { - const SDL_Event *event; +typedef struct player_control PlayerControl; +struct player_control { + bool walk_left; + bool walk_right; + bool space_last; + bool space_pressed; + bool jump; + bool lctrl_last; + bool lctrl_pressed; + bool dash; + bool dash_in_air; }; typedef struct movement Movement; @@ -38,13 +48,14 @@ typedef struct player Player; struct player { uint32_t current_state; uint32_t velocity; + int32_t base_y; int32_t x_direction; Movement movement; SDL_Rect position; - PlayerEventData event_data; StateMachine state_machine; State states[COUNT_PLAYER_STATES]; AnimPlayer animations[COUNT_PLAYER_STATES]; + PlayerControl controls; }; void player_init (Player *player, SDL_Renderer *renderer, SDL_Rect position);