Add guard asserts for attack, Add death animations
This commit is contained in:
parent
44014a8add
commit
9fde0594e1
@ -433,16 +433,14 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
if (*state == FP_EntityTerryState_AttackUp ||
|
||||
*state == FP_EntityTerryState_AttackDown ||
|
||||
*state == FP_EntityTerryState_AttackSide) {
|
||||
DQN_ASSERT(action->sprite.anim);
|
||||
|
||||
// NOTE: Grab timings to narrow down a midpoint of the attack animation
|
||||
const uint32_t GRACE_PERIOD = 33;
|
||||
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
|
||||
DQN_ASSERT(duration_ms >= PHYSICS_STEP);
|
||||
uint64_t midpoint_clock_ms = action->end_at_clock_ms - (duration_ms / 2);
|
||||
uint64_t window_start = midpoint_clock_ms - GRACE_PERIOD;
|
||||
uint64_t window_end = midpoint_clock_ms + GRACE_PERIOD;
|
||||
|
||||
// NOTE: Adding an attack_processed bool to make sure things only fire once
|
||||
if (!entity->attack_processed && game->clock_ms >= window_start && game->clock_ms < window_end) {
|
||||
if (!entity->attack_processed && game->clock_ms >= midpoint_clock_ms) {
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
|
||||
// NOTE: Position the attack box
|
||||
@ -564,6 +562,19 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
case FP_EntitySmoochieState_AttackHeart: {
|
||||
} break;
|
||||
|
||||
case FP_EntitySmoochieState_Death: {
|
||||
if (entering_new_state) {
|
||||
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_death, TELY_AssetFlip_No);
|
||||
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
|
||||
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||
}
|
||||
|
||||
if (action_has_finished) {
|
||||
FP_Game_DeleteEntity(game, entity->handle);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
case FP_EntitySmoochieState_Run: {
|
||||
Dqn_String8 desired_action_name = {};
|
||||
switch (entity->direction) {
|
||||
@ -592,6 +603,10 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
} break;
|
||||
}
|
||||
|
||||
if (entity->is_dying && *state != FP_EntitySmoochieState_Death) {
|
||||
action->next_state = FP_EntitySmoochieState_Death;
|
||||
}
|
||||
|
||||
if (*state == FP_EntitySmoochieState_AttackDown) {
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
// NOTE: Position the attack box
|
||||
@ -644,6 +659,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
} break;
|
||||
|
||||
case FP_EntityClingerState_Attack: {
|
||||
|
||||
uint32_t asset_flip = {};
|
||||
Dqn_String8 desired_action_name = {};
|
||||
switch (entity->direction) {
|
||||
@ -664,7 +680,16 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
} break;
|
||||
|
||||
case FP_EntityClingerState_Death: {
|
||||
// TODO(doyle): Implement
|
||||
if (entering_new_state) {
|
||||
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.clinger_death, TELY_AssetFlip_No);
|
||||
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
|
||||
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||
}
|
||||
|
||||
if (action_has_finished) {
|
||||
FP_Game_DeleteEntity(game, entity->handle);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case FP_EntityClingerState_Run: {
|
||||
@ -695,6 +720,10 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
|
||||
} break;
|
||||
}
|
||||
|
||||
if (entity->is_dying && *state != FP_EntityClingerState_Death) {
|
||||
action->next_state = FP_EntityClingerState_Death;
|
||||
}
|
||||
|
||||
if (*state == FP_EntityClingerState_Attack) { // NOTE: Position the attack box
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
switch (entity->direction) {
|
||||
@ -895,25 +924,29 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
// NOTE: We had a waypoint to move to Terry because he has
|
||||
// drawn our aggro and we've arrived at Terry
|
||||
|
||||
switch (entity->type) {
|
||||
case FP_EntityType_Nil: /*FALLTHRU*/
|
||||
case FP_EntityType_Merchant: break;
|
||||
bool can_attack = !entity->is_dying;
|
||||
|
||||
case FP_EntityType_Terry: {
|
||||
// TODO(doyle): We should check if it's valid to enter this new state
|
||||
// from the entity's current state
|
||||
entity->action.next_state = FP_EntityTerryState_AttackSide;
|
||||
} break;
|
||||
if (can_attack) {
|
||||
switch (entity->type) {
|
||||
case FP_EntityType_Nil: /*FALLTHRU*/
|
||||
case FP_EntityType_Merchant: break;
|
||||
|
||||
case FP_EntityType_Smoochie: {
|
||||
// TODO(doyle): We should check if it's valid to enter this new state
|
||||
// from the entity's current state
|
||||
entity->action.next_state = FP_EntitySmoochieState_AttackDown;
|
||||
} break;
|
||||
case FP_EntityType_Terry: {
|
||||
// TODO(doyle): We should check if it's valid to enter this new state
|
||||
// from the entity's current state
|
||||
entity->action.next_state = FP_EntityTerryState_AttackSide;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Clinger: {
|
||||
entity->action.next_state = FP_EntityClingerState_Attack;
|
||||
} break;
|
||||
case FP_EntityType_Smoochie: {
|
||||
// TODO(doyle): We should check if it's valid to enter this new state
|
||||
// from the entity's current state
|
||||
entity->action.next_state = FP_EntitySmoochieState_AttackDown;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Clinger: {
|
||||
entity->action.next_state = FP_EntityClingerState_Attack;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Aggro makes the entity attack Terry, we will
|
||||
@ -1030,7 +1063,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
if (target->handle == entity->handle)
|
||||
continue;
|
||||
|
||||
// TODO(josh): This check should be updated based on an entity attackable flag
|
||||
if (target->flags & FP_GameEntityFlag_Attackable) {
|
||||
Dqn_Rect target_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, target->handle);
|
||||
|
||||
@ -1038,7 +1070,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
target->hp -= 1;
|
||||
|
||||
if (target->hp <= 0) {
|
||||
FP_Game_DeleteEntity(game, target->handle);
|
||||
target->is_dying = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ
|
||||
va_end(args);
|
||||
|
||||
entity->type = FP_EntityType_Clinger;
|
||||
entity->hp = 3;
|
||||
entity->hp = 1;
|
||||
entity->is_dying = false;
|
||||
entity->local_pos = pos;
|
||||
entity->sprite_height.meters = 1.6f;
|
||||
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.4f, 1.7f);
|
||||
@ -64,6 +65,7 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D
|
||||
|
||||
entity->type = FP_EntityType_Smoochie;
|
||||
entity->hp = 1;
|
||||
entity->is_dying = false;
|
||||
entity->local_pos = pos;
|
||||
entity->sprite_height.meters = 1.6f;
|
||||
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.4f, 1.6f);
|
||||
|
@ -30,6 +30,7 @@ enum FP_EntitySmoochieState
|
||||
FP_EntitySmoochieState_AttackDown,
|
||||
FP_EntitySmoochieState_HurtSide,
|
||||
FP_EntitySmoochieState_AttackHeart,
|
||||
FP_EntitySmoochieState_Death,
|
||||
FP_EntitySmoochieState_Run,
|
||||
};
|
||||
|
||||
|
@ -142,6 +142,7 @@ struct FP_GameEntity
|
||||
Dqn_V2 attack_box_size;
|
||||
Dqn_V2 attack_box_offset;
|
||||
bool attack_processed;
|
||||
bool is_dying;
|
||||
|
||||
Dqn_FArray<Dqn_V2, 8> spawner_waypoints;
|
||||
FP_SentinelList<FP_GameEntityHandle> spawn_list;
|
||||
|
Loading…
Reference in New Issue
Block a user