fp: Add projectile attack

This commit is contained in:
2023-10-05 21:10:50 +11:00
parent aed29a9f50
commit 5f8344ddda
7 changed files with 103 additions and 23 deletions
+57 -16
View File
@@ -207,6 +207,7 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
case FP_EntityType_AirportTerry: break;
case FP_EntityType_ChurchTerry: break;
case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
}
if (!entity_collides_with_collider)
@@ -214,6 +215,9 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
// NOTE: Sweep collider with half the radius of the source entity
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
if (Dqn_V2_Area(collider_world_hit_box.size) <= 0)
continue;
Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
swept_collider_world_hit_box.size += entity_world_hit_box.size;
@@ -524,6 +528,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_K) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_Y)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_RangeAttack);
} else if (acceleration_meters_per_s->x || acceleration_meters_per_s->y) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Run);
}
@@ -541,7 +548,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
}
} break;
case FP_EntityTerryState_AttackPhone: {
case FP_EntityTerryState_RangeAttack: {
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
@@ -562,6 +569,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_K) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_Y)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_RangeAttack);
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftControl) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Dash);
@@ -585,7 +595,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} break;
}
if (*state == FP_EntityTerryState_Attack || *state == FP_EntityTerryState_AttackPhone) {
if (*state == FP_EntityTerryState_Attack || *state == FP_EntityTerryState_RangeAttack) {
DQN_ASSERT(action->sprite.anim);
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
@@ -594,33 +604,46 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
// NOTE: Adding an attack_processed bool to make sure things only fire once
if (!entity->attack_processed && game->clock_ms >= midpoint_clock_ms) {
entity->attack_box_size = entity->local_hit_box_size;
TELY_Audio_Play(audio, game->audio[FP_GameAudio_TerryHit], 1.f);
// NOTE: Position the attack box
Dqn_V2 dir_vector = {};
switch (entity->direction) {
case FP_GameDirection_Left: {
dir_vector.x = -1.f;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
entity->local_hit_box_offset.y);
} break;
case FP_GameDirection_Right: {
dir_vector.x = +1.f;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w,
entity->local_hit_box_offset.y);
} break;
case FP_GameDirection_Up: {
dir_vector.y = -1.f;
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: {
dir_vector.y = +1.f;
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;
}
if (*state == FP_EntityTerryState_RangeAttack) {
Dqn_Rect entity_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 projectile_pos = entity_hit_box.pos + entity->attack_box_offset;
Dqn_V2 projectile_acceleration = FP_Game_MetersToPixelsV2(game, dir_vector * 0.25f);
FP_Entity_CreatePhoneMessageProjectile(game, projectile_pos, projectile_acceleration, "Phone Message Projectile");
} else {
entity->attack_box_size = entity->local_hit_box_size;
TELY_Audio_Play(audio, game->audio[FP_GameAudio_TerryHit], 1.f);
}
entity->attack_processed = true;
} else {
entity->attack_box_size = {};
@@ -723,6 +746,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
entity->local_hit_box_size = {};
}
if (action_has_finished)
@@ -827,6 +851,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
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);
entity->local_hit_box_size = {};
}
if (action_has_finished)
@@ -1082,6 +1107,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
entity->local_hit_box_size = {};
}
if (action_has_finished)
@@ -1241,7 +1267,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
continue;
// NOTE: Move entity by keyboard and gamepad ===============================================
Dqn_V2 acceleration_meters_per_s = {};
Dqn_V2 acceleration_meters_per_s = entity->constant_acceleration_per_s;
if (game->clicked_entity == entity->handle) {
if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) {
bool move_entity = true;
@@ -1261,15 +1287,20 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
move_entity = *state == FP_EntityClingerState_Run || *state == FP_EntityClingerState_Idle;
} break;
case FP_EntityType_Nil: break;
case FP_EntityType_ClubTerry: break;
case FP_EntityType_Count: break;
case FP_EntityType_Map: break;
case FP_EntityType_MerchantTerry: break;
case FP_EntityType_MerchantGraveyard: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break;
case FP_EntityType_MerchantGym: break;
case FP_EntityType_Nil: break;
case FP_EntityType_ClubTerry: break;
case FP_EntityType_Count: break;
case FP_EntityType_Map: break;
case FP_EntityType_MerchantTerry: break;
case FP_EntityType_MerchantGraveyard: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break;
case FP_EntityType_MerchantGym: break;
case FP_EntityType_AirportTerry: break;
case FP_EntityType_Catfish: break;
case FP_EntityType_ChurchTerry: break;
case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
}
if (move_entity) {
@@ -1536,7 +1567,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
if (game->active_entity == entity->handle && entity->flags & FP_GameEntityFlag_MoveByMouse) {
entity->velocity = {};
acceleration_meters_per_s = {};
entity->local_pos += input->mouse_p_delta;
entity->local_pos += input->mouse_p_delta;
}
if (game->clicked_entity == entity->handle) {
@@ -1596,6 +1627,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) {
FP_GameEntity *entity = it.entity;
if (entity->flags & FP_GameEntityFlag_TTL) {
if (game->clock_ms >= entity->ttl_end_timestamp) {
FP_Game_DeleteEntity(game, entity->handle);
continue;
}
}
// NOTE: Derive dynmamic bounding boxes ====================================================
if (entity->flags & FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox) {
Dqn_Rect children_bbox = {};
@@ -1727,7 +1765,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_Heart: break;
case FP_EntityType_AirportTerry:
case FP_EntityType_ChurchTerry:
case FP_EntityType_KennelTerry: break;
case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
}
if (!permit_attack)
@@ -1743,6 +1782,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
defender->is_dying = true;
// NOTE: Kickback ======================================================================
#if 0
Dqn_V2 defender_world_pos = Dqn_Rect_Center(defender_box);
Dqn_V2 attack_dir_vector = {};
if (attacker_world_pos.x < defender_world_pos.x)
@@ -1752,6 +1792,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
Dqn_V2 attack_acceleration_meters_per_s = attack_dir_vector * 60.f;
FP_Game_MoveEntity(game, defender->handle, attack_acceleration_meters_per_s);
#endif
}
}
}