feat: implemented slide attack with QCF+H

This commit is contained in:
Sara 2024-01-18 18:30:41 +01:00
parent 2f26672fc4
commit 3c15d808b5
4 changed files with 123 additions and 8 deletions

View file

@ -6,8 +6,10 @@
#include "PlayerStates.h"
#include "Layers.h"
#include "program.h"
const Vector PLAYER_SPEED = { 1.0f, 0.50f };
static const float PLAYER_INPUT_RATE = 1.f/15.f;
START_REFLECT(Player)
REFLECT_TYPECLASS(Player, Drop)
@ -86,8 +88,12 @@ Player* MakePlayer() {
.jab_b = NULL,
.kick_a = NULL,
.air_heavy = NULL,
.slide = NULL,
.animationStateMachine = NULL,
.pushInputTimer = 0.f,
.inputLog = list_from_type(PlayerInputFrame),
};
self->rigidbody = rigidbody_make(Player_as_PhysicsEntity(self));
@ -113,6 +119,7 @@ Player* MakePlayer() {
self->jab_b = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Jab_B.png", IVectorFrom(512)), 10.f, LoopMode_Stop);
self->kick_a = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Kick_A.png", IVectorFrom(512)), 12.f, LoopMode_Stop);
self->air_heavy = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Air_Heavy.png", IVectorFrom(512)), 10.f, LoopMode_Stop);
self->slide = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Slide.png", IVectorFrom(512)), 1.f, LoopMode_Loop);
self->animationStateMachine = state_machine_init(self, PlayerIdle());
@ -150,6 +157,24 @@ void PlayerStart(Player* self) {
animation_sprite_play_from(self->currentAnimation, 0.0f);
}
static
void PlayerPushInput(Player* self) {
PlayerInputFrame state = {
.time = game_time(),
.direction = self->moveInput,
.light = self->attackInput == 1,
.heavy = self->attackInput == 2,
.jump = self->jumpInput,
.facing = self->facing,
};
list_add(&self->inputLog, &state);
if(self->inputLog.len >= 5)
list_erase(&self->inputLog, 0);
LOG_INFO("%f %f, L:%x, H:%x, J:%x",
state.direction.x, state.direction.y,
state.light, state.heavy, state.jump);
}
void PlayerUpdate(Player* self, float deltaTime) {
state_machine_update(self->animationStateMachine, deltaTime);
self->height += self->verticalVelocity * deltaTime;
@ -165,24 +190,33 @@ void PlayerDraw(Player* self) {
void PlayerHorizontalInput(Player* self, InputEvent value) {
self->moveInput.x = value.as_float;
PlayerPushInput(self);
}
void PlayerVerticalInput(Player* self, InputEvent value) {
self->moveInput.y = -value.as_float;
PlayerPushInput(self);
}
void PlayerJumpInput(Player* self, InputEvent value) {
self->jumpInput = value.as_bool;
if(value.as_bool) {
self->jumpInput = value.as_bool;
PlayerPushInput(self);
}
}
void PlayerLightAttackInput(Player* self, InputEvent value) {
if(value.as_bool)
if(value.as_bool) {
self->attackInput = 1;
PlayerPushInput(self);
}
}
void PlayerHeavyAttackInput(Player* self, InputEvent value) {
if(value.as_bool)
if(value.as_bool) {
self->attackInput = 2;
PlayerPushInput(self);
}
}
void PlayerOnCollision(Player* self, Collision collision) {}
@ -195,3 +229,18 @@ Transform* PlayerGetTransform(Player* self) {
RigidBody* PlayerGetRigidBody(Player* self) {
return self->rigidbody;
}
PlayerInputFrame* PlayerInputHistory(Player* self) {
return (PlayerInputFrame*)self->inputLog.data;
}
int PlayerInputIsQuarterCircleForward(Player* self) {
PlayerInputFrame* history = PlayerInputHistory(self);
const size_t last = self->inputLog.len-1;
const float forward = history[last-3].facing;
if(game_time() - history[last-2].time > 0.225f)
return 0;
return veqf(history[last-3].direction, MakeVector(0.f, 1.f))
&& veqf(history[last-2].direction, MakeVector(forward, 1.f))
&& veqf(history[last-1].direction, MakeVector(forward, 0.f));
}

View file

@ -14,6 +14,15 @@
extern const Vector PLAYER_SPEED;
typedef struct PlayerInputFrame {
float time;
Vector direction;
int light;
int heavy;
int jump;
float facing;
} PlayerInputFrame;
typedef struct Player {
Transform transform;
float height;
@ -42,10 +51,15 @@ typedef struct Player {
AnimationSprite* jab_b;
AnimationSprite* kick_a;
AnimationSprite* air_heavy;
AnimationSprite* slide;
StateMachine* animationStateMachine;
AnimationSprite* currentAnimation;
float pushInputTimer;
List inputLog;
PlayerInputFrame nextInputFrame;
} Player;
Player* MakePlayer();
@ -68,6 +82,9 @@ void PlayerOnOverlap(Player* self, Collider* other);
Transform* PlayerGetTransform(Player* self);
RigidBody* PlayerGetRigidBody(Player* self);
PlayerInputFrame* PlayerInputHistory(Player* self);
int PlayerInputIsQuarterCircleForward(Player* self);
static long PlayerGetDepth(Player* self) { return (int)(-10-self->transform.position.y * 1000); }

View file

@ -18,6 +18,22 @@ void PlayerAnimationExit(Player* self) {
self->attackInput = 0;
}
static
const State* PlayerTryStartNewChain(Player* self) {
if(self->attackInput == 1) {
return PlayerJabA();
}
if(self->attackInput == 2) {
if(self->height > 0.f)
return PlayerAirHeavy();
else if(PlayerInputIsQuarterCircleForward(self))
return PlayerSlide();
else
return PlayerKickA();
}
return NULL;
}
void PlayerIdleEnter(Player* self) {
self->currentAnimation = self->idle;
rigidbody_set_velocity(self->rigidbody, ZeroVector);
@ -46,10 +62,9 @@ const State* PlayerWalk_Update(Player* self, float deltaTime) {
if(veqf(self->moveInput, ZeroVector))
return PlayerIdle();
if(self->attackInput == 1)
return PlayerJabA();
if(self->attackInput == 2)
return PlayerKickA();
const State* attackState = PlayerTryStartNewChain(self);
if(attackState)
return attackState;
if(self->jumpInput)
return PlayerJump();
InternalSpriteFlipWithMovement(self);
@ -148,7 +163,7 @@ const State* PlayerKickA_Update(Player* self, float deltaTime) {
};
const float ntime = animation_sprite_get_time_normalized(self->currentAnimation);
const size_t frame = sprite_get_tile(self->sprite);
if(frame >= 2 && frame <= 3) {
if(frame >= 3 && frame <= 4) {
PlayerHurtbox(self, damage, MakeVector(0.16f, 0.06f), MakeVector(0.33f, -0.4f));
}
if(!veqf(self->moveInput, ZeroVector) && ntime > 1.05f)
@ -158,6 +173,31 @@ const State* PlayerKickA_Update(Player* self, float deltaTime) {
return PlayerKickA();
}
void PlayerSlide_Enter(Player* self) {
PlayerAttackEnter(self);
self->currentAnimation = self->slide;
// adjust for the downward motion of the quartercircle
Transform* trans = rigidbody_get_transform(self->rigidbody);
trans->position.y -= 0.03f;
animation_sprite_play_from(self->currentAnimation, 0.f);
}
const State* PlayerSlide_Update(Player* self, float deltaTime) {
static const DamageEventData damage = {
.damageAmount = 3,
.knockdown = 1,
.stun = 1.f,
.knockback = 0.3f,
};
const float time = animation_sprite_get_time(self->currentAnimation);
rigidbody_set_velocity(self->rigidbody, MakeVector(self->facing * 3.f, 0.f));
if(time > 0.34f)
return PlayerIdle();
if(time > 0.1f)
PlayerHurtbox(self, damage, MakeVector(0.16, 0.06f), MakeVector(0.33f, -0.03f));
return PlayerSlide();
}
void PlayerJump_Enter(Player* self) {
if(self->jumpInput) {
self->currentAnimation = self->jump;

View file

@ -54,6 +54,15 @@ DefineState(PlayerKickA, Player,
PlayerAnimationExit
)
extern void PlayerSlide_Enter(Player* self);
extern const State* PlayerSlide_Update(Player* self, float deltaTime);
DefineState(PlayerSlide, Player,
PlayerSlide_Enter,
PlayerSlide_Update,
PlayerAnimationExit
)
extern void PlayerJump_Enter(Player *self);
extern const State* PlayerJump_Update(Player* self, float deltaTime);