Compare commits
3 Commits
30a69e40e9
...
677486e094
Author | SHA1 | Date | |
---|---|---|---|
677486e094 | |||
858a66786a | |||
468c9995bd |
2
External/tely
vendored
2
External/tely
vendored
@ -1 +1 @@
|
|||||||
Subproject commit b135bb46769657e730b49c173db7476160855984
|
Subproject commit 96ddc4d93441f1fdccf04d9f7faed96de7971c52
|
620
feely_pona.cpp
620
feely_pona.cpp
@ -83,7 +83,8 @@ TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_A
|
|||||||
anim->label = Dqn_String8_Copy(allocator, anim_name);
|
anim->label = Dqn_String8_Copy(allocator, anim_name);
|
||||||
anim->index = DQN_CAST(uint16_t)sprite_rect_index;
|
anim->index = DQN_CAST(uint16_t)sprite_rect_index;
|
||||||
anim->count = DQN_CAST(uint16_t)frame_count.value;
|
anim->count = DQN_CAST(uint16_t)frame_count.value;
|
||||||
anim->seconds_per_frame = 1.f / frames_per_second.value;
|
anim->ms_per_frame = DQN_CAST(uint32_t)(1000.f / frames_per_second.value);
|
||||||
|
DQN_ASSERT(anim->ms_per_frame != 0);
|
||||||
} else {
|
} else {
|
||||||
DQN_ASSERTF(line_splits.size == 4, "Expected 4 splits for sprite frame lines");
|
DQN_ASSERTF(line_splits.size == 4, "Expected 4 splits for sprite frame lines");
|
||||||
Dqn_String8ToU64Result x = Dqn_String8_ToU64(line_splits.data[0], 0);
|
Dqn_String8ToU64Result x = Dqn_String8_ToU64(line_splits.data[0], 0);
|
||||||
@ -106,6 +107,7 @@ TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_A
|
|||||||
|
|
||||||
DQN_ASSERT(result.rects.size == sprite_rect_index);
|
DQN_ASSERT(result.rects.size == sprite_rect_index);
|
||||||
DQN_ASSERT(result.anims.size == sprite_anim_index);
|
DQN_ASSERT(result.anims.size == sprite_anim_index);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,26 +141,26 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
sheet->sprite_size = Dqn_V2I_InitNx2(50, 37);
|
sheet->sprite_size = Dqn_V2I_InitNx2(50, 37);
|
||||||
|
|
||||||
TELY_AssetSpriteAnimation hero_anims[] = {
|
TELY_AssetSpriteAnimation hero_anims[] = {
|
||||||
{DQN_STRING8("Everything"), /*index*/ 0, /*count*/ sheet->sprite_count, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Everything"), /*index*/ 0, /*count*/ sheet->sprite_count, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Idle"), /*index*/ 0, /*count*/ 3, /*seconds_per_frame*/ 1 / 4.f},
|
{DQN_STRING8("Idle"), /*index*/ 0, /*count*/ 3, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 4.f)},
|
||||||
{DQN_STRING8("Run"), /*index*/ 8, /*count*/ 6, /*seconds_per_frame*/ 1 / 8.f},
|
{DQN_STRING8("Run"), /*index*/ 8, /*count*/ 6, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 8.f)},
|
||||||
{DQN_STRING8("Jump"), /*index*/ 14, /*count*/ 10, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Jump"), /*index*/ 14, /*count*/ 10, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Floor slide"), /*index*/ 24, /*count*/ 5, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Floor slide"), /*index*/ 24, /*count*/ 5, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Unknown"), /*index*/ 29, /*count*/ 9, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Unknown"), /*index*/ 29, /*count*/ 9, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Attack A"), /*index*/ 42, /*count*/ 7, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Attack A"), /*index*/ 42, /*count*/ 7, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Attack B"), /*index*/ 49, /*count*/ 4, /*seconds_per_frame*/ 1 / 8.f},
|
{DQN_STRING8("Attack B"), /*index*/ 49, /*count*/ 4, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 8.f)},
|
||||||
{DQN_STRING8("Attack C"), /*index*/ 53, /*count*/ 6, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Attack C"), /*index*/ 53, /*count*/ 6, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Hurt A"), /*index*/ 59, /*count*/ 5, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Hurt A"), /*index*/ 59, /*count*/ 5, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Hurt B"), /*index*/ 64, /*count*/ 5, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Hurt B"), /*index*/ 64, /*count*/ 5, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Unsheath sword"), /*index*/ 69, /*count*/ 4, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Unsheath sword"), /*index*/ 69, /*count*/ 4, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Sheath sword"), /*index*/ 73, /*count*/ 4, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Sheath sword"), /*index*/ 73, /*count*/ 4, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Air drift"), /*index*/ 77, /*count*/ 2, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Air drift"), /*index*/ 77, /*count*/ 2, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Air drop"), /*index*/ 79, /*count*/ 2, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Air drop"), /*index*/ 79, /*count*/ 2, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Ladder climb"), /*index*/ 81, /*count*/ 4, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Ladder climb"), /*index*/ 81, /*count*/ 4, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Chi push"), /*index*/ 85, /*count*/ 8, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Chi push"), /*index*/ 85, /*count*/ 8, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Leap slice A"), /*index*/ 93, /*count*/ 7, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Leap slice A"), /*index*/ 93, /*count*/ 7, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Leap slice B"), /*index*/ 100, /*count*/ 3, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Leap slice B"), /*index*/ 100, /*count*/ 3, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
{DQN_STRING8("Leap slice C"), /*index*/ 103, /*count*/ 6, /*seconds_per_frame*/ 1 / 12.f},
|
{DQN_STRING8("Leap slice C"), /*index*/ 103, /*count*/ 6, /*ms_per_frame*/ DQN_CAST(uint32_t)(1000.f / 12.f)},
|
||||||
};
|
};
|
||||||
|
|
||||||
game->hero_sprite_anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(&platform->arena, DQN_ARRAY_UCOUNT(hero_anims), Dqn_ZeroMem_No);
|
game->hero_sprite_anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(&platform->arena, DQN_ARRAY_UCOUNT(hero_anims), Dqn_ZeroMem_No);
|
||||||
@ -167,35 +169,9 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
|
|
||||||
// NOTE: Load sprite sheets ====================================================================
|
// NOTE: Load sprite sheets ====================================================================
|
||||||
{
|
{
|
||||||
game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_resized_25%"));
|
game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_resized_25%"));
|
||||||
game->terry_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
game->terry_merchant_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_merchant_resized_25%"));
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_idle)},
|
game->smoochie_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%"));
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_up)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_down)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_left)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_right)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_up)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_side)},
|
|
||||||
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_down)},
|
|
||||||
});
|
|
||||||
|
|
||||||
game->terry_merchant_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_merchant_resized_25%"));
|
|
||||||
game->terry_merchant_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
|
|
||||||
{&game->terry_merchant_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_merchant_sprite_sheet, g_anim_names.terry_merchant)},
|
|
||||||
});
|
|
||||||
|
|
||||||
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_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_up)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_left)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_right)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_down)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_side)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_heart)},
|
|
||||||
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_death)},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
|
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
|
||||||
@ -207,7 +183,6 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Terry");
|
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Terry");
|
||||||
entity->type = FP_EntityType_Terry;
|
entity->type = FP_EntityType_Terry;
|
||||||
entity->local_pos = Dqn_V2_InitNx2(1334, 396);
|
entity->local_pos = Dqn_V2_InitNx2(1334, 396);
|
||||||
entity->action_to_anim_mapping = game->terry_action_mappings;
|
|
||||||
entity->size_scale = Dqn_V2_InitNx1(0.25f);
|
entity->size_scale = Dqn_V2_InitNx1(0.25f);
|
||||||
entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale;
|
entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale;
|
||||||
entity->flags |= FP_GameEntityFlag_Clickable;
|
entity->flags |= FP_GameEntityFlag_Clickable;
|
||||||
@ -222,17 +197,16 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
|
|
||||||
// NOTE: Merchant
|
// NOTE: Merchant
|
||||||
{
|
{
|
||||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Merchant");
|
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Merchant");
|
||||||
entity->type = FP_EntityType_Merchant;
|
entity->type = FP_EntityType_Merchant;
|
||||||
entity->local_pos = Dqn_V2_InitNx2(1000, 124);
|
entity->local_pos = Dqn_V2_InitNx2(1000, 124);
|
||||||
entity->local_hit_box_size = Dqn_V2_InitNx2(50, 50);
|
entity->local_hit_box_size = Dqn_V2_InitNx2(50, 50);
|
||||||
entity->size_scale = Dqn_V2_InitNx1(0.25f);
|
entity->size_scale = Dqn_V2_InitNx1(0.25f);
|
||||||
entity->action_to_anim_mapping = game->terry_merchant_action_mappings;
|
entity->flags |= FP_GameEntityFlag_Clickable;
|
||||||
entity->flags |= FP_GameEntityFlag_Clickable;
|
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
||||||
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
entity->flags |= FP_GameEntityFlag_MoveByMouse;
|
||||||
entity->flags |= FP_GameEntityFlag_MoveByMouse;
|
entity->flags |= FP_GameEntityFlag_MoveByGamepad;
|
||||||
entity->flags |= FP_GameEntityFlag_MoveByGamepad;
|
entity->flags |= FP_GameEntityFlag_NonTraversable;
|
||||||
entity->flags |= FP_GameEntityFlag_NonTraversable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
game->tile_size = 37;
|
game->tile_size = 37;
|
||||||
@ -318,179 +292,171 @@ void TELY_DLL_Init(void *user_data)
|
|||||||
game->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa"));
|
game->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingWithName(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_String8 name)
|
void FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 dir_vector)
|
||||||
{
|
{
|
||||||
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
|
FP_GameEntityAction *action = &entity->action;
|
||||||
FP_ActionToAnimationMapping result = {};
|
bool const we_are_clicked_entity = entity->handle == game->clicked_entity;
|
||||||
for (FP_ActionToAnimationMapping const &mapping : entity->action_to_anim_mapping) {
|
bool const entity_has_velocity = entity->velocity.x || entity->velocity.y;
|
||||||
if (mapping.anim.label == name) {
|
bool const entering_new_state = action->state != action->next_state;
|
||||||
result = mapping;
|
bool const action_has_finished = !entering_new_state && game->clock_ms >= action->end_at_clock_ms;
|
||||||
break;
|
action->state = action->next_state;
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
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;
|
||||||
if (*state == FP_EntityTerryState_Nil)
|
TELY_AssetSpriteSheet *sheet = &game->terry_sprite_sheet;
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Idle);
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_Idle) {
|
switch (*state) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_idle);
|
case FP_EntityTerryState_Nil: {
|
||||||
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
|
} break;
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
case FP_EntityTerryState_Idle: {
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
if (entering_new_state) {
|
||||||
} else if (we_are_clicked_entity) {
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_walk_idle, TELY_AssetFlip_No);
|
||||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
switch (entity->direction) {
|
}
|
||||||
case FP_GameDirection_Up: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackUp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Left: {
|
if (we_are_clicked_entity) {
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackSide);
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
} break;
|
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_Right: {
|
case FP_GameDirection_Left: {
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackSide);
|
action->next_state = FP_EntityTerryState_AttackSide;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FP_GameDirection_Down: {
|
case FP_GameDirection_Right: {
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackDown);
|
action->next_state = FP_EntityTerryState_AttackSide;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case FP_GameDirection_Down: {
|
||||||
|
action->next_state = FP_EntityTerryState_AttackDown;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} else if (dir_vector.x || dir_vector.y) {
|
||||||
|
action->next_state = FP_EntityTerryState_Run;
|
||||||
}
|
}
|
||||||
} else if (dir_vector.x || dir_vector.y) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Run);
|
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_AttackSide) {
|
case FP_EntityTerryState_AttackUp: {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_side);
|
if (entering_new_state) {
|
||||||
action->flip_on_x = entity->direction == FP_GameDirection_Right;
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_attack_up, TELY_AssetFlip_No);
|
||||||
|
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Idle);
|
|
||||||
action->flip_on_x = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
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_EntityTerryState_AttackB);
|
|
||||||
else
|
|
||||||
action->flags |= FP_GameEntityActionFlag_Failed;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_AttackUp) {
|
if (action_has_finished) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_up);
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
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_EntityTerryState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_AttackDown) {
|
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_down);
|
|
||||||
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_EntityTerryState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_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)) {
|
|
||||||
switch (entity->direction) {
|
|
||||||
case FP_GameDirection_Up: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackUp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Left: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackSide);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Right: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackSide);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Down: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_AttackDown);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
|
|
||||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Dash);
|
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
|
|
||||||
// NOTE: Also handles state transition
|
case FP_EntityTerryState_AttackDown: {
|
||||||
if (action->mapping.anim.label != result.anim.label) {
|
if (entering_new_state) {
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
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 (!entity_has_velocity /*&& !has_collision*/) {
|
if (action_has_finished)
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Idle);
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
}
|
} break;
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_Dash) {
|
case FP_EntityTerryState_AttackSide: {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right);
|
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->flags & FP_GameEntityActionFlag_StateTransition) {
|
if (action_has_finished)
|
||||||
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
|
} break;
|
||||||
|
|
||||||
Dqn_V2 dash_dir = {};
|
case FP_EntityTerryState_Run: {
|
||||||
|
Dqn_String8 desired_action_name = {};
|
||||||
switch (entity->direction) {
|
switch (entity->direction) {
|
||||||
case FP_GameDirection_Up: dash_dir.y = -1.f; break;
|
case FP_GameDirection_Up: desired_action_name = g_anim_names.terry_walk_up; break;
|
||||||
case FP_GameDirection_Down: dash_dir.y = +1.f; break;
|
case FP_GameDirection_Down: desired_action_name = g_anim_names.terry_walk_down; break;
|
||||||
case FP_GameDirection_Left: dash_dir.x = -1.f; break;
|
case FP_GameDirection_Left: desired_action_name = g_anim_names.terry_walk_left; break;
|
||||||
case FP_GameDirection_Right: dash_dir.x = +1.f; break;
|
case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_walk_right; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dqn_V2 dash_acceleration = dash_dir * 400'000'000.f;
|
if (entering_new_state || action->sprite.anim->label != desired_action_name) {
|
||||||
Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s);
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, TELY_AssetFlip_No);
|
||||||
entity->velocity = (dash_acceleration * t) + entity->velocity * 2.0f;
|
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||||
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
} else if (action_has_finished) {
|
|
||||||
if (entity_has_velocity) {
|
|
||||||
// TODO(doyle): Not sure if this branch triggers properly.
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Run);
|
|
||||||
} else {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryState_Idle);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
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 (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
|
||||||
|
action->next_state = FP_EntityTerryState_Dash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity_has_velocity /*&& !has_collision*/) {
|
||||||
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_EntityTerryState_Dash: {
|
||||||
|
|
||||||
|
if (entering_new_state) {
|
||||||
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_walk_right, TELY_AssetFlip_No);
|
||||||
|
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
|
||||||
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action_has_finished) {
|
||||||
|
if (entity_has_velocity) {
|
||||||
|
// TODO(doyle): Not sure if this branch triggers properly.
|
||||||
|
action->next_state = FP_EntityTerryState_Run;
|
||||||
|
} else {
|
||||||
|
action->next_state = FP_EntityTerryState_Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*state == FP_EntityTerryState_AttackUp ||
|
if (*state == FP_EntityTerryState_AttackUp ||
|
||||||
@ -512,92 +478,107 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FP_EntityType_Smoochie: {
|
case FP_EntityType_Smoochie: {
|
||||||
FP_EntitySmoochieState *state = DQN_CAST(FP_EntitySmoochieState *)&action->state;
|
FP_EntitySmoochieState *state = DQN_CAST(FP_EntitySmoochieState *) & action->state;
|
||||||
if (*state == FP_EntitySmoochieState_Nil)
|
TELY_AssetSpriteSheet *sheet = &game->smoochie_sprite_sheet;
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_Idle);
|
|
||||||
|
|
||||||
if (*state == FP_EntitySmoochieState_Idle) {
|
switch (*state) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_walk_down);
|
case FP_EntitySmoochieState_Nil: {
|
||||||
|
action->next_state = FP_EntitySmoochieState_Idle;
|
||||||
|
} break;
|
||||||
|
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
case FP_EntitySmoochieState_Idle: {
|
||||||
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)) {
|
|
||||||
|
|
||||||
switch (entity->direction) {
|
if (entering_new_state) {
|
||||||
case FP_GameDirection_Up: /*FALLTHRU*/
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_walk_down, TELY_AssetFlip_No);
|
||||||
case FP_GameDirection_Right: /*FALLTHRU*/
|
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||||
case FP_GameDirection_Left: {
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_AttackSide);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Down: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_AttackDown);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
} else if (dir_vector.x || dir_vector.y) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_Run);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntitySmoochieState_AttackDown) {
|
if (we_are_clicked_entity) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack_down);
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
|
||||||
} else if (action_has_finished) {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntitySmoochieState_AttackSide) {
|
switch (entity->direction) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack_side);
|
case FP_GameDirection_Up: /*FALLTHRU*/
|
||||||
action->flip_on_x = entity->direction == FP_GameDirection_Right;
|
case FP_GameDirection_Right: /*FALLTHRU*/
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
case FP_GameDirection_Left: {
|
||||||
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
|
action->next_state = FP_EntitySmoochieState_AttackSide;
|
||||||
} else if (action_has_finished) {
|
} break;
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_Idle);
|
|
||||||
action->flip_on_x = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state == FP_EntitySmoochieState_Run) {
|
case FP_GameDirection_Down: {
|
||||||
Dqn_String8 desired_action_name = {};
|
action->next_state = FP_EntitySmoochieState_AttackDown;
|
||||||
switch (entity->direction) {
|
} break;
|
||||||
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;
|
} else if (dir_vector.x || dir_vector.y) {
|
||||||
case FP_GameDirection_Left: desired_action_name = g_anim_names.smoochie_walk_left; break;
|
action->next_state = FP_EntitySmoochieState_Run;
|
||||||
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)) {
|
|
||||||
|
|
||||||
switch (entity->direction) {
|
|
||||||
case FP_GameDirection_Up: /*FALLTHRU*/
|
|
||||||
case FP_GameDirection_Right: /*FALLTHRU*/
|
|
||||||
case FP_GameDirection_Left: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_AttackSide);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FP_GameDirection_Down: {
|
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_AttackDown);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
|
|
||||||
// NOTE: Also handles state transition
|
case FP_EntitySmoochieState_AttackDown: {
|
||||||
if (action->mapping.anim.label != result.anim.label) {
|
if (entering_new_state) {
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
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;
|
||||||
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
|
}
|
||||||
|
|
||||||
if (!entity_has_velocity /*&& !has_collision*/) {
|
if (action_has_finished) {
|
||||||
FP_Game_EntityActionSetState(action, FP_EntitySmoochieState_Idle);
|
action->next_state = FP_EntitySmoochieState_Idle;
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_EntitySmoochieState_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.smoochie_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_EntitySmoochieState_Idle;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_EntitySmoochieState_AttackHeart: {
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_EntitySmoochieState_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entering_new_state || action->sprite.anim->label != desired_action_name) {
|
||||||
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, TELY_AssetFlip_No);
|
||||||
|
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||||
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (we_are_clicked_entity) {
|
||||||
|
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||||
|
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||||
|
|
||||||
|
switch (entity->direction) {
|
||||||
|
case FP_GameDirection_Up: /*FALLTHRU*/
|
||||||
|
case FP_GameDirection_Right: /*FALLTHRU*/
|
||||||
|
case FP_GameDirection_Left: {
|
||||||
|
action->next_state = FP_EntitySmoochieState_AttackSide;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FP_GameDirection_Down: {
|
||||||
|
action->next_state = FP_EntitySmoochieState_AttackDown;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity_has_velocity /*&& !has_collision*/) {
|
||||||
|
action->next_state = FP_EntitySmoochieState_Idle;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*state == FP_EntitySmoochieState_AttackSide || *state == FP_EntitySmoochieState_AttackDown) {
|
if (*state == FP_EntitySmoochieState_AttackSide || *state == FP_EntitySmoochieState_AttackDown) {
|
||||||
@ -613,26 +594,28 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
|
|||||||
} else {
|
} else {
|
||||||
entity->attack_box_size = {};
|
entity->attack_box_size = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FP_EntityType_Merchant: {
|
case FP_EntityType_Merchant: {
|
||||||
FP_EntityTerryMerchantState *state = DQN_CAST(FP_EntityTerryMerchantState *)&action->state;
|
FP_EntityTerryMerchantState *state = DQN_CAST(FP_EntityTerryMerchantState *)&action->state;
|
||||||
if (*state == FP_EntityTerryMerchantState_Nil)
|
TELY_AssetSpriteSheet *sheet = &game->terry_merchant_sprite_sheet;
|
||||||
FP_Game_EntityActionSetState(action, FP_EntityTerryMerchantState_Idle);
|
|
||||||
|
|
||||||
if (*state == FP_EntityTerryMerchantState_Idle) {
|
switch (*state) {
|
||||||
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_merchant);
|
case FP_EntityTerryMerchantState_Nil: {
|
||||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
action->next_state = FP_EntityTerryMerchantState_Idle;
|
||||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
|
} break;
|
||||||
}
|
|
||||||
|
case FP_EntityTerryMerchantState_Idle: {
|
||||||
|
if (entering_new_state) {
|
||||||
|
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_merchant, TELY_AssetFlip_No);
|
||||||
|
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||||
|
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
} break;
|
} 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)
|
||||||
@ -642,6 +625,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
|||||||
if (TELY_Platform_InputKeyIsReleased(input->mouse_left))
|
if (TELY_Platform_InputKeyIsReleased(input->mouse_left))
|
||||||
game->clicked_entity = game->prev_active_entity;
|
game->clicked_entity = game->prev_active_entity;
|
||||||
|
|
||||||
|
game->clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f);
|
||||||
Dqn_V2 dir_vector = {};
|
Dqn_V2 dir_vector = {};
|
||||||
|
|
||||||
// NOTE: Keyboard movement input
|
// NOTE: Keyboard movement input
|
||||||
@ -887,7 +871,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Handle input on entity ============================================================
|
// NOTE: Handle input on entity ============================================================
|
||||||
FP_ActionToAnimationMapping action_to_anim_mapping = FP_EntityActionStateMachine(game, input, entity, dir_vector);
|
FP_EntityActionStateMachine(game, input, entity, dir_vector);
|
||||||
|
|
||||||
// NOTE: Mob spawner =======================================================================
|
// NOTE: Mob spawner =======================================================================
|
||||||
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
||||||
@ -1036,27 +1020,28 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Render entity sprites =============================================================
|
// NOTE: Render entity sprites =============================================================
|
||||||
if (entity->action.mapping.anim.label.size) {
|
if (entity->action.sprite.anim) {
|
||||||
FP_GameEntityAction const *action = &entity->action;
|
FP_GameEntityAction const *action = &entity->action;
|
||||||
TELY_AssetSpriteSheet const *sprite_sheet = action->mapping.sheet;
|
TELY_AssetAnimatedSprite const sprite = action->sprite;
|
||||||
TELY_AssetSpriteAnimation const *sprite_anim = &action->mapping.anim;
|
|
||||||
uint16_t anim_frame = DQN_CAST(uint16_t)(action->timer_s / sprite_anim->seconds_per_frame) % sprite_anim->count;
|
|
||||||
|
|
||||||
Dqn_usize sprite_index = sprite_anim->index + anim_frame;
|
uint64_t elapsed_ms = game->clock_ms - action->started_at_clock_ms;
|
||||||
|
uint16_t anim_frame = DQN_CAST(uint16_t)(elapsed_ms / sprite.anim->ms_per_frame) % sprite.anim->count;
|
||||||
|
|
||||||
|
Dqn_usize sprite_index = sprite.anim->index + anim_frame;
|
||||||
Dqn_Rect src_rect = {};
|
Dqn_Rect src_rect = {};
|
||||||
switch (sprite_sheet->type) {
|
switch (sprite.sheet->type) {
|
||||||
case TELY_AssetSpriteSheetType_Uniform: {
|
case TELY_AssetSpriteSheetType_Uniform: {
|
||||||
Dqn_usize sprite_sheet_row = sprite_index / sprite_sheet->sprites_per_row;
|
Dqn_usize sprite_sheet_row = sprite_index / sprite.sheet->sprites_per_row;
|
||||||
Dqn_usize sprite_sheet_column = sprite_index % sprite_sheet->sprites_per_row;
|
Dqn_usize sprite_sheet_column = sprite_index % sprite.sheet->sprites_per_row;
|
||||||
src_rect.pos.x = DQN_CAST(Dqn_f32)(sprite_sheet_column * sprite_sheet->sprite_size.w);
|
src_rect.pos.x = DQN_CAST(Dqn_f32)(sprite_sheet_column * sprite.sheet->sprite_size.w);
|
||||||
src_rect.pos.y = DQN_CAST(Dqn_f32)(sprite_sheet_row * sprite_sheet->sprite_size.y);
|
src_rect.pos.y = DQN_CAST(Dqn_f32)(sprite_sheet_row * sprite.sheet->sprite_size.y);
|
||||||
src_rect.size.w = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.w;
|
src_rect.size.w = DQN_CAST(Dqn_f32)sprite.sheet->sprite_size.w;
|
||||||
src_rect.size.h = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.h;
|
src_rect.size.h = DQN_CAST(Dqn_f32)sprite.sheet->sprite_size.h;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TELY_AssetSpriteSheetType_Rects: {
|
case TELY_AssetSpriteSheetType_Rects: {
|
||||||
DQN_ASSERT(sprite_index < sprite_sheet->rects.size);
|
DQN_ASSERT(sprite_index < sprite.sheet->rects.size);
|
||||||
src_rect = sprite_sheet->rects.data[sprite_index];
|
src_rect = sprite.sheet->rects.data[sprite_index];
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1064,10 +1049,13 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
|
|||||||
dest_rect.size = src_rect.size * entity->size_scale;
|
dest_rect.size = src_rect.size * entity->size_scale;
|
||||||
dest_rect.pos = world_pos - (dest_rect.size * .5f);
|
dest_rect.pos = world_pos - (dest_rect.size * .5f);
|
||||||
|
|
||||||
if (action->flip_on_x)
|
if (sprite.flip & TELY_AssetFlip_X)
|
||||||
dest_rect.size.w *= -1.f; // NOTE: Flip the texture horizontally
|
dest_rect.size.w *= -1.f; // NOTE: Flip the texture horizontally
|
||||||
|
|
||||||
TELY_Render_TextureColourV4(renderer, sprite_sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4);
|
if (sprite.flip & TELY_AssetFlip_Y)
|
||||||
|
dest_rect.size.h *= -1.f; // NOTE: Flip the texture vertically
|
||||||
|
|
||||||
|
TELY_Render_TextureColourV4(renderer, sprite.sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Render attack box =================================================================
|
// NOTE: Render attack box =================================================================
|
||||||
|
@ -425,32 +425,16 @@ static Dqn_Rect FP_Game_CalcEntityWorldBoundingBox(FP_Game *game, FP_GameEntityH
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition the action into the desire state and set the flag to indicate it
|
|
||||||
// has just transitioned
|
|
||||||
static void FP_Game_EntityActionSetState(FP_GameEntityAction *action, uint32_t state)
|
|
||||||
{
|
|
||||||
if (!action)
|
|
||||||
return;
|
|
||||||
action->state = state;
|
|
||||||
action->flags |= FP_GameEntityActionFlag_StateTransition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the timers and animation for the current action and set the duration
|
// Reset the timers and animation for the current action and set the duration
|
||||||
// for the new action.
|
// for the new action.
|
||||||
static void FP_Game_EntityActionReset(FP_GameEntityAction *action, Dqn_f32 new_action_duration, FP_ActionToAnimationMapping mapping)
|
static void FP_Game_EntityActionReset(FP_Game *game, FP_GameEntityHandle entity_handle, uint64_t duration_ms, TELY_AssetAnimatedSprite sprite)
|
||||||
{
|
{
|
||||||
if (!action)
|
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
|
||||||
|
if (!entity)
|
||||||
return;
|
return;
|
||||||
action->mapping = mapping;
|
entity->action.sprite = sprite;
|
||||||
action->timer_s = 0.f;
|
entity->action.started_at_clock_ms = game->clock_ms;
|
||||||
action->end_at_s = new_action_duration;
|
entity->action.end_at_clock_ms = DQN_MAX(duration_ms, game->clock_ms + duration_ms);
|
||||||
action->flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool FP_Game_EntityActionHasFailed(FP_GameEntityAction const *action)
|
|
||||||
{
|
|
||||||
bool result = action ? action->flags & FP_GameEntityActionFlag_Failed : true;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Dqn_V2I FP_Game_WorldPosToTilePos(FP_Game *game, Dqn_V2 world_pos)
|
static Dqn_V2I FP_Game_WorldPosToTilePos(FP_Game *game, Dqn_V2 world_pos)
|
||||||
@ -674,7 +658,6 @@ static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos)
|
|||||||
entity->type = FP_EntityType_Smoochie;
|
entity->type = FP_EntityType_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->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale;
|
entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale;
|
||||||
entity->flags |= FP_GameEntityFlag_Clickable;
|
entity->flags |= FP_GameEntityFlag_Clickable;
|
||||||
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
||||||
|
@ -60,27 +60,20 @@ struct FP_GameEntitySpawnList
|
|||||||
FP_GameEntitySpawnList *prev;
|
FP_GameEntitySpawnList *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FP_GameEntityActionFlag
|
struct FP_GameEntityActionSprite
|
||||||
{
|
|
||||||
FP_GameEntityActionFlag_StateTransition = 1 << 0,
|
|
||||||
FP_GameEntityActionFlag_Failed = 1 << 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FP_ActionToAnimationMapping
|
|
||||||
{
|
{
|
||||||
TELY_AssetSpriteSheet *sheet;
|
TELY_AssetSpriteSheet *sheet;
|
||||||
TELY_AssetSpriteAnimation anim;
|
TELY_AssetSpriteAnimation *anim;
|
||||||
};
|
};
|
||||||
|
|
||||||
Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f;
|
uint64_t const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = UINT64_MAX;
|
||||||
struct FP_GameEntityAction
|
struct FP_GameEntityAction
|
||||||
{
|
{
|
||||||
bool flip_on_x;
|
uint32_t state;
|
||||||
uint32_t state;
|
uint32_t next_state;
|
||||||
uint32_t flags; // Bit flags corresponding with `FP_GameEntityActionFlag`
|
TELY_AssetAnimatedSprite sprite;
|
||||||
FP_ActionToAnimationMapping mapping;
|
uint64_t started_at_clock_ms;
|
||||||
Dqn_f32 timer_s;
|
uint64_t end_at_clock_ms;
|
||||||
Dqn_f32 end_at_s;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FP_GameDirection
|
enum FP_GameDirection
|
||||||
@ -103,8 +96,6 @@ struct FP_GameEntity
|
|||||||
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_V2 size_scale;
|
Dqn_V2 size_scale;
|
||||||
FP_GameEntityAction action;
|
FP_GameEntityAction action;
|
||||||
Dqn_V2 velocity;
|
Dqn_V2 velocity;
|
||||||
@ -167,29 +158,26 @@ struct FP_Game
|
|||||||
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
|
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
|
||||||
Dqn_VArray<FP_GameEntity> entities;
|
Dqn_VArray<FP_GameEntity> entities;
|
||||||
|
|
||||||
TELY_AssetSpriteSheet terry_sprite_sheet;
|
TELY_AssetSpriteSheet terry_sprite_sheet;
|
||||||
Dqn_Slice<FP_ActionToAnimationMapping> terry_action_mappings;
|
TELY_AssetSpriteSheet smoochie_sprite_sheet;
|
||||||
|
TELY_AssetSpriteSheet terry_merchant_sprite_sheet;
|
||||||
|
|
||||||
TELY_AssetSpriteSheet smoochie_sprite_sheet;
|
FP_GameEntity *root_entity;
|
||||||
Dqn_Slice<FP_ActionToAnimationMapping> smoochie_action_mappings;
|
FP_GameEntity *entity_free_list;
|
||||||
|
|
||||||
TELY_AssetSpriteSheet terry_merchant_sprite_sheet;
|
FP_GameEntityHandle player;
|
||||||
Dqn_Slice<FP_ActionToAnimationMapping> terry_merchant_action_mappings;
|
|
||||||
|
|
||||||
FP_GameEntity *root_entity;
|
FP_GameEntityHandle clicked_entity;
|
||||||
FP_GameEntity *entity_free_list;
|
FP_GameEntityHandle hot_entity;
|
||||||
|
FP_GameEntityHandle active_entity;
|
||||||
|
FP_GameEntityHandle prev_clicked_entity;
|
||||||
|
FP_GameEntityHandle prev_hot_entity;
|
||||||
|
FP_GameEntityHandle prev_active_entity;
|
||||||
|
|
||||||
FP_GameEntityHandle player;
|
FP_GameCamera camera;
|
||||||
|
TELY_RFui rfui;
|
||||||
|
|
||||||
FP_GameEntityHandle clicked_entity;
|
uint64_t clock_ms;
|
||||||
FP_GameEntityHandle hot_entity;
|
|
||||||
FP_GameEntityHandle active_entity;
|
|
||||||
FP_GameEntityHandle prev_clicked_entity;
|
|
||||||
FP_GameEntityHandle prev_hot_entity;
|
|
||||||
FP_GameEntityHandle prev_active_entity;
|
|
||||||
|
|
||||||
FP_GameCamera camera;
|
|
||||||
TELY_RFui rfui;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FP_GameAStarNode
|
struct FP_GameAStarNode
|
||||||
|
Loading…
Reference in New Issue
Block a user