feat: documentation pass

This commit is contained in:
Sara 2024-01-20 12:34:13 +01:00
parent 526ff0b0c6
commit 73104a02c4
4 changed files with 53 additions and 21 deletions

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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));

View file

@ -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) {