Add player jump and fall states
This commit is contained in:
		
							
								
								
									
										174
									
								
								player.c
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								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 <SDL2/SDL_events.h> | ||||
| #include <SDL2/SDL_keyboard.h> | ||||
| #include <SDL2/SDL_scancode.h> | ||||
| #include <SDL2/SDL_render.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| #define SPRITE_WIDTH 100 | ||||
| #define SPRITE_HEIGHT 64 | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	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; | ||||
| 	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; | ||||
| 					break; | ||||
| 				case SDLK_RIGHT: | ||||
| 					player->movement.x  = PLAYER_DIRECTION_RIGHT * player->velocity; | ||||
| 					player->x_direction = PLAYER_DIRECTION_RIGHT; | ||||
| 	} else if (player->controls.walk_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; | ||||
| 	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; | ||||
| 					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.walk_left) && !(player->controls.walk_right)) { | ||||
| 		state = PLAYER_STATE_IDLE; | ||||
| 	} | ||||
|  | ||||
| 	return update_state(player, state); | ||||
| @@ -118,17 +156,65 @@ 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) { | ||||
| 		if (player->controls.dash_in_air) { | ||||
| 			player->movement.y = player->velocity * 6; | ||||
| 			state              = PLAYER_STATE_FALL; | ||||
| 		} else { | ||||
| 			player->movement.x = 0; | ||||
| 		reset              = true; | ||||
| 			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->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); | ||||
| } | ||||
|   | ||||
							
								
								
									
										19
									
								
								player.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user