fp: Add projectile attack
This commit is contained in:
+57
-16
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user