From d1870e7a1950c3a6309fd9881b128d20adec4a6a Mon Sep 17 00:00:00 2001 From: Sara Date: Fri, 24 Nov 2023 16:22:59 +0100 Subject: [PATCH] feat(game): added player --- game/src/Player.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ game/src/Player.h | 93 ++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 game/src/Player.c create mode 100644 game/src/Player.h diff --git a/game/src/Player.c b/game/src/Player.c new file mode 100644 index 0000000..08ba0ff --- /dev/null +++ b/game/src/Player.c @@ -0,0 +1,151 @@ +#include "Player.h" +#include "debug.h" +#include "game_world.h" +#include "input_axis.h" + +#define WALK_SPEED_H 1.f +#define WALK_SPEED_V 0.75f + +static inline +void Internal_PlayerInitInput(Player* self) { + playerinput_add(self->playerInput, CompositeAxis1D_as_InputAxis(compositeaxis1d_new( + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_A)), + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_D)), + InputEvent_Float)), (InputDelegateFn)PlayerHorizontalInput); + playerinput_add(self->playerInput, CompositeAxis1D_as_InputAxis(compositeaxis1d_new( + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_S)), + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_W)), + InputEvent_Float)), (InputDelegateFn)PlayerVerticalInput); + playerinput_add(self->playerInput, KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_J)), (InputDelegateFn)PlayerAttackInput); +} + +Player* MakePlayer() { + Player* self = malloc(sizeof(Player)); + ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for new Player instance"); + + *self = (Player) { + .transform = IdentityTransform, + .playerInput = playerinput_new(self, -1), + .moveInput = ZeroVector, + .attackInput = 0, + .sprite = sprite_new_empty(), + .idle = NULL, + .walk = NULL, + .jab_a = NULL, + .jab_b = NULL, + .animationStateMachine = NULL, + }; + sprite_set_origin(self->sprite, MakeVector(0.45f, 1.f)); + self->idle = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Idle.png", IVectorFrom(522)), 1.5f); + self->walk = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Walk.png", IVectorFrom(522)), 5.f); + self->jab_a = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Jab_A.png", IVectorFrom(522)), 10.f); + self->jab_b = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Jab_B.png", IVectorFrom(522)), 10.f); + self->animationStateMachine = state_machine_init(self, PlayerIdle()); + return self; +} + +Player* SpawnPlayer(Vector location) { + Player* self = MakePlayer(); + self->transform.position = location; + game_world_add_entity(Player_as_BehaviourEntity(self)); + Internal_PlayerInitInput(self); + return self; +} + +void DestroyPlayer(Player* self) { + playerinput_drop(self->playerInput); + animation_sprite_destroy(self->idle); + animation_sprite_destroy(self->walk); + state_machine_destroy(self->animationStateMachine); +} + +void PlayerHorizontalInput(Player* self, InputEvent value) { + self->moveInput.x = value.as_float * WALK_SPEED_H; +} + +void PlayerVerticalInput(Player* self, InputEvent value) { + self->moveInput.y = -value.as_float * WALK_SPEED_V; +} + +void PlayerAttackInput(Player* self, InputEvent value) { + if(value.as_bool) + self->attackInput = 1; +} + +void PlayerStart(Player* self) {} + +void PlayerUpdate(Player* self, float deltaTime) { + state_machine_update(self->animationStateMachine, deltaTime); +} + +void PlayerDraw(Player* self) { + animation_sprite_draw(self->currentAnimation, &self->transform); +} + +void PlayerAnimationExit(Player* self) {} + +void PlayerIdleEnter(Player* self) { + self->currentAnimation = self->idle; + animation_sprite_play_from(self->currentAnimation, 0.f); +} + +const State* PlayerIdleUpdate(Player* self, float deltaTime) { + if(!veqf(self->moveInput, ZeroVector)) + return PlayerWalk(); + if(self->attackInput) + return PlayerJabA(); + + return PlayerIdle(); +} + +void PlayerWalk_Enter(Player* self) { + self->currentAnimation = self->walk; + animation_sprite_play_from(self->currentAnimation, 0.f); +} + +const State* PlayerWalk_Update(Player* self, float deltaTime) { + if(veqf(self->moveInput, ZeroVector)) + return PlayerIdle(); + if(self->attackInput) + return PlayerJabA(); + + if(self->moveInput.x > 0.f) + sprite_flip_horizontal(self->sprite, 0); + if(self->moveInput.x < -0.1f) + sprite_flip_horizontal(self->sprite, 1); + + self->transform.position = vaddf(self->transform.position, vmulff(self->moveInput, deltaTime)); + + return PlayerWalk(); +} + +void PlayerJabA_Enter(Player* self) { + self->attackInput = 0; + self->currentAnimation = self->jab_a; + animation_sprite_play_from(self->currentAnimation, 0.f); +} + +const State* PlayerJabA_Update(Player* self, float deltaTime) { + if(animation_sprite_get_time_normalized(self->currentAnimation) >= 2.0f) { + if(self->attackInput) + return PlayerJabB(); + else + return PlayerIdle(); + } + + return PlayerJabA(); +} + +void PlayerJabB_Enter(Player* self) { + self->attackInput = 0; + self->currentAnimation = self->jab_b; + animation_sprite_play_from(self->currentAnimation, 0.f); +} + +const State* PlayerJabB_Update(Player* self, float deltaTime) { + if(animation_sprite_get_time_normalized(self->currentAnimation) >= 2.0f) { + return PlayerIdle(); + } + + return PlayerJabB(); +} diff --git a/game/src/Player.h b/game/src/Player.h new file mode 100644 index 0000000..3c8f754 --- /dev/null +++ b/game/src/Player.h @@ -0,0 +1,93 @@ +#ifndef FIGHT_PLAYER_H +#define FIGHT_PLAYER_H + +#include "state_machine.h" +#include "state.h" +#include "behaviour_entity.h" +#include "animation_sprite.h" +#include "input.h" +#include "vmath.h" +#include "transform.h" +#include "player_input.h" + +typedef struct Player { + Transform transform; + + PlayerInput* playerInput; + + Vector moveInput; + int attackInput; + + Sprite* sprite; + + AnimationSprite* idle; + AnimationSprite* walk; + AnimationSprite* jab_a; + AnimationSprite* jab_b; + + StateMachine* animationStateMachine; + + AnimationSprite* currentAnimation; +} Player; + +Player* MakePlayer(); +Player* SpawnPlayer(Vector location); +void DestroyPlayer(Player* self); + +void PlayerHorizontalInput(Player* self, InputEvent value); +void PlayerVerticalInput(Player* self, InputEvent value); +void PlayerAttackInput(Player* self, InputEvent value); + +void PlayerStart(Player* self); +void PlayerUpdate(Player* self, float deltaTime); +void PlayerDraw(Player* self); + +impl_Drop_for(Player, + DestroyPlayer +) + +impl_BehaviourEntity_for(Player, + PlayerStart, + PlayerUpdate, + PlayerDraw +) + +void PlayerAnimationExit(Player* self); + +void PlayerIdleEnter(Player* self); +const State* PlayerIdleUpdate(Player* self, float deltaTime); + +DefineState(PlayerIdle, Player, + PlayerIdleEnter, + PlayerIdleUpdate, + PlayerAnimationExit +) + +void PlayerWalk_Enter(Player* self); +const State* PlayerWalk_Update(Player* self, float deltaTime); + +DefineState(PlayerWalk, Player, + PlayerWalk_Enter, + PlayerWalk_Update, + PlayerAnimationExit +) + +void PlayerJabA_Enter(Player* self); +const State* PlayerJabA_Update(Player* self, float deltaTime); + +DefineState(PlayerJabA, Player, + PlayerJabA_Enter, + PlayerJabA_Update, + PlayerAnimationExit +) + +void PlayerJabB_Enter(Player* self); +const State* PlayerJabB_Update(Player* self, float deltaTime); + +DefineState(PlayerJabB, Player, + PlayerJabB_Enter, + PlayerJabB_Update, + PlayerAnimationExit +) + +#endif // !FIGHT_PLAYER_H