tely: Deprecate anim to action mapping it sucks
This commit is contained in:
parent
f95cb8ec9b
commit
ea9f63d709
458
feely_pona.cpp
458
feely_pona.cpp
@ -3,6 +3,23 @@
|
|||||||
#include "feely_pona_unity.h"
|
#include "feely_pona_unity.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct FP_GlobalAnimations
|
||||||
|
{
|
||||||
|
Dqn_String8 terry_walk_idle = DQN_STRING8("terry_walk_idle");
|
||||||
|
Dqn_String8 terry_walk_up = DQN_STRING8("terry_walk_up");
|
||||||
|
Dqn_String8 terry_walk_down = DQN_STRING8("terry_walk_down");
|
||||||
|
Dqn_String8 terry_walk_left = DQN_STRING8("terry_walk_left");
|
||||||
|
Dqn_String8 terry_walk_right = DQN_STRING8("terry_walk_right");
|
||||||
|
|
||||||
|
Dqn_String8 smoochie_walk_up = DQN_STRING8("smoochie_walk_up");
|
||||||
|
Dqn_String8 smoochie_walk_down = DQN_STRING8("smoochie_walk_down");
|
||||||
|
Dqn_String8 smoochie_walk_left = DQN_STRING8("smoochie_walk_left");
|
||||||
|
Dqn_String8 smoochie_walk_right = DQN_STRING8("smoochie_walk_right");
|
||||||
|
Dqn_String8 smoochie_attack = DQN_STRING8("smoochie_attack");
|
||||||
|
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death");
|
||||||
|
}
|
||||||
|
g_anim_names;
|
||||||
|
|
||||||
TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
|
TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
|
||||||
{
|
{
|
||||||
TELY_AssetSpriteSheet result = {};
|
TELY_AssetSpriteSheet result = {};
|
||||||
@ -486,21 +503,22 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
{
|
{
|
||||||
game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_walk_resized_25%"));
|
game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_walk_resized_25%"));
|
||||||
game->terry_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
game->terry_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
||||||
{FP_ActionType_Idle, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, DQN_STRING8("terry_walk_idle"))},
|
{FP_ActionType_Idle, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_idle)},
|
||||||
{FP_ActionType_WalkUp, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, DQN_STRING8("terry_walk_up"))},
|
{FP_ActionType_WalkUp, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_up)},
|
||||||
{FP_ActionType_WalkDown, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, DQN_STRING8("terry_walk_down"))},
|
{FP_ActionType_WalkDown, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_down)},
|
||||||
{FP_ActionType_WalkLeft, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, DQN_STRING8("terry_walk_left"))},
|
{FP_ActionType_WalkLeft, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_left)},
|
||||||
{FP_ActionType_WalkRight, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, DQN_STRING8("terry_walk_right"))},
|
{FP_ActionType_WalkRight, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_right)},
|
||||||
});
|
});
|
||||||
|
|
||||||
game->smoochie_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%"));
|
game->smoochie_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%"));
|
||||||
game->smoochie_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
game->smoochie_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
||||||
{FP_ActionType_Idle, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_walk_down"))},
|
{FP_ActionType_Idle, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
|
||||||
{FP_ActionType_WalkUp, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_walk_up"))},
|
{FP_ActionType_WalkUp, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_up)},
|
||||||
{FP_ActionType_WalkDown, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_walk_down"))},
|
{FP_ActionType_WalkDown, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
|
||||||
{FP_ActionType_WalkLeft, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_walk_left"))},
|
{FP_ActionType_WalkLeft, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_left)},
|
||||||
{FP_ActionType_WalkRight, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_walk_right"))},
|
{FP_ActionType_WalkRight, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_right)},
|
||||||
{FP_ActionType_Death, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, DQN_STRING8("smoochie_death"))},
|
{FP_ActionType_Attack, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack)},
|
||||||
|
{FP_ActionType_Death, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_death)},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +622,7 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
Dqn_V2I max_tile = platform->core.window_size / game->tile_size;
|
Dqn_V2I max_tile = platform->core.window_size / game->tile_size;
|
||||||
|
|
||||||
// NOTE: Wall ==================================================================================
|
// NOTE: Wall ==================================================================================
|
||||||
{
|
if (0) {
|
||||||
Dqn_V2I vert_wall_tile_size = Dqn_V2I_InitNx2(1, 12);
|
Dqn_V2I vert_wall_tile_size = Dqn_V2I_InitNx2(1, 12);
|
||||||
Dqn_V2I right_wall_tile_pos = Dqn_V2I_InitNx2(max_tile.x - vert_wall_tile_size.x - 0, (max_tile.y / 2.f) - (vert_wall_tile_size.y * .5f));
|
Dqn_V2I right_wall_tile_pos = Dqn_V2I_InitNx2(max_tile.x - vert_wall_tile_size.x - 0, (max_tile.y / 2.f) - (vert_wall_tile_size.y * .5f));
|
||||||
|
|
||||||
@ -679,6 +697,252 @@ FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingForType(FP_Game *game, F
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingWithName(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_String8 name)
|
||||||
|
{
|
||||||
|
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
|
||||||
|
FP_ActionToAnimationMapping result = {};
|
||||||
|
for (FP_ActionToAnimationMapping const &mapping : entity->action_to_anim_mapping) {
|
||||||
|
if (mapping.anim.label == name) {
|
||||||
|
result = mapping;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 dir_vector)
|
||||||
|
{
|
||||||
|
FP_GameEntityAction *action = &entity->action;
|
||||||
|
bool we_are_clicked_entity = entity->handle == game->clicked_entity;
|
||||||
|
bool action_has_finished = action->timer_s != FP_GAME_ENTITY_ACTION_INFINITE_TIMER && action->timer_s >= action->end_at_s;
|
||||||
|
bool entity_has_velocity = entity->velocity.x || entity->velocity.y;
|
||||||
|
FP_ActionToAnimationMapping result = {};
|
||||||
|
|
||||||
|
switch (entity->type) {
|
||||||
|
case FP_GameEntityType_Terry: {
|
||||||
|
FP_GameTerryState *state = DQN_CAST(FP_GameTerryState *)&action->state;
|
||||||
|
if (*state == FP_GameTerryState_Nil)
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_Idle) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_idle);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
||||||
|
} else if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackA);
|
||||||
|
} else if (dir_vector.x || dir_vector.y) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_AttackA) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
||||||
|
} else if (action_has_finished) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
Dqn_f32 t01 = action->timer_s / action->end_at_s;
|
||||||
|
if (t01 > 0.5f)
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackB);
|
||||||
|
else
|
||||||
|
action->flags |= FP_GameEntityActionFlag_Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_AttackB) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
||||||
|
} else if (action_has_finished) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
Dqn_f32 t01 = action->timer_s / action->end_at_s;
|
||||||
|
if (t01 > 0.5f)
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackC);
|
||||||
|
else
|
||||||
|
action->flags |= FP_GameEntityActionFlag_Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_AttackC) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
||||||
|
} else if (action_has_finished) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_Run) {
|
||||||
|
Dqn_String8 desired_action_name = {};
|
||||||
|
switch (entity->direction) {
|
||||||
|
case FP_GameDirection_Up: desired_action_name = g_anim_names.terry_walk_up; 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_Right: desired_action_name = g_anim_names.terry_walk_right; break;
|
||||||
|
}
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, desired_action_name);
|
||||||
|
|
||||||
|
if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackA);
|
||||||
|
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Dash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Also handles state transition
|
||||||
|
if (action->mapping.action_type != result.action_type) {
|
||||||
|
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity_has_velocity /*&& !has_collision*/) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_Dash) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
||||||
|
|
||||||
|
Dqn_V2 dash_dir = {};
|
||||||
|
switch (entity->direction) {
|
||||||
|
case FP_GameDirection_Up: 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_Right: dash_dir.x = +1.f; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f;
|
||||||
|
Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s);
|
||||||
|
entity->velocity = (dash_acceleration * t) + entity->velocity * 2.0f;
|
||||||
|
|
||||||
|
} else if (action_has_finished) {
|
||||||
|
if (entity_has_velocity) {
|
||||||
|
// TODO(doyle): Not sure if this branch triggers properly.
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Run);
|
||||||
|
} else {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameTerryState_AttackA ||
|
||||||
|
*state == FP_GameTerryState_AttackB ||
|
||||||
|
*state == FP_GameTerryState_AttackC) {
|
||||||
|
entity->attack_box_size = entity->local_hit_box_size;
|
||||||
|
|
||||||
|
// NOTE: Position the attack box
|
||||||
|
if (entity->direction == FP_GameDirection_Left) {
|
||||||
|
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
|
||||||
|
entity->local_hit_box_offset.y);
|
||||||
|
} else {
|
||||||
|
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->local_hit_box_size.w,
|
||||||
|
entity->local_hit_box_offset.y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entity->attack_box_size = {};
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_GameEntityType_Smoochie: {
|
||||||
|
FP_GameSmoochieState *state = DQN_CAST(FP_GameSmoochieState *)&action->state;
|
||||||
|
if (*state == FP_GameSmoochieState_Nil)
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Idle);
|
||||||
|
|
||||||
|
if (*state == FP_GameSmoochieState_Idle) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_walk_down);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
||||||
|
} else if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Attack);
|
||||||
|
} else if (dir_vector.x || dir_vector.y) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameSmoochieState_Attack) {
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack);
|
||||||
|
|
||||||
|
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||||
|
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
||||||
|
} else if (action_has_finished) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameSmoochieState_Run) {
|
||||||
|
Dqn_String8 desired_action_name = {};
|
||||||
|
switch (entity->direction) {
|
||||||
|
case FP_GameDirection_Up: desired_action_name = g_anim_names.smoochie_walk_up; 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_Right: desired_action_name = g_anim_names.smoochie_walk_right; break;
|
||||||
|
}
|
||||||
|
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, desired_action_name);
|
||||||
|
|
||||||
|
if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Attack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Also handles state transition
|
||||||
|
if (action->mapping.action_type != result.action_type) {
|
||||||
|
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity_has_velocity /*&& !has_collision*/) {
|
||||||
|
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*state == FP_GameSmoochieState_Attack) {
|
||||||
|
entity->attack_box_size = entity->local_hit_box_size;
|
||||||
|
// NOTE: Position the attack box
|
||||||
|
if (entity->direction == FP_GameDirection_Left) {
|
||||||
|
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
|
||||||
|
entity->local_hit_box_offset.y);
|
||||||
|
} else {
|
||||||
|
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->local_hit_box_size.w,
|
||||||
|
entity->local_hit_box_offset.y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entity->attack_box_size = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Tick entity action ================================================================
|
||||||
|
action->timer_s += DQN_CAST(Dqn_f32)input->delta_s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input)
|
void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input)
|
||||||
{
|
{
|
||||||
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
|
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
|
||||||
@ -726,9 +990,21 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
|||||||
|
|
||||||
// NOTE: Move entity by keyboard and gamepad ===============================================
|
// NOTE: Move entity by keyboard and gamepad ===============================================
|
||||||
Dqn_V2 acceleration = {};
|
Dqn_V2 acceleration = {};
|
||||||
if (game->clicked_entity == entity->handle &&
|
if (game->clicked_entity == entity->handle) {
|
||||||
(entity->action.state == FP_GameEntityState_Run || entity->action.state == FP_GameEntityState_Idle)) {
|
if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) {
|
||||||
if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard || FP_GameEntityFlag_MoveByGamepad)) {
|
bool move_entity = false;
|
||||||
|
switch (entity->type) {
|
||||||
|
case FP_GameEntityType_Terry: {
|
||||||
|
FP_GameTerryState *state = DQN_CAST(FP_GameTerryState *)&entity->action.state;
|
||||||
|
move_entity = *state == FP_GameTerryState_Run || *state == FP_GameTerryState_Idle;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_GameEntityType_Smoochie: {
|
||||||
|
FP_GameSmoochieState *state = DQN_CAST(FP_GameSmoochieState *)&entity->action.state;
|
||||||
|
move_entity = *state == FP_GameSmoochieState_Run || *state == FP_GameSmoochieState_Idle;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
acceleration = dir_vector * 10000000.f;
|
acceleration = dir_vector * 10000000.f;
|
||||||
if (dir_vector.x)
|
if (dir_vector.x)
|
||||||
entity->direction = dir_vector.x > 0.f ? FP_GameDirection_Right : FP_GameDirection_Left;
|
entity->direction = dir_vector.x > 0.f ? FP_GameDirection_Right : FP_GameDirection_Left;
|
||||||
@ -878,7 +1154,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
|||||||
Dqn_V2 pos_just_before_collide = entity_pos + (d * earliest_t);
|
Dqn_V2 pos_just_before_collide = entity_pos + (d * earliest_t);
|
||||||
Dqn_V2 new_delta_p = pos_just_before_collide - entity_pos;
|
Dqn_V2 new_delta_p = pos_just_before_collide - entity_pos;
|
||||||
entity->local_pos += new_delta_p;
|
entity->local_pos += new_delta_p;
|
||||||
entity->velocity = {};
|
|
||||||
has_collision = true;
|
has_collision = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -917,156 +1192,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Handle input on entity ============================================================
|
// NOTE: Handle input on entity ============================================================
|
||||||
FP_GameEntityAction *action = &entity->action;
|
FP_ActionToAnimationMapping action_to_anim_mapping = FP_EntityActionStateMachine(game, input, entity, dir_vector);
|
||||||
FP_ActionToAnimationMapping action_to_anim_mapping = {};
|
|
||||||
{
|
|
||||||
bool we_are_clicked_entity = entity->handle == game->clicked_entity;
|
|
||||||
bool action_has_finished = action->timer_s != FP_GAME_ENTITY_ACTION_INFINITE_TIMER && action->timer_s >= action->end_at_s;
|
|
||||||
bool entity_has_velocity = entity->velocity.x || entity->velocity.y;
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_Nil)
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_Idle) {
|
|
||||||
action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_Idle);
|
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, action_to_anim_mapping);
|
|
||||||
} else if (we_are_clicked_entity) {
|
|
||||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_AttackA);
|
|
||||||
} else if (dir_vector.x || dir_vector.y) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Run);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_AttackA) {
|
|
||||||
action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_Attack);
|
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
|
||||||
FP_Game_EntityActionReset(action, action_to_anim_mapping.anim.count * action_to_anim_mapping.anim.seconds_per_frame, action_to_anim_mapping);
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
|
|
||||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
|
||||||
Dqn_f32 t01 = action->timer_s / action->end_at_s;
|
|
||||||
if (t01 > 0.5f)
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_AttackB);
|
|
||||||
else
|
|
||||||
action->flags |= FP_GameEntityActionFlag_Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_AttackB) {
|
|
||||||
action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_Attack);
|
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
|
||||||
FP_Game_EntityActionReset(action, action_to_anim_mapping.anim.count * action_to_anim_mapping.anim.seconds_per_frame, action_to_anim_mapping);
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
|
|
||||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
|
||||||
Dqn_f32 t01 = action->timer_s / action->end_at_s;
|
|
||||||
if (t01 > 0.5f)
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_AttackC);
|
|
||||||
else
|
|
||||||
action->flags |= FP_GameEntityActionFlag_Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_AttackC) {
|
|
||||||
action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_Attack);
|
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
|
||||||
FP_Game_EntityActionReset(action, action_to_anim_mapping.anim.count * action_to_anim_mapping.anim.seconds_per_frame, action_to_anim_mapping);
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_Run) {
|
|
||||||
switch (entity->direction) {
|
|
||||||
case FP_GameDirection_Up: action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_WalkUp); break;
|
|
||||||
case FP_GameDirection_Down: action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_WalkDown); break;
|
|
||||||
case FP_GameDirection_Left: action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_WalkLeft); break;
|
|
||||||
case FP_GameDirection_Right: action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_WalkRight); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (we_are_clicked_entity) {
|
|
||||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_AttackA);
|
|
||||||
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Dash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Also handles state transition
|
|
||||||
if (action->mapping.action_type != action_to_anim_mapping.action_type) {
|
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, action_to_anim_mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entity_has_velocity && !has_collision) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action->state == FP_GameEntityState_Dash) {
|
|
||||||
action_to_anim_mapping = FP_Game_GetActionAnimMappingForType(game, entity->handle, FP_ActionType_WalkRight);
|
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
|
||||||
FP_Game_EntityActionReset(action, action_to_anim_mapping.anim.count * action_to_anim_mapping.anim.seconds_per_frame, action_to_anim_mapping);
|
|
||||||
|
|
||||||
Dqn_V2 dash_dir = {};
|
|
||||||
switch (entity->direction) {
|
|
||||||
case FP_GameDirection_Up: 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_Right: dash_dir.x = +1.f; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f;
|
|
||||||
Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s);
|
|
||||||
entity->velocity = (dash_acceleration * t) + entity->velocity * 2.0f;
|
|
||||||
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
if (entity_has_velocity) {
|
|
||||||
// TODO(doyle): Not sure if this branch triggers properly.
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Run);
|
|
||||||
} else {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_GameEntityState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Tick entity action ================================================================
|
|
||||||
action->timer_s += DQN_CAST(Dqn_f32)input->delta_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Calculate entity attack box =======================================================
|
|
||||||
if (action->state == FP_GameEntityState_AttackA ||
|
|
||||||
action->state == FP_GameEntityState_AttackB ||
|
|
||||||
action->state == FP_GameEntityState_AttackC) {
|
|
||||||
entity->attack_box_size = entity->local_hit_box_size;
|
|
||||||
|
|
||||||
// NOTE: Position the attack box
|
|
||||||
if (entity->direction == FP_GameDirection_Left) {
|
|
||||||
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
|
|
||||||
entity->local_hit_box_offset.y);
|
|
||||||
} else {
|
|
||||||
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->local_hit_box_size.w,
|
|
||||||
entity->local_hit_box_offset.y);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entity->attack_box_size = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Mob spawner =======================================================================
|
// NOTE: Mob spawner =======================================================================
|
||||||
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
||||||
|
@ -424,7 +424,7 @@ static Dqn_Rect FP_Game_CalcEntityWorldBoundingBox(FP_Game *game, FP_GameEntityH
|
|||||||
|
|
||||||
// Transition the action into the desire state and set the flag to indicate it
|
// Transition the action into the desire state and set the flag to indicate it
|
||||||
// has just transitioned
|
// has just transitioned
|
||||||
static void FP_Game_EntityActionSetState(FP_GameEntityAction *action, FP_GameEntityState state)
|
static void FP_Game_EntityActionSetState(FP_GameEntityAction *action, uint32_t state)
|
||||||
{
|
{
|
||||||
if (!action)
|
if (!action)
|
||||||
return;
|
return;
|
||||||
@ -668,6 +668,7 @@ static FP_GameEntityHandle FP_Game_EntityAddWallAtTile(FP_Game *game, Dqn_String
|
|||||||
static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos)
|
static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos)
|
||||||
{
|
{
|
||||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob");
|
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob");
|
||||||
|
entity->type = FP_GameEntityType_Smoochie;
|
||||||
entity->local_pos = pos;
|
entity->local_pos = pos;
|
||||||
entity->size_scale = Dqn_V2_InitNx1(.25f);
|
entity->size_scale = Dqn_V2_InitNx1(.25f);
|
||||||
entity->action_to_anim_mapping = game->smoochie_action_mappings;
|
entity->action_to_anim_mapping = game->smoochie_action_mappings;
|
||||||
|
@ -45,17 +45,6 @@ struct FP_GameEntityHandle
|
|||||||
uint64_t id;
|
uint64_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FP_GameEntityState
|
|
||||||
{
|
|
||||||
FP_GameEntityState_Nil,
|
|
||||||
FP_GameEntityState_Idle,
|
|
||||||
FP_GameEntityState_AttackA,
|
|
||||||
FP_GameEntityState_AttackB,
|
|
||||||
FP_GameEntityState_AttackC,
|
|
||||||
FP_GameEntityState_Run,
|
|
||||||
FP_GameEntityState_Dash,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FP_GameWaypoint
|
struct FP_GameWaypoint
|
||||||
{
|
{
|
||||||
Dqn_V2I pos;
|
Dqn_V2I pos;
|
||||||
@ -90,7 +79,7 @@ struct FP_ActionToAnimationMapping
|
|||||||
Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f;
|
Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f;
|
||||||
struct FP_GameEntityAction
|
struct FP_GameEntityAction
|
||||||
{
|
{
|
||||||
FP_GameEntityState state;
|
uint32_t state;
|
||||||
uint32_t flags; // Bit flags corresponding with `FP_GameEntityActionFlag`
|
uint32_t flags; // Bit flags corresponding with `FP_GameEntityActionFlag`
|
||||||
FP_ActionToAnimationMapping mapping;
|
FP_ActionToAnimationMapping mapping;
|
||||||
Dqn_f32 timer_s;
|
Dqn_f32 timer_s;
|
||||||
@ -105,6 +94,31 @@ enum FP_GameDirection
|
|||||||
FP_GameDirection_Right,
|
FP_GameDirection_Right,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FP_GameEntityType
|
||||||
|
{
|
||||||
|
FP_GameEntityType_Terry,
|
||||||
|
FP_GameEntityType_Smoochie,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FP_GameTerryState
|
||||||
|
{
|
||||||
|
FP_GameTerryState_Nil,
|
||||||
|
FP_GameTerryState_Idle,
|
||||||
|
FP_GameTerryState_AttackA,
|
||||||
|
FP_GameTerryState_AttackB,
|
||||||
|
FP_GameTerryState_AttackC,
|
||||||
|
FP_GameTerryState_Run,
|
||||||
|
FP_GameTerryState_Dash,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FP_GameSmoochieState
|
||||||
|
{
|
||||||
|
FP_GameSmoochieState_Nil,
|
||||||
|
FP_GameSmoochieState_Idle,
|
||||||
|
FP_GameSmoochieState_Attack,
|
||||||
|
FP_GameSmoochieState_Run,
|
||||||
|
};
|
||||||
|
|
||||||
struct FP_GameEntity
|
struct FP_GameEntity
|
||||||
{
|
{
|
||||||
FP_GameEntity *next;
|
FP_GameEntity *next;
|
||||||
@ -113,8 +127,11 @@ struct FP_GameEntity
|
|||||||
FP_GameEntity *last_child;
|
FP_GameEntity *last_child;
|
||||||
FP_GameEntity *parent;
|
FP_GameEntity *parent;
|
||||||
|
|
||||||
|
FP_GameEntityType type;
|
||||||
Dqn_String8 name;
|
Dqn_String8 name;
|
||||||
FP_GameEntityHandle handle;
|
FP_GameEntityHandle handle;
|
||||||
|
|
||||||
|
// TODO(doyle): Deprecate this, it is over engineered and doesn't work
|
||||||
Dqn_Slice<FP_ActionToAnimationMapping> action_to_anim_mapping;
|
Dqn_Slice<FP_ActionToAnimationMapping> action_to_anim_mapping;
|
||||||
Dqn_V2 size_scale;
|
Dqn_V2 size_scale;
|
||||||
FP_GameEntityAction action;
|
FP_GameEntityAction action;
|
||||||
|
Loading…
Reference in New Issue
Block a user