feat: documentation pass
This commit is contained in:
parent
526ff0b0c6
commit
73104a02c4
|
@ -60,19 +60,20 @@ Enemy* MakeEnemy() {
|
|||
};
|
||||
|
||||
self->rigidbody = rigidbody_make(Enemy_as_PhysicsEntity(self));
|
||||
// collider used for physics and movement
|
||||
self->collider = collider_new(Enemy_as_PhysicsEntity(self), shape_new_square(MakeVector(0.2f, 0.05f)), 0,
|
||||
PHYSICS_LAYER_DEFAULT, PHYSICS_LAYER_DEFAULT);
|
||||
// hitbox used to detect damage
|
||||
self->hitbox = collider_new(Enemy_as_PhysicsEntity(self), shape_new((Vector[]){
|
||||
MakeVector(-0.1f, -0.9f),
|
||||
MakeVector( 0.1f, -0.9f),
|
||||
MakeVector( 0.1f, 0.0f),
|
||||
MakeVector(-0.1f, 0.0f),
|
||||
}, 4), 1, PHYSICS_LAYER_COMBAT, 0x0);
|
||||
PhysicsEntity pe = Enemy_as_PhysicsEntity(self);
|
||||
LOG_INFO("enemy instantiated mirroring as: %s", pe.mirror->get_typestring(pe.data));
|
||||
}, 4), 1, PHYSICS_LAYER_COMBAT, 0x0); // does not query
|
||||
|
||||
sprite_set_origin(self->sprite, MakeVector(0.45f, 0.925f));
|
||||
|
||||
// load and configure animations
|
||||
self->idleAnim = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Idle.png", IVectorFrom(512)), 1.5f, LoopMode_Loop);
|
||||
self->walkAnim = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Walk.png", IVectorFrom(512)), 1.5f, LoopMode_Loop);
|
||||
self->hurtAnim = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Hurt.png", IVectorFrom(512)), 5.f, LoopMode_Stop);
|
||||
|
@ -83,7 +84,9 @@ Enemy* MakeEnemy() {
|
|||
Enemy* SpawnEnemy(Vector location, const State* entryState) {
|
||||
Enemy* self = MakeEnemy();
|
||||
self->behaviour = state_machine_init(self, entryState);
|
||||
// spawn at location
|
||||
rigidbody_get_transform(self->rigidbody)->position = location;
|
||||
// register into game world
|
||||
game_world_add_entity(Enemy_as_BehaviourEntity(self));
|
||||
physics_world_add_entity(Enemy_as_PhysicsEntity(self));
|
||||
return self;
|
||||
|
@ -102,6 +105,7 @@ void EnemyDraw(Enemy* self) {
|
|||
|
||||
void EnemyDestroy(Enemy* self) {
|
||||
state_machine_destroy(self->behaviour);
|
||||
// unregister *before* deallocating physics components
|
||||
physics_world_remove_entity(Enemy_as_PhysicsEntity(self));
|
||||
collider_destroy(self->collider);
|
||||
rigidbody_destroy(self->rigidbody);
|
||||
|
@ -122,20 +126,26 @@ RigidBody* EnemyGetRigidBody(Enemy* self) {
|
|||
}
|
||||
|
||||
int EnemyDamage(Enemy* self, DamageEventData* data) {
|
||||
// being stunned gives iframes
|
||||
if(self->stun_time > game_time())
|
||||
return 0;
|
||||
// subtract damage
|
||||
self->health -= data->damageAmount;
|
||||
LOG_INFO("Damage received");
|
||||
// die if health drops below zero
|
||||
if(self->health <= 0) {
|
||||
// TODO: swap to death state instead
|
||||
game_world_destroy_entity(Enemy_as_BehaviourEntity(self));
|
||||
return 1;
|
||||
} else {
|
||||
// store the most recent damage event
|
||||
self->last_damage = *data;
|
||||
const float stun_time = game_time() + data->stun;
|
||||
if(stun_time > self->stun_time)
|
||||
self->stun_time = stun_time;
|
||||
// get stunned
|
||||
self->stun_time = game_time() + data->stun;
|
||||
// calculate which direction the damage is coming from
|
||||
float direction = ((data->origin.x - self->transform.position.x) > 0) * 2 - 1;
|
||||
// face the direction damage is coming from
|
||||
self->facing = direction;
|
||||
// add knockback according to damage data in the calculated direction
|
||||
rigidbody_add_impulse(self->rigidbody, MakeVector(-direction * data->knockback, 0), 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,8 +11,10 @@ void EnemyIdle_Enter(Enemy* self) {
|
|||
}
|
||||
|
||||
const State* EnemyIdle_Update(Enemy* self, float deltaTime) {
|
||||
// apply drag
|
||||
Vector velocity = vmovetowardsf(rigidbody_get_velocity(self->rigidbody), ZeroVector, 0.1f);
|
||||
rigidbody_set_velocity(self->rigidbody, velocity);
|
||||
// state transitions
|
||||
if(self->stun_time >= game_time())
|
||||
return EnemyHurt();
|
||||
return EnemyIdle();
|
||||
|
@ -34,10 +36,11 @@ void EnemyHurt_Enter(Enemy* self) {
|
|||
|
||||
const State* EnemyHurt_Update(Enemy* self, float deltaTime) {
|
||||
const float time = animation_sprite_get_time(self->currentAnimation);
|
||||
// apply drag
|
||||
Vector velocity = vmovetowardsf(rigidbody_get_velocity(self->rigidbody), ZeroVector, 0.1f);
|
||||
rigidbody_set_velocity(self->rigidbody, velocity);
|
||||
// state transitions
|
||||
if(self->stun_time < game_time())
|
||||
return EnemyIdle();
|
||||
else
|
||||
return EnemyHurt();
|
||||
}
|
||||
|
|
|
@ -97,21 +97,24 @@ Player* MakePlayer() {
|
|||
};
|
||||
|
||||
self->rigidbody = rigidbody_make(Player_as_PhysicsEntity(self));
|
||||
// physics collider used for movement
|
||||
self->physicsCollider = collider_new(Player_as_PhysicsEntity(self), shape_new((Vector[]){
|
||||
MakeVector(-0.2f, -0.065f),
|
||||
MakeVector( 0.2f, -0.065f),
|
||||
MakeVector( 0.2f, 0.065f),
|
||||
MakeVector(-0.2f, 0.065f)
|
||||
}, 4), 0, PHYSICS_LAYER_CHARACTERS, PHYSICS_LAYER_DEFAULT);
|
||||
// hitbox is used for combat only
|
||||
self->hitbox = collider_new(Player_as_PhysicsEntity(self), shape_new((Vector[]){
|
||||
MakeVector(-0.1f, -0.9f),
|
||||
MakeVector( 0.1f, -0.9f),
|
||||
MakeVector( 0.1f, 0.00f),
|
||||
MakeVector(-0.1f, 0.00f)
|
||||
}, 4), 1, PHYSICS_LAYER_COMBAT, 0x0);
|
||||
}, 4), 1, PHYSICS_LAYER_COMBAT, 0x0); // empty mask and overlap means this does not detect collisions itself
|
||||
|
||||
sprite_set_origin(self->sprite, MakeVector(0.45f, 0.925f));
|
||||
|
||||
// load and configure animations
|
||||
self->idle = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Idle.png", IVectorFrom(512)), 1.5f, LoopMode_Loop);
|
||||
self->walk = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Walk.png", IVectorFrom(512)), 5.f, LoopMode_Loop);
|
||||
self->jump = animation_sprite_new(self->sprite, spritesheet_load("assets/Player_Jumping.png", IVectorFrom(512)), 1.f, LoopMode_Stop);
|
||||
|
@ -138,16 +141,22 @@ Player* SpawnPlayer(Vector location) {
|
|||
}
|
||||
|
||||
void DestroyPlayer(Player* self) {
|
||||
// deregister and free physics components
|
||||
physics_world_remove_entity(Player_as_PhysicsEntity(self));
|
||||
collider_destroy(self->physicsCollider);
|
||||
rigidbody_destroy(self->rigidbody);
|
||||
|
||||
playerinput_drop(self->playerInput);
|
||||
|
||||
// erase animations
|
||||
animation_sprite_destroy(self->idle);
|
||||
animation_sprite_destroy(self->walk);
|
||||
animation_sprite_destroy(self->jump);
|
||||
animation_sprite_destroy(self->jab_a);
|
||||
animation_sprite_destroy(self->jab_b);
|
||||
animation_sprite_destroy(self->kick_a);
|
||||
animation_sprite_destroy(self->air_heavy);
|
||||
animation_sprite_destroy(self->slide);
|
||||
sprite_destroy(self->sprite);
|
||||
|
||||
state_machine_destroy(self->animationStateMachine);
|
||||
|
@ -159,6 +168,7 @@ void PlayerStart(Player* self) {
|
|||
|
||||
static
|
||||
void PlayerPushInput(Player* self) {
|
||||
// the current input state
|
||||
PlayerInputFrame state = {
|
||||
.time = game_time(),
|
||||
.direction = self->moveInput,
|
||||
|
@ -167,22 +177,28 @@ void PlayerPushInput(Player* self) {
|
|||
.jump = self->jumpInput,
|
||||
.facing = self->facing,
|
||||
};
|
||||
// push onto the end of the log
|
||||
list_add(&self->inputLog, &state);
|
||||
// erase oldest input from the log
|
||||
if(self->inputLog.len >= 5)
|
||||
list_erase(&self->inputLog, 0);
|
||||
// log current input state
|
||||
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) {
|
||||
// update state machine
|
||||
state_machine_update(self->animationStateMachine, deltaTime);
|
||||
// update gravity
|
||||
self->height += self->verticalVelocity * deltaTime;
|
||||
if(self->height <= 0.f)
|
||||
self->height = 0.f;
|
||||
}
|
||||
|
||||
void PlayerDraw(Player* self) {
|
||||
// create a new transform that adjusts the "ground" transform to reflect distance from the ground as well
|
||||
Transform trans = self->transform;
|
||||
trans.position.y -= self->height;
|
||||
animation_sprite_draw(self->currentAnimation, &trans);
|
||||
|
@ -235,11 +251,19 @@ PlayerInputFrame* PlayerInputHistory(Player* self) {
|
|||
}
|
||||
|
||||
int PlayerInputIsQuarterCircleForward(Player* self) {
|
||||
// at least four inputs have to be logged for a valid quartercircle
|
||||
// (three directional, one button, in that order)
|
||||
if(self->inputLog.len < 4)
|
||||
return 0;
|
||||
PlayerInputFrame* history = PlayerInputHistory(self);
|
||||
// the most recent input (assumed to be a button input)
|
||||
const size_t last = self->inputLog.len-1;
|
||||
// the forward direction at the assumed start of the action
|
||||
const float forward = history[last-3].facing;
|
||||
if(game_time() - history[last-2].time > 0.225f)
|
||||
return 0;
|
||||
// check if the three inputs before the most recent input are a quartercircle towards the facing direction at last-3 (three before current)
|
||||
// current (history[last]) is assumed to be a button input
|
||||
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));
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "Damagable.h"
|
||||
#include "Player.h"
|
||||
|
||||
// flip the facing direction of the player based on input
|
||||
// does not do movement
|
||||
static inline
|
||||
void InternalSpriteFlipWithMovement(Player* self) {
|
||||
if(self->moveInput.x > 0.f)
|
||||
|
@ -19,7 +21,7 @@ void PlayerAnimationExit(Player* self) {
|
|||
}
|
||||
|
||||
static
|
||||
const State* PlayerTryStartNewChain(Player* self) {
|
||||
const State* PlayerTryStartNewChain(Player* self, const State* fallback) {
|
||||
if(self->attackInput == 1) {
|
||||
return PlayerJabA();
|
||||
}
|
||||
|
@ -31,7 +33,7 @@ const State* PlayerTryStartNewChain(Player* self) {
|
|||
else
|
||||
return PlayerKickA();
|
||||
}
|
||||
return NULL;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void PlayerIdleEnter(Player* self) {
|
||||
|
@ -43,13 +45,9 @@ void PlayerIdleEnter(Player* self) {
|
|||
const State* PlayerIdleUpdate(Player* self, float deltaTime) {
|
||||
if(!veqf(self->moveInput, ZeroVector))
|
||||
return PlayerWalk();
|
||||
if(self->attackInput == 1)
|
||||
return PlayerJabA();
|
||||
if(self->attackInput == 2)
|
||||
return PlayerKickA();
|
||||
if(self->jumpInput)
|
||||
return PlayerJump();
|
||||
return PlayerIdle();
|
||||
return PlayerTryStartNewChain(self, PlayerIdle());
|
||||
}
|
||||
|
||||
void PlayerWalk_Enter(Player* self) {
|
||||
|
@ -62,13 +60,10 @@ const State* PlayerWalk_Update(Player* self, float deltaTime) {
|
|||
|
||||
if(veqf(self->moveInput, ZeroVector))
|
||||
return PlayerIdle();
|
||||
const State* attackState = PlayerTryStartNewChain(self);
|
||||
if(attackState)
|
||||
return attackState;
|
||||
if(self->jumpInput)
|
||||
return PlayerJump();
|
||||
InternalSpriteFlipWithMovement(self);
|
||||
return PlayerWalk();
|
||||
return PlayerTryStartNewChain(self, PlayerWalk());
|
||||
}
|
||||
|
||||
void PlayerAttackEnter(Player* self) {
|
||||
|
|
Loading…
Reference in a new issue