tely: Add idle animation for the player

This commit is contained in:
2023-09-23 21:21:08 +10:00
parent 1062e138d6
commit 1ff0daba4a
16 changed files with 244 additions and 14 deletions
+85 -13
View File
@@ -398,6 +398,68 @@ void TELY_DLL_Init(void *user_data)
DQN_MEMCPY(game->hero_sprite_anims.data, &hero_anims, sizeof(hero_anims[0]) * DQN_ARRAY_UCOUNT(hero_anims));
}
{
TELY_AssetSpriteSheet *sheet = &game->protag_walk_sprite_sheet;
Dqn_Slice<TELY_AssetSpriteAnimation> *anims = &game->protag_walk_sprite_anims;
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/protagonist_walk.png", DQN_STRING_FMT(assets->textures_dir));
sheet->tex_handle = platform->func_load_texture(assets, DQN_STRING8("Protagonist Walk"), sheet_path);
sheet->sprite_count = 28;
sheet->sprites_per_row = 7;
sheet->sprite_size = Dqn_V2I_InitNx2(185, 170);
sheet->type = TELY_AssetSpriteSheetType_Rects;
struct LoadedSprite
{
Dqn_String8 name;
Dqn_Rect rect;
};
// NOTE: Load the sprite meta file =========================================================
{
Dqn_List<LoadedSprite> raw_sprites = Dqn_List_Init<LoadedSprite>(scratch.arena, 32);
Dqn_String8 sheet_meta_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/protagonist_walk.txt", DQN_STRING_FMT(assets->textures_dir));
Dqn_String8 sheet_meta_file = Dqn_Fs_Read(sheet_meta_path, scratch.allocator);
Dqn_String8BinarySplitResult split = {};
Dqn_String8 first = sheet_meta_file;
do {
split = Dqn_String8_BinarySplit(first, DQN_STRING8("\n"));
Dqn_String8BinarySplitResult name = Dqn_String8_BinarySplit(split.lhs, DQN_STRING8(";"));
Dqn_String8BinarySplitResult x = Dqn_String8_BinarySplit(name.rhs, DQN_STRING8(";"));
Dqn_String8BinarySplitResult y = Dqn_String8_BinarySplit(x.rhs, DQN_STRING8(";"));
Dqn_String8BinarySplitResult width = Dqn_String8_BinarySplit(y.rhs, DQN_STRING8(";"));
Dqn_String8BinarySplitResult height = Dqn_String8_BinarySplit(width.rhs, DQN_STRING8(";"));
LoadedSprite *loaded_anim = Dqn_List_Make(&raw_sprites, 1);
loaded_anim->name = name.lhs;
loaded_anim->rect.pos.x = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(x.lhs, 0).value;
loaded_anim->rect.pos.y = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(y.lhs, 0).value;
loaded_anim->rect.size.w = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(width.lhs, 0).value;
loaded_anim->rect.size.h = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(height.lhs, 0).value;
first = split.rhs;
} while (first.size);
// NOTE: Populate the sheet ============================================================
sheet->rects = Dqn_Slice_Alloc<Dqn_Rect>(&platform->arena, raw_sprites.count, Dqn_ZeroMem_No);
for (Dqn_ListIterator<LoadedSprite> it = {}; Dqn_List_Iterate(&raw_sprites, &it, 0); ) {
sheet->rects.data[it.index] = it.data->rect;
}
}
TELY_AssetSpriteAnimation raw_anims[] = {
// {DQN_STRING8("Walk down"), /*index*/ 0, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
{DQN_STRING8("Walk idle"), /*index*/ 0, /*count*/ 8, /*seconds_per_frame*/ 1 / 8.f},
// {DQN_STRING8("Walk left"), /*index*/ 15, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
// {DQN_STRING8("Walk right"), /*index*/ 22, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
};
*anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(&platform->arena, DQN_ARRAY_UCOUNT(raw_anims), Dqn_ZeroMem_No);
DQN_MEMCPY(anims->data, &raw_anims, sizeof(raw_anims[0]) * DQN_ARRAY_UCOUNT(raw_anims));
}
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
game->root_entity = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle);
@@ -478,12 +540,14 @@ void TELY_DLL_Init(void *user_data)
// NOTE: Hero
{
TELY_AssetSpriteSheet *sheet = &game->protag_walk_sprite_sheet;
Dqn_Slice<TELY_AssetSpriteAnimation> anims = game->protag_walk_sprite_anims;
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Terry");
entity->local_pos = Dqn_V2_InitNx2(1334, 396);
entity->size_scale = Dqn_V2_InitNx1(4);
entity->sprite_sheet = &game->hero_sprite_sheet;
entity->sprite_anims = game->hero_sprite_anims;
entity->local_hit_box_size = Dqn_V2_InitV2I(game->hero_sprite_sheet.sprite_size);
entity->sprite_sheet = sheet;
entity->sprite_anims = anims;
entity->local_hit_box_size = Dqn_V2_InitV2I(sheet->sprite_size);
entity->flags |= FP_GameEntityFlag_Clickable;
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
entity->flags |= FP_GameEntityFlag_MoveByMouse;
@@ -540,7 +604,7 @@ void TELY_DLL_Init(void *user_data)
}
// NOTE: Mob spawner
{
if (0) {
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob spawner");
entity->local_pos = Dqn_V2_InitNx2(0, platform->core.window_size.y * .5f);
entity->flags |= FP_GameEntityFlag_Clickable;
@@ -775,7 +839,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
if (action->state == FP_GameEntityState_Idle) {
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Idle")).index;
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk idle")).index;
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, anim);
} else if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J)) {
@@ -831,7 +895,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
if (action->state == FP_GameEntityState_Run) {
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Run")).index;
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk right")).index;
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, anim);
} else if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J)) {
@@ -995,7 +1059,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
// NOTE: Render entity sprites =============================================================
if (entity->sprite_sheet && entity->action.anim) {
TELY_AssetSpriteSheet const *sprite_sheet = entity->sprite_sheet;
FP_GameEntityAction const *action = &entity->action;
TELY_AssetSpriteAnimation const *sprite_anim = action->anim;
@@ -1006,10 +1069,19 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
Dqn_usize sprite_sheet_column = sprite_index % sprite_sheet->sprites_per_row;
Dqn_Rect src_rect = {};
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.size.w = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.w;
src_rect.size.h = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.h;
switch (sprite_sheet->type) {
case TELY_AssetSpriteSheetType_Uniform: {
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.size.w = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.w;
src_rect.size.h = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.h;
} break;
case TELY_AssetSpriteSheetType_Rects: {
DQN_ASSERT(sprite_index < sprite_sheet->rects.size);
src_rect = sprite_sheet->rects.data[sprite_index];
} break;
}
Dqn_Rect dest_rect = {};
dest_rect.size = src_rect.size * entity->size_scale;
@@ -1122,7 +1194,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
}
Dqn_f32 const PHYSICS_STEP = 1 / 60.f;
for (game->delta_s_accumulator += input->delta_s;
for (game->delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s;
game->delta_s_accumulator > PHYSICS_STEP;
game->delta_s_accumulator -= PHYSICS_STEP) {
FP_Update(platform, game, renderer, input);