feat: implemented slide attack with QCF+H
This commit is contained in:
parent
2f26672fc4
commit
3c15d808b5
|
@ -6,8 +6,10 @@
|
||||||
|
|
||||||
#include "PlayerStates.h"
|
#include "PlayerStates.h"
|
||||||
#include "Layers.h"
|
#include "Layers.h"
|
||||||
|
#include "program.h"
|
||||||
|
|
||||||
const Vector PLAYER_SPEED = { 1.0f, 0.50f };
|
const Vector PLAYER_SPEED = { 1.0f, 0.50f };
|
||||||
|
static const float PLAYER_INPUT_RATE = 1.f/15.f;
|
||||||
|
|
||||||
START_REFLECT(Player)
|
START_REFLECT(Player)
|
||||||
REFLECT_TYPECLASS(Player, Drop)
|
REFLECT_TYPECLASS(Player, Drop)
|
||||||
|
@ -86,8 +88,12 @@ Player* MakePlayer() {
|
||||||
.jab_b = NULL,
|
.jab_b = NULL,
|
||||||
.kick_a = NULL,
|
.kick_a = NULL,
|
||||||
.air_heavy = NULL,
|
.air_heavy = NULL,
|
||||||
|
.slide = NULL,
|
||||||
|
|
||||||
.animationStateMachine = NULL,
|
.animationStateMachine = NULL,
|
||||||
|
|
||||||
|
.pushInputTimer = 0.f,
|
||||||
|
.inputLog = list_from_type(PlayerInputFrame),
|
||||||
};
|
};
|
||||||
|
|
||||||
self->rigidbody = rigidbody_make(Player_as_PhysicsEntity(self));
|
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->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->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->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());
|
self->animationStateMachine = state_machine_init(self, PlayerIdle());
|
||||||
|
|
||||||
|
@ -150,6 +157,24 @@ void PlayerStart(Player* self) {
|
||||||
animation_sprite_play_from(self->currentAnimation, 0.0f);
|
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) {
|
void PlayerUpdate(Player* self, float deltaTime) {
|
||||||
state_machine_update(self->animationStateMachine, deltaTime);
|
state_machine_update(self->animationStateMachine, deltaTime);
|
||||||
self->height += self->verticalVelocity * deltaTime;
|
self->height += self->verticalVelocity * deltaTime;
|
||||||
|
@ -165,24 +190,33 @@ void PlayerDraw(Player* self) {
|
||||||
|
|
||||||
void PlayerHorizontalInput(Player* self, InputEvent value) {
|
void PlayerHorizontalInput(Player* self, InputEvent value) {
|
||||||
self->moveInput.x = value.as_float;
|
self->moveInput.x = value.as_float;
|
||||||
|
PlayerPushInput(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerVerticalInput(Player* self, InputEvent value) {
|
void PlayerVerticalInput(Player* self, InputEvent value) {
|
||||||
self->moveInput.y = -value.as_float;
|
self->moveInput.y = -value.as_float;
|
||||||
|
PlayerPushInput(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerJumpInput(Player* self, InputEvent value) {
|
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) {
|
void PlayerLightAttackInput(Player* self, InputEvent value) {
|
||||||
if(value.as_bool)
|
if(value.as_bool) {
|
||||||
self->attackInput = 1;
|
self->attackInput = 1;
|
||||||
|
PlayerPushInput(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerHeavyAttackInput(Player* self, InputEvent value) {
|
void PlayerHeavyAttackInput(Player* self, InputEvent value) {
|
||||||
if(value.as_bool)
|
if(value.as_bool) {
|
||||||
self->attackInput = 2;
|
self->attackInput = 2;
|
||||||
|
PlayerPushInput(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerOnCollision(Player* self, Collision collision) {}
|
void PlayerOnCollision(Player* self, Collision collision) {}
|
||||||
|
@ -195,3 +229,18 @@ Transform* PlayerGetTransform(Player* self) {
|
||||||
RigidBody* PlayerGetRigidBody(Player* self) {
|
RigidBody* PlayerGetRigidBody(Player* self) {
|
||||||
return self->rigidbody;
|
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));
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,15 @@
|
||||||
|
|
||||||
extern const Vector PLAYER_SPEED;
|
extern const Vector PLAYER_SPEED;
|
||||||
|
|
||||||
|
typedef struct PlayerInputFrame {
|
||||||
|
float time;
|
||||||
|
Vector direction;
|
||||||
|
int light;
|
||||||
|
int heavy;
|
||||||
|
int jump;
|
||||||
|
float facing;
|
||||||
|
} PlayerInputFrame;
|
||||||
|
|
||||||
typedef struct Player {
|
typedef struct Player {
|
||||||
Transform transform;
|
Transform transform;
|
||||||
float height;
|
float height;
|
||||||
|
@ -42,10 +51,15 @@ typedef struct Player {
|
||||||
AnimationSprite* jab_b;
|
AnimationSprite* jab_b;
|
||||||
AnimationSprite* kick_a;
|
AnimationSprite* kick_a;
|
||||||
AnimationSprite* air_heavy;
|
AnimationSprite* air_heavy;
|
||||||
|
AnimationSprite* slide;
|
||||||
|
|
||||||
StateMachine* animationStateMachine;
|
StateMachine* animationStateMachine;
|
||||||
|
|
||||||
AnimationSprite* currentAnimation;
|
AnimationSprite* currentAnimation;
|
||||||
|
|
||||||
|
float pushInputTimer;
|
||||||
|
List inputLog;
|
||||||
|
PlayerInputFrame nextInputFrame;
|
||||||
} Player;
|
} Player;
|
||||||
|
|
||||||
Player* MakePlayer();
|
Player* MakePlayer();
|
||||||
|
@ -68,6 +82,9 @@ void PlayerOnOverlap(Player* self, Collider* other);
|
||||||
Transform* PlayerGetTransform(Player* self);
|
Transform* PlayerGetTransform(Player* self);
|
||||||
RigidBody* PlayerGetRigidBody(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); }
|
static long PlayerGetDepth(Player* self) { return (int)(-10-self->transform.position.y * 1000); }
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,22 @@ void PlayerAnimationExit(Player* self) {
|
||||||
self->attackInput = 0;
|
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) {
|
void PlayerIdleEnter(Player* self) {
|
||||||
self->currentAnimation = self->idle;
|
self->currentAnimation = self->idle;
|
||||||
rigidbody_set_velocity(self->rigidbody, ZeroVector);
|
rigidbody_set_velocity(self->rigidbody, ZeroVector);
|
||||||
|
@ -46,10 +62,9 @@ const State* PlayerWalk_Update(Player* self, float deltaTime) {
|
||||||
|
|
||||||
if(veqf(self->moveInput, ZeroVector))
|
if(veqf(self->moveInput, ZeroVector))
|
||||||
return PlayerIdle();
|
return PlayerIdle();
|
||||||
if(self->attackInput == 1)
|
const State* attackState = PlayerTryStartNewChain(self);
|
||||||
return PlayerJabA();
|
if(attackState)
|
||||||
if(self->attackInput == 2)
|
return attackState;
|
||||||
return PlayerKickA();
|
|
||||||
if(self->jumpInput)
|
if(self->jumpInput)
|
||||||
return PlayerJump();
|
return PlayerJump();
|
||||||
InternalSpriteFlipWithMovement(self);
|
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 float ntime = animation_sprite_get_time_normalized(self->currentAnimation);
|
||||||
const size_t frame = sprite_get_tile(self->sprite);
|
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));
|
PlayerHurtbox(self, damage, MakeVector(0.16f, 0.06f), MakeVector(0.33f, -0.4f));
|
||||||
}
|
}
|
||||||
if(!veqf(self->moveInput, ZeroVector) && ntime > 1.05f)
|
if(!veqf(self->moveInput, ZeroVector) && ntime > 1.05f)
|
||||||
|
@ -158,6 +173,31 @@ const State* PlayerKickA_Update(Player* self, float deltaTime) {
|
||||||
return PlayerKickA();
|
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) {
|
void PlayerJump_Enter(Player* self) {
|
||||||
if(self->jumpInput) {
|
if(self->jumpInput) {
|
||||||
self->currentAnimation = self->jump;
|
self->currentAnimation = self->jump;
|
||||||
|
|
|
@ -54,6 +54,15 @@ DefineState(PlayerKickA, Player,
|
||||||
PlayerAnimationExit
|
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 void PlayerJump_Enter(Player *self);
|
||||||
extern const State* PlayerJump_Update(Player* self, float deltaTime);
|
extern const State* PlayerJump_Update(Player* self, float deltaTime);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue