201 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			6.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 *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);
 | |
| }
 |