fp: Use same attack pattern for Smoochie+Terry as Clinger

This commit is contained in:
doyle 2023-09-29 16:17:55 +10:00
parent 2aa3a9568b
commit d3462f8dc9
2 changed files with 80 additions and 106 deletions

View File

@ -161,12 +161,6 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
bool entity_collides_with_collider = true; bool entity_collides_with_collider = true;
switch (entity->type) { switch (entity->type) {
case FP_EntityType_Nil: {
} break;
case FP_EntityType_Terry: {
} break;
case FP_EntityType_Smoochie: { case FP_EntityType_Smoochie: {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger) if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger)
entity_collides_with_collider = false; entity_collides_with_collider = false;
@ -177,8 +171,10 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
entity_collides_with_collider = false; entity_collides_with_collider = false;
} break; } break;
case FP_EntityType_Merchant: { case FP_EntityType_Nil: /*FALLTRHU*/
} break; case FP_EntityType_Terry: /*FALLTRHU*/
case FP_EntityType_Merchant: /*FALLTRHU*/
case FP_EntityType_Count: break;
} }
if (!entity_collides_with_collider) if (!entity_collides_with_collider)
@ -394,8 +390,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
action->state = action->next_state; action->state = action->next_state;
switch (entity->type) { switch (entity->type) {
case FP_EntityType_Nil: {
} break;
case FP_EntityType_Terry: { case FP_EntityType_Terry: {
FP_EntityTerryState *state = DQN_CAST(FP_EntityTerryState *) & action->state; FP_EntityTerryState *state = DQN_CAST(FP_EntityTerryState *) & action->state;
@ -416,32 +410,25 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
switch (entity->direction) {
case FP_GameDirection_Up: {
action->next_state = FP_EntityTerryState_AttackUp;
} break;
case FP_GameDirection_Left: {
action->next_state = FP_EntityTerryState_AttackSide;
} break;
case FP_GameDirection_Right: {
action->next_state = FP_EntityTerryState_AttackSide;
} break;
case FP_GameDirection_Down: {
action->next_state = FP_EntityTerryState_AttackDown;
} break;
}
} else if (dir_vector.x || dir_vector.y) { } else if (dir_vector.x || dir_vector.y) {
action->next_state = FP_EntityTerryState_Run; action->next_state = FP_EntityTerryState_Run;
} }
} }
} break; } break;
case FP_EntityTerryState_AttackUp: { case FP_EntityTerryState_Attack: {
if (entering_new_state) { if (entering_new_state) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_attack_up, TELY_AssetFlip_No); uint32_t asset_flip = {};
Dqn_String8 desired_action_name = {};
switch (entity->direction) {
case FP_GameDirection_Up: desired_action_name = g_anim_names.terry_attack_up; break;
case FP_GameDirection_Down: desired_action_name = g_anim_names.terry_attack_down; break;
case FP_GameDirection_Left: desired_action_name = g_anim_names.terry_attack_side; break;
case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_attack_side; asset_flip |= TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, DQN_CAST(TELY_AssetFlip)asset_flip);
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame; uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
} }
@ -451,29 +438,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
} }
} break; } break;
case FP_EntityTerryState_AttackDown: {
if (entering_new_state) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_attack_down, 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)
action->next_state = FP_EntityTerryState_Idle;
} break;
case FP_EntityTerryState_AttackSide: {
if (entering_new_state) {
TELY_AssetFlip flip = entity->direction == FP_GameDirection_Right ? TELY_AssetFlip_X : TELY_AssetFlip_No;
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_attack_side, flip);
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)
action->next_state = FP_EntityTerryState_Idle;
} break;
case FP_EntityTerryState_Run: { case FP_EntityTerryState_Run: {
Dqn_String8 desired_action_name = {}; Dqn_String8 desired_action_name = {};
switch (entity->direction) { switch (entity->direction) {
@ -481,6 +445,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
case FP_GameDirection_Down: desired_action_name = g_anim_names.terry_walk_down; break; case FP_GameDirection_Down: desired_action_name = g_anim_names.terry_walk_down; break;
case FP_GameDirection_Left: desired_action_name = g_anim_names.terry_walk_left; break; case FP_GameDirection_Left: desired_action_name = g_anim_names.terry_walk_left; break;
case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_walk_right; break; case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
if (entering_new_state || action->sprite.anim->label != desired_action_name) { if (entering_new_state || action->sprite.anim->label != desired_action_name) {
@ -492,23 +457,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
switch (entity->direction) { action->next_state = FP_EntityTerryState_Attack;
case FP_GameDirection_Up: {
action->next_state = FP_EntityTerryState_AttackUp;
} break;
case FP_GameDirection_Left: {
action->next_state = FP_EntityTerryState_AttackSide;
} break;
case FP_GameDirection_Right: {
action->next_state = FP_EntityTerryState_AttackSide;
} break;
case FP_GameDirection_Down: {
action->next_state = FP_EntityTerryState_AttackDown;
} break;
}
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) || } else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
action->next_state = FP_EntityTerryState_Dash; action->next_state = FP_EntityTerryState_Dash;
@ -533,6 +482,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
case FP_GameDirection_Down: dash_dir.y = +1.f; break; case FP_GameDirection_Down: dash_dir.y = +1.f; break;
case FP_GameDirection_Left: dash_dir.x = -1.f; break; case FP_GameDirection_Left: dash_dir.x = -1.f; break;
case FP_GameDirection_Right: dash_dir.x = +1.f; break; case FP_GameDirection_Right: dash_dir.x = +1.f; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f; Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f;
@ -551,9 +501,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
} break; } break;
} }
if (*state == FP_EntityTerryState_AttackUp || if (*state == FP_EntityTerryState_Attack) {
*state == FP_EntityTerryState_AttackDown ||
*state == FP_EntityTerryState_AttackSide) {
DQN_ASSERT(action->sprite.anim); DQN_ASSERT(action->sprite.anim);
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame; uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
@ -565,18 +513,28 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
entity->attack_box_size = entity->local_hit_box_size; entity->attack_box_size = entity->local_hit_box_size;
// NOTE: Position the attack box // NOTE: Position the attack box
if (entity->direction == FP_GameDirection_Left) { switch (entity->direction) {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w, case FP_GameDirection_Left: {
entity->local_hit_box_offset.y); entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
} else if (entity->direction == FP_GameDirection_Right) { entity->local_hit_box_offset.y);
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w, } break;
entity->local_hit_box_offset.y);
} else if (entity->direction == FP_GameDirection_Up) { case FP_GameDirection_Right: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x, entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w,
entity->local_hit_box_offset.y - entity->attack_box_size.h); entity->local_hit_box_offset.y);
} else if (entity->direction == FP_GameDirection_Down) { } break;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h); case FP_GameDirection_Up: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y - entity->attack_box_size.h);
} break;
case FP_GameDirection_Down: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h);
} break;
case FP_GameDirection_Count: break;
} }
entity->attack_processed = true; entity->attack_processed = true;
} else { } else {
@ -608,7 +566,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
action->next_state = FP_EntitySmoochieState_AttackDown; action->next_state = FP_EntitySmoochieState_Attack;
} else if (dir_vector.x || dir_vector.y) { } else if (dir_vector.x || dir_vector.y) {
action->next_state = FP_EntitySmoochieState_Run; action->next_state = FP_EntitySmoochieState_Run;
} }
@ -619,7 +577,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
} }
} break; } break;
case FP_EntitySmoochieState_AttackDown: { case FP_EntitySmoochieState_Attack: {
if (entering_new_state) { if (entering_new_state) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_attack_down, TELY_AssetFlip_No); TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_attack_down, TELY_AssetFlip_No);
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame; uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
@ -703,6 +661,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
case FP_GameDirection_Down: desired_action_name = g_anim_names.smoochie_walk_down; break; case FP_GameDirection_Down: desired_action_name = g_anim_names.smoochie_walk_down; break;
case FP_GameDirection_Left: desired_action_name = g_anim_names.smoochie_walk_left; break; case FP_GameDirection_Left: desired_action_name = g_anim_names.smoochie_walk_left; break;
case FP_GameDirection_Right: desired_action_name = g_anim_names.smoochie_walk_right; break; case FP_GameDirection_Right: desired_action_name = g_anim_names.smoochie_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
if (entering_new_state || action->sprite.anim->label != desired_action_name) { if (entering_new_state || action->sprite.anim->label != desired_action_name) {
@ -714,7 +673,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
action->next_state = FP_EntitySmoochieState_AttackDown; action->next_state = FP_EntitySmoochieState_Attack;
} }
} }
@ -728,21 +687,31 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
action->next_state = FP_EntitySmoochieState_Death; action->next_state = FP_EntitySmoochieState_Death;
} }
if (*state == FP_EntitySmoochieState_AttackDown) { if (*state == FP_EntitySmoochieState_Attack) {
entity->attack_box_size = entity->local_hit_box_size; entity->attack_box_size = entity->local_hit_box_size;
// NOTE: Position the attack box // NOTE: Position the attack box
if (entity->direction == FP_GameDirection_Left) { switch (entity->direction) {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w, case FP_GameDirection_Left: {
entity->local_hit_box_offset.y); entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
} else if (entity->direction == FP_GameDirection_Right) { entity->local_hit_box_offset.y);
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w, } break;
entity->local_hit_box_offset.y);
} else if (entity->direction == FP_GameDirection_Up) { case FP_GameDirection_Right: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x, entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w,
entity->local_hit_box_offset.y - entity->attack_box_size.h); entity->local_hit_box_offset.y);
} else if (entity->direction == FP_GameDirection_Down) { } break;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h); case FP_GameDirection_Up: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y - entity->attack_box_size.h);
} break;
case FP_GameDirection_Down: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h);
} break;
case FP_GameDirection_Count: break;
} }
} else { } else {
entity->attack_box_size = {}; entity->attack_box_size = {};
@ -788,6 +757,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
case FP_GameDirection_Down: desired_action_name = g_anim_names.clinger_attack_down; break; case FP_GameDirection_Down: desired_action_name = g_anim_names.clinger_attack_down; break;
case FP_GameDirection_Left: desired_action_name = g_anim_names.clinger_attack_side; asset_flip |= TELY_AssetFlip_X; break; case FP_GameDirection_Left: desired_action_name = g_anim_names.clinger_attack_side; asset_flip |= TELY_AssetFlip_X; break;
case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_attack_side; break; case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_attack_side; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
if (entering_new_state) { if (entering_new_state) {
@ -820,6 +790,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
case FP_GameDirection_Down: desired_action_name = g_anim_names.clinger_walk_down; break; case FP_GameDirection_Down: desired_action_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Left: desired_action_name = g_anim_names.clinger_walk_down; break; case FP_GameDirection_Left: desired_action_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_walk_down; break; case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
if (entering_new_state || action->sprite.anim->label != desired_action_name) { if (entering_new_state || action->sprite.anim->label != desired_action_name) {
@ -867,6 +838,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x, entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h); entity->local_hit_box_offset.y + entity->attack_box_size.h);
} break; } break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
} else { } else {
entity->attack_box_size = {}; entity->attack_box_size = {};
@ -892,6 +865,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_Ga
} break; } break;
} }
} break; } break;
case FP_EntityType_Nil: break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
} }
} }
@ -1081,13 +1057,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_Terry: { case FP_EntityType_Terry: {
// TODO(doyle): We should check if it's valid to enter this new state // TODO(doyle): We should check if it's valid to enter this new state
// from the entity's current state // from the entity's current state
entity->action.next_state = FP_EntityTerryState_AttackSide; entity->action.next_state = FP_EntityTerryState_Attack;
} break; } break;
case FP_EntityType_Smoochie: { case FP_EntityType_Smoochie: {
// TODO(doyle): We should check if it's valid to enter this new state // TODO(doyle): We should check if it's valid to enter this new state
// from the entity's current state // from the entity's current state
entity->action.next_state = FP_EntitySmoochieState_AttackDown; entity->action.next_state = FP_EntitySmoochieState_Attack;
} break; } break;
case FP_EntityType_Clinger: { case FP_EntityType_Clinger: {

View File

@ -17,9 +17,7 @@ enum FP_EntityTerryState
{ {
FP_EntityTerryState_Nil, FP_EntityTerryState_Nil,
FP_EntityTerryState_Idle, FP_EntityTerryState_Idle,
FP_EntityTerryState_AttackUp, FP_EntityTerryState_Attack,
FP_EntityTerryState_AttackDown,
FP_EntityTerryState_AttackSide,
FP_EntityTerryState_Run, FP_EntityTerryState_Run,
FP_EntityTerryState_Dash, FP_EntityTerryState_Dash,
}; };
@ -28,7 +26,7 @@ enum FP_EntitySmoochieState
{ {
FP_EntitySmoochieState_Nil, FP_EntitySmoochieState_Nil,
FP_EntitySmoochieState_Idle, FP_EntitySmoochieState_Idle,
FP_EntitySmoochieState_AttackDown, FP_EntitySmoochieState_Attack,
FP_EntitySmoochieState_HurtSide, FP_EntitySmoochieState_HurtSide,
FP_EntitySmoochieState_AttackHeart, FP_EntitySmoochieState_AttackHeart,
FP_EntitySmoochieState_Death, FP_EntitySmoochieState_Death,