From 6d33b183647cc58cf8f715807292a10473de1681 Mon Sep 17 00:00:00 2001 From: doyle Date: Sun, 17 Sep 2023 20:24:07 +1000 Subject: [PATCH] fp: Merge TELY_Game and FP_Game --- feely_pona.cpp | 257 +++++++++++++++++++++----------------------- feely_pona.h | 143 ++++++++++++++++++++++-- feely_pona_game.cpp | 140 ++++++++++++------------ feely_pona_game.h | 171 ----------------------------- feely_pona_unity.h | 1 - 5 files changed, 328 insertions(+), 384 deletions(-) delete mode 100644 feely_pona_game.h diff --git a/feely_pona.cpp b/feely_pona.cpp index bd7997a..09ba010 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -47,12 +47,11 @@ void TELY_DLL_Init(void *user_data) // NOTE: TELY Game ============================================================================= TELY_Assets *assets = &platform->assets; - Feely_Pona *pona = Dqn_Arena_New(&platform->arena, Feely_Pona, Dqn_ZeroMem_Yes); - TELY_Game *game = &pona->game; + FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes); game->chunk_pool.arena = &platform->arena; platform->user_data = game; { - TELY_AssetSpriteSheet *sheet = &pona->hero_sprite_sheet; + TELY_AssetSpriteSheet *sheet = &game->hero_sprite_sheet; Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8 sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/adventurer-v1.5-sheet.png", DQN_STRING_FMT(assets->textures_dir)); sheet->tex_handle = platform->func_load_texture(assets, DQN_STRING8("Hero"), sheet_path); @@ -83,11 +82,11 @@ void TELY_DLL_Init(void *user_data) {DQN_STRING8("Leap slice C"), /*index*/ 103, /*count*/ 6}, }; - pona->hero_sprite_anims = Dqn_Slice_Alloc(&platform->arena, DQN_ARRAY_UCOUNT(hero_anims), Dqn_ZeroMem_No); - DQN_MEMCPY(pona->hero_sprite_anims.data, &hero_anims, sizeof(hero_anims[0]) * DQN_ARRAY_UCOUNT(hero_anims)); + game->hero_sprite_anims = Dqn_Slice_Alloc(&platform->arena, DQN_ARRAY_UCOUNT(hero_anims), Dqn_ZeroMem_No); + DQN_MEMCPY(game->hero_sprite_anims.data, &hero_anims, sizeof(hero_anims[0]) * DQN_ARRAY_UCOUNT(hero_anims)); } - game->entities = Dqn_VArray_Init(&platform->arena, 1024 * 8); + game->entities = Dqn_VArray_Init(&platform->arena, 1024 * 8); game->root_entity = Dqn_VArray_Make(&game->entities, 1, Dqn_ZeroMem_No); Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle); @@ -95,32 +94,32 @@ void TELY_DLL_Init(void *user_data) { // NOTE: Setup entity-tree ================================================================= - TELY_GameEntity *f = TELY_Game_MakeEntityPointerF(game, "F"); - TELY_Game_PushParentEntity(game, f->handle); - TELY_GameEntity *b = TELY_Game_MakeEntityPointerF(game, "B"); - TELY_GameEntity *g = TELY_Game_MakeEntityPointerF(game, "G"); - TELY_Game_PushParentEntity(game, b->handle); - TELY_GameEntity *a = TELY_Game_MakeEntityPointerF(game, "A"); - TELY_GameEntity *d = TELY_Game_MakeEntityPointerF(game, "D"); - TELY_Game_PushParentEntity(game, d->handle); - TELY_GameEntity *c = TELY_Game_MakeEntityPointerF(game, "C"); - TELY_GameEntity *e = TELY_Game_MakeEntityPointerF(game, "E"); - TELY_Game_PopParentEntity(game); - TELY_Game_PopParentEntity(game); + FP_GameEntity *f = FP_Game_MakeEntityPointerF(game, "F"); + FP_Game_PushParentEntity(game, f->handle); + FP_GameEntity *b = FP_Game_MakeEntityPointerF(game, "B"); + FP_GameEntity *g = FP_Game_MakeEntityPointerF(game, "G"); + FP_Game_PushParentEntity(game, b->handle); + FP_GameEntity *a = FP_Game_MakeEntityPointerF(game, "A"); + FP_GameEntity *d = FP_Game_MakeEntityPointerF(game, "D"); + FP_Game_PushParentEntity(game, d->handle); + FP_GameEntity *c = FP_Game_MakeEntityPointerF(game, "C"); + FP_GameEntity *e = FP_Game_MakeEntityPointerF(game, "E"); + FP_Game_PopParentEntity(game); + FP_Game_PopParentEntity(game); - TELY_Game_PushParentEntity(game, g->handle); - TELY_GameEntity *i = TELY_Game_MakeEntityPointerF(game, "I"); - TELY_Game_PushParentEntity(game, i->handle); - TELY_GameEntity *h = TELY_Game_MakeEntityPointerF(game, "H"); - TELY_Game_PopParentEntity(game); - TELY_Game_PopParentEntity(game); - TELY_Game_PopParentEntity(game); + FP_Game_PushParentEntity(game, g->handle); + FP_GameEntity *i = FP_Game_MakeEntityPointerF(game, "I"); + FP_Game_PushParentEntity(game, i->handle); + FP_GameEntity *h = FP_Game_MakeEntityPointerF(game, "H"); + FP_Game_PopParentEntity(game); + FP_Game_PopParentEntity(game); + FP_Game_PopParentEntity(game); // NOTE: Pre order test ==================================================================== - TELY_GameEntity *pre_order_walk[9] = {}; + FP_GameEntity *pre_order_walk[9] = {}; Dqn_usize pre_order_walk_count = 0; - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity);) { + for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity);) { DQN_ASSERT(pre_order_walk_count < DQN_ARRAY_UCOUNT(pre_order_walk)); pre_order_walk[pre_order_walk_count++] = it.entity; } @@ -138,9 +137,9 @@ void TELY_DLL_Init(void *user_data) // NOTE: Post order test =================================================================== - TELY_GameEntity *post_order_walk[9] = {}; + FP_GameEntity *post_order_walk[9] = {}; Dqn_usize post_order_walk_count = 0; - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity);) { + for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity);) { DQN_ASSERT(post_order_walk_count < DQN_ARRAY_UCOUNT(post_order_walk)); post_order_walk[post_order_walk_count++] = it.entity; } @@ -157,7 +156,7 @@ void TELY_DLL_Init(void *user_data) DQN_ASSERT(post_order_walk[8] == f); // NOTE: Cleanup =========================================================================== - TELY_Game_DeleteEntity(game, game->root_entity->handle); + FP_Game_DeleteEntity(game, game->root_entity->handle); DQN_ASSERT(game->root_entity->first_child == nullptr); DQN_ASSERT(game->root_entity->last_child == nullptr); DQN_ASSERT(game->root_entity->next == nullptr); @@ -167,65 +166,60 @@ void TELY_DLL_Init(void *user_data) // NOTE: Hero { - TELY_GameEntity *hero = TELY_Game_MakeEntityPointerF(game, "Hero"); + FP_GameEntity *hero = FP_Game_MakeEntityPointerF(game, "Hero"); hero->local_pos = Dqn_V2_InitNx2(100.f, 100.f); hero->size_scale = Dqn_V2_InitNx1(4); - hero->sprite_sheet = &pona->hero_sprite_sheet; - hero->sprite_anims = pona->hero_sprite_anims; - hero->local_hit_box_size = Dqn_V2_InitV2I(pona->hero_sprite_sheet.sprite_size); - hero->flags |= TELY_EntityFlag_Clickable; - hero->flags |= TELY_EntityFlag_MoveByKeyboard; - hero->flags |= TELY_EntityFlag_MoveByMouse; + hero->sprite_sheet = &game->hero_sprite_sheet; + hero->sprite_anims = game->hero_sprite_anims; + hero->local_hit_box_size = Dqn_V2_InitV2I(game->hero_sprite_sheet.sprite_size); + hero->flags |= FP_EntityFlag_Clickable; + hero->flags |= FP_EntityFlag_MoveByKeyboard; + hero->flags |= FP_EntityFlag_MoveByMouse; game->clicked_entity = hero->handle; } // NOTE: Enemy { - TELY_GameEntity *enemy = TELY_Game_MakeEntityPointerF(game, "Enemy"); + FP_GameEntity *enemy = FP_Game_MakeEntityPointerF(game, "Enemy"); enemy->local_pos = Dqn_V2_InitNx2(300.f, 300.f); enemy->size_scale = Dqn_V2_InitNx1(4); - enemy->sprite_sheet = &pona->hero_sprite_sheet; - enemy->sprite_anims = pona->hero_sprite_anims; - enemy->local_hit_box_size = Dqn_V2_InitV2I(pona->hero_sprite_sheet.sprite_size); - enemy->flags |= TELY_EntityFlag_Clickable; - enemy->flags |= TELY_EntityFlag_MoveByKeyboard; - enemy->flags |= TELY_EntityFlag_MoveByMouse; + enemy->sprite_sheet = &game->hero_sprite_sheet; + enemy->sprite_anims = game->hero_sprite_anims; + enemy->local_hit_box_size = Dqn_V2_InitV2I(game->hero_sprite_sheet.sprite_size); + enemy->flags |= FP_EntityFlag_Clickable; + enemy->flags |= FP_EntityFlag_MoveByKeyboard; + enemy->flags |= FP_EntityFlag_MoveByMouse; } // NOTE: Wall { - TELY_GameEntity *entity = TELY_Game_MakeEntityPointerF(game, "V. Wall"); + FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "V. Wall"); entity->local_pos = Dqn_V2_InitNx2(100.f, 300.f); entity->local_hit_box_size = Dqn_V2_InitNx2(100.f, 300.f); - entity->flags |= TELY_EntityFlag_Clickable; - entity->flags |= TELY_EntityFlag_MoveByKeyboard; - entity->flags |= TELY_EntityFlag_MoveByMouse; + entity->flags |= FP_EntityFlag_Clickable; + entity->flags |= FP_EntityFlag_MoveByKeyboard; + entity->flags |= FP_EntityFlag_MoveByMouse; - TELY_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes); - wall->type = TELY_GameShapeType_Rect; + FP_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes); + wall->type = FP_GameShapeType_Rect; wall->p2 = entity->local_hit_box_size; wall->colour = TELY_COLOUR_GREEN_DARK_KHAKI_V4; } uint16_t font_size = 18; game->camera.scale = Dqn_V2_InitNx1(1); - pona->inter_regular_font = platform->func_load_font(assets, DQN_STRING8("Inter (Regular)"), DQN_STRING8("Data/Inter-Regular.otf"), font_size); - pona->inter_italic_font = platform->func_load_font(assets, DQN_STRING8("Inter (Italic)"), DQN_STRING8("Data/Inter-Italic.otf"), font_size); - pona->jetbrains_mono_font = platform->func_load_font(assets, DQN_STRING8("JetBrains Mono NL (Regular)"), DQN_STRING8("Data/JetBrainsMonoNL-Regular.ttf"), font_size); - pona->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa")); + game->inter_regular_font = platform->func_load_font(assets, DQN_STRING8("Inter (Regular)"), DQN_STRING8("Data/Inter-Regular.otf"), font_size); + game->inter_italic_font = platform->func_load_font(assets, DQN_STRING8("Inter (Italic)"), DQN_STRING8("Data/Inter-Italic.otf"), font_size); + game->jetbrains_mono_font = platform->func_load_font(assets, DQN_STRING8("JetBrains Mono NL (Regular)"), DQN_STRING8("Data/JetBrainsMonoNL-Regular.ttf"), font_size); + game->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa")); // NOTE: TELY audio ============================================================================ TELY_Audio *audio = &platform->audio; audio->chunk_pool = &game->chunk_pool; - - // NOTE: TELY ui =============================================================================== - - TELY_UI *ui = &game->ui; - ui->arena.allocs_are_allowed_to_leak = true; } -void TELY_Game_EntityChangeState(TELY_GameEntity *entity, TELY_GameEntityState state) +void FP_Game_EntityChangeState(FP_GameEntity *entity, FP_GameEntityState state) { if (entity->state == state) return; @@ -237,18 +231,18 @@ void TELY_Game_EntityChangeState(TELY_GameEntity *entity, TELY_GameEntityState s // decouple the state from the animation, e.g. the wall doesn't have an animation uint16_t desired_sprite_anim_index = 0; switch (state) { - case TELY_GameEntityState_Nil: { + case FP_GameEntityState_Nil: { } break; - case TELY_GameEntityState_Idle: { + case FP_GameEntityState_Idle: { desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Idle")); } break; - case TELY_GameEntityState_Attack: { + case FP_GameEntityState_Attack: { desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Attack A")); } break; - case TELY_GameEntityState_Run: { + case FP_GameEntityState_Run: { desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Running")); } break; } @@ -366,7 +360,7 @@ Dqn_Slice AStarPathFind(Dqn_Arena *arena, TELY_Platform *platform, Dqn_ return result; } -void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) +void FP_GameUpdate(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) { if (TELY_Platform_InputKeyIsReleased(input->mouse_left)) game->clicked_entity = game->prev_active_entity; @@ -383,19 +377,19 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend if (game->clicked_entity.id) { if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Delete)) - TELY_Game_DeleteEntity(game, game->clicked_entity); + FP_Game_DeleteEntity(game, game->clicked_entity); - TELY_GameEntity *player = TELY_Game_GetEntity(game, game->clicked_entity); + FP_GameEntity *player = FP_Game_GetEntity(game, game->clicked_entity); if (player) { if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_J)) { - TELY_Game_EntityChangeState(player, TELY_GameEntityState_Attack); + FP_Game_EntityChangeState(player, FP_GameEntityState_Attack); } - if (player->state != TELY_GameEntityState_Attack) { + if (player->state != FP_GameEntityState_Attack) { if (dir_vector.x || dir_vector.y) { - TELY_Game_EntityChangeState(player, TELY_GameEntityState_Run); + FP_Game_EntityChangeState(player, FP_GameEntityState_Run); } else { - TELY_Game_EntityChangeState(player, TELY_GameEntityState_Idle); + FP_Game_EntityChangeState(player, FP_GameEntityState_Idle); } } } @@ -403,36 +397,36 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend game->camera.world_pos += dir_vector * 5.f; } - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { - TELY_GameEntity *entity = it.entity; + for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { + FP_GameEntity *entity = it.entity; entity->alive_time_s += input->delta_s; // NOTE: Move entity by keyboard =========================================================== Dqn_V2 acceleration = {}; if (game->clicked_entity == entity->handle) { - if (entity->flags & TELY_EntityFlag_MoveByKeyboard) { + if (entity->flags & FP_EntityFlag_MoveByKeyboard) { acceleration = dir_vector * 10000000.f; if (dir_vector.x) entity->facing_left = dir_vector.x < 0.f; } } - Dqn_V2 entity_world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle); + Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); if (entity->name == DQN_STRING8("Enemy")) { if (entity->handle != game->clicked_entity && entity->stalk_entity != game->clicked_entity) { entity->stalk_entity = game->clicked_entity; } - TELY_GameEntity *stalk_entity = TELY_Game_GetEntity(game, entity->stalk_entity); + FP_GameEntity *stalk_entity = FP_Game_GetEntity(game, entity->stalk_entity); if (stalk_entity) { - Dqn_V2 stalk_world_pos = TELY_Game_CalcEntityWorldPos(game, stalk_entity->handle); + Dqn_V2 stalk_world_pos = FP_Game_CalcEntityWorldPos(game, stalk_entity->handle); Dqn_V2I stalk_tile = Dqn_V2I_InitNx2(stalk_world_pos.x / FP_TILE_SIZE, stalk_world_pos.y / FP_TILE_SIZE); if (entity->stalk_entity_last_known_tile != stalk_tile) { entity->stalk_entity_last_known_tile = stalk_tile; // NOTE: Dealloc all waypoints - for (TELY_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; ) { - TELY_GameWaypoint *next = waypoint->next; + for (FP_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; ) { + FP_GameWaypoint *next = waypoint->next; TELY_ChunkPool_Dealloc(&game->chunk_pool, waypoint); waypoint = next; } @@ -443,7 +437,7 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend Dqn_Slice path_find = AStarPathFind(&platform->arena, platform, entity_tile, stalk_tile); for (Dqn_usize index = path_find.size - 1; index < path_find.size; index--) { - TELY_GameWaypoint *waypoint = TELY_ChunkPool_New(&game->chunk_pool, TELY_GameWaypoint); + FP_GameWaypoint *waypoint = TELY_ChunkPool_New(&game->chunk_pool, FP_GameWaypoint); waypoint->pos = path_find.data[index]; waypoint->next = entity->waypoints; waypoint->prev = entity->waypoints->prev; @@ -454,13 +448,13 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend } } - for (TELY_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; waypoint = waypoint->next) { + for (FP_GameWaypoint *waypoint = entity->waypoints->next; waypoint != entity->waypoints; waypoint = waypoint->next) { Dqn_V2 circle_pos = Dqn_V2_InitNx2(waypoint->pos.x * FP_TILE_SIZE + FP_TILE_SIZE * .5f, waypoint->pos.y * FP_TILE_SIZE + FP_TILE_SIZE * .5f); TELY_Render_CircleColourV4(renderer, circle_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_MAGENTA_V4); } if (entity->waypoints->next != entity->waypoints) { - TELY_GameWaypoint *waypoint = entity->waypoints->next; + FP_GameWaypoint *waypoint = entity->waypoints->next; Dqn_V2I target_tile = entity->waypoints->next->pos; Dqn_V2 target_pos = Dqn_V2_InitNx2(target_tile.x * FP_TILE_SIZE + FP_TILE_SIZE *.5f, target_tile.y * FP_TILE_SIZE + FP_TILE_SIZE * .5f); Dqn_V2 entity_to_target_pos = target_pos - entity_world_pos; @@ -487,42 +481,42 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend Dqn_V2 delta_p = (acceleration * 0.5f * t_squared) + (entity->velocity * t); entity->local_pos += delta_p; - Dqn_Rect world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, entity->handle); + Dqn_Rect world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); Dqn_Rect new_world_hit_box = world_hit_box; new_world_hit_box.pos += delta_p; - for (TELY_GameEntityIterator collider_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) { - TELY_GameEntity *collider = collider_it.entity; + for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) { + FP_GameEntity *collider = collider_it.entity; if (collider->handle == entity->handle) continue; // TODO(doyle): Minkowski sweep? - Dqn_Rect collider_world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, collider->handle); + Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle); if (Dqn_Rect_Intersects(new_world_hit_box, collider_world_hit_box)) { } } } // NOTE: Move entity by mouse ============================================================== - if (game->active_entity == entity->handle && entity->flags & TELY_EntityFlag_MoveByMouse) { - if (entity->flags & TELY_EntityFlag_MoveByMouse) { + if (game->active_entity == entity->handle && entity->flags & FP_EntityFlag_MoveByMouse) { + if (entity->flags & FP_EntityFlag_MoveByMouse) { entity->velocity = {}; entity->local_pos += input->mouse_p_delta; } } - if (entity->flags & TELY_EntityFlag_DeriveHitBoxFromChildrenBoundingBox) { + if (entity->flags & FP_EntityFlag_DeriveHitBoxFromChildrenBoundingBox) { Dqn_Rect children_bbox = {}; // TODO(doyle): Is the hit box supposed to include the containing // entity itself? Not sure - children_bbox.pos = TELY_Game_CalcEntityWorldPos(game, entity->handle); + children_bbox.pos = FP_Game_CalcEntityWorldPos(game, entity->handle); - for (TELY_GameEntityIterator child_it = {}; TELY_Game_DFSPreOrderWalkEntityTree(game, &child_it, entity);) { - TELY_GameEntity *child = child_it.entity; + for (FP_GameEntityIterator child_it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &child_it, entity);) { + FP_GameEntity *child = child_it.entity; DQN_ASSERT(child != entity); - Dqn_Rect bbox = TELY_Game_CalcEntityWorldBoundingBox(game, child->handle); + Dqn_Rect bbox = FP_Game_CalcEntityWorldBoundingBox(game, child->handle); children_bbox = Dqn_Rect_Union(children_bbox, bbox); } @@ -550,22 +544,22 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend if (action_is_done) { switch (entity->state) { - case TELY_GameEntityState_Nil: break; - case TELY_GameEntityState_Idle: break; - case TELY_GameEntityState_Attack: { - TELY_Game_EntityChangeState(entity, TELY_GameEntityState_Idle); + case FP_GameEntityState_Nil: break; + case FP_GameEntityState_Idle: break; + case FP_GameEntityState_Attack: { + FP_Game_EntityChangeState(entity, FP_GameEntityState_Idle); } break; - case TELY_GameEntityState_Run: { + case FP_GameEntityState_Run: { if (dir_vector.x == 0 && dir_vector.y == 0) - TELY_Game_EntityChangeState(entity, TELY_GameEntityState_Idle); + FP_Game_EntityChangeState(entity, FP_GameEntityState_Idle); } break; } } } // NOTE: Calculate entity attack box ======================================================= - if (entity->state == TELY_GameEntityState_Attack) { + if (entity->state == FP_GameEntityState_Attack) { entity->attack_box_size = entity->local_hit_box_size; TELY_AssetSpriteSheet const *sprite_sheet = entity->sprite_sheet; @@ -587,18 +581,18 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend } // NOTE: Do attacks ============================================================================ - for (TELY_GameEntityIterator attacker_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &attacker_it, game->root_entity); ) { - TELY_GameEntity *attacker = attacker_it.entity; + for (FP_GameEntityIterator attacker_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &attacker_it, game->root_entity); ) { + FP_GameEntity *attacker = attacker_it.entity; // NOTE: Resolve attack boxes if (Dqn_V2_Area(attacker->attack_box_size)) { - Dqn_Rect attacker_box = TELY_Game_CalcEntityAttackWorldHitBox(game, attacker->handle); - for (TELY_GameEntityIterator defender_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &defender_it, game->root_entity); ) { - TELY_GameEntity *defender = defender_it.entity; + Dqn_Rect attacker_box = FP_Game_CalcEntityAttackWorldHitBox(game, attacker->handle); + for (FP_GameEntityIterator defender_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &defender_it, game->root_entity); ) { + FP_GameEntity *defender = defender_it.entity; if (defender->handle == attacker->handle) continue; - Dqn_Rect defender_box = TELY_Game_CalcEntityWorldHitBox(game, defender->handle); + Dqn_Rect defender_box = FP_Game_CalcEntityWorldHitBox(game, defender->handle); Dqn_Rect hit_rect = Dqn_Rect_Intersection(attacker_box, defender_box); if (!Dqn_Rect_Area(hit_rect)) @@ -624,10 +618,10 @@ void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *rend } } -void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) +void FP_GameRender(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer) { TELY_PlatformInput *input = &platform->input; - Dqn_M2x3 model_view = TELY_Game_CameraModelViewM2x3(game->camera, platform); + Dqn_M2x3 model_view = FP_Game_CameraModelViewM2x3(game->camera, platform); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(model_view, input->mouse_p); // NOTE: Draw tiles ============================================================================ @@ -647,31 +641,31 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend } // NOTE: Draw entities ========================================================================= - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { - TELY_GameEntity *entity = it.entity; + for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { + FP_GameEntity *entity = it.entity; entity->alive_time_s += input->delta_s; // NOTE: Render shapes in entity =========================================================== - Dqn_V2 world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle); - for (TELY_GameShape const &shape_ : entity->shapes) { - TELY_GameShape const *shape = &shape_; + Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); + for (FP_GameShape const &shape_ : entity->shapes) { + FP_GameShape const *shape = &shape_; Dqn_V2 local_to_world_p1 = world_pos + shape->p1; Dqn_V2 local_to_world_p2 = world_pos + shape->p2; switch (shape->type) { - case TELY_GameShapeType_None: { + case FP_GameShapeType_None: { } break; - case TELY_GameShapeType_Circle: { + case FP_GameShapeType_Circle: { TELY_Render_CircleColourV4(renderer, local_to_world_p1, shape->circle_radius, shape->render_mode, shape->colour); } break; - case TELY_GameShapeType_Rect: { + case FP_GameShapeType_Rect: { Dqn_Rect rect = Dqn_Rect_InitV2x2(local_to_world_p1, local_to_world_p2 - local_to_world_p1); rect.pos -= rect.size * .5f; TELY_Render_RectColourV4(renderer, rect, shape->render_mode, shape->colour); } break; - case TELY_GameShapeType_Line: { + case FP_GameShapeType_Line: { TELY_Render_LineColourV4(renderer, local_to_world_p1, local_to_world_p2, shape->colour, shape->line_thickness); } break; } @@ -704,7 +698,7 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend // NOTE: Render attack box ================================================================= { - Dqn_Rect attack_box = TELY_Game_CalcEntityAttackWorldHitBox(game, entity->handle); + Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle); TELY_Render_RectColourV4(renderer, attack_box, TELY_RenderShapeMode_Line, TELY_COLOUR_RED_TOMATO_V4); } @@ -712,10 +706,10 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend TELY_Render_CircleColourV4(renderer, world_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_RED_TOMATO_V4); // NOTE: Render hot/active entity ========================================================== - Dqn_Rect world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, entity->handle); + Dqn_Rect world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); if (game->clicked_entity == entity->handle) { TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4); - } else if (game->hot_entity == entity->handle || (entity->flags & TELY_EntityFlag_DrawHitBox)) { + } else if (game->hot_entity == entity->handle || (entity->flags & FP_EntityFlag_DrawHitBox)) { Dqn_V4 hot_colour = game->hot_entity == entity->handle ? TELY_COLOUR_RED_TOMATO_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_YELLOW_SANDY_V4, .5f); TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, hot_colour); @@ -724,7 +718,7 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend if (game->clicked_entity == entity->handle || game->hot_entity == entity->handle) { if (entity->name.size) { Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / FP_TILE_SIZE, world_pos.y / FP_TILE_SIZE); - Dqn_V2 entity_world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle); + Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8 label = Dqn_String8_InitF(scratch.allocator, "%.*s (%.1f, %.1f) (%I32d, %I32d)", @@ -746,15 +740,10 @@ void TELY_DLL_FrameUpdate(void *user_data) TELY_PlatformInput *input = &platform->input; TELY_Assets *assets = &platform->assets; TELY_Renderer *renderer = &platform->renderer; - Feely_Pona *pona = DQN_CAST(Feely_Pona *) platform->user_data; - TELY_Game *game = &pona->game; - TELY_UI *ui = &game->ui; - - TELY_UI_FrameSetup(ui, assets, &platform->frame_arena); - TELY_UI_PushFont(ui, pona->jetbrains_mono_font); + FP_Game *game = DQN_CAST(FP_Game *) platform->user_data; TELY_Render_ClearColourV3(renderer, TELY_COLOUR_BLACK_MIDNIGHT_V4.rgb); - TELY_Render_PushFont(renderer, pona->jetbrains_mono_font); + TELY_Render_PushFont(renderer, game->jetbrains_mono_font); { Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8Builder builder = {}; @@ -797,14 +786,14 @@ void TELY_DLL_FrameUpdate(void *user_data) Dqn_FArray_Clear(&game->parent_entity_stack); Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle); - Dqn_M2x3 model_view = TELY_Game_CameraModelViewM2x3(game->camera, platform); + Dqn_M2x3 model_view = FP_Game_CameraModelViewM2x3(game->camera, platform); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(model_view, input->mouse_p); // ============================================================================================= TELY_Audio *audio = &platform->audio; if (audio->playback_size == 0) { - TELY_Audio_Play(audio, pona->test_audio, 1.f /*volume*/); + TELY_Audio_Play(audio, game->test_audio, 1.f /*volume*/); } // ============================================================================================= @@ -813,15 +802,15 @@ void TELY_DLL_FrameUpdate(void *user_data) if (game->prev_active_entity.id) game->active_entity = game->prev_active_entity; } else { - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity); ) { - TELY_GameEntity *entity = it.entity; + for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity); ) { + FP_GameEntity *entity = it.entity; if (entity->local_hit_box_size.x <= 0 || entity->local_hit_box_size.y <= 0) continue; - if ((entity->flags & TELY_EntityFlag_Clickable) == 0) + if ((entity->flags & FP_EntityFlag_Clickable) == 0) continue; - Dqn_Rect world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, entity->handle); + Dqn_Rect world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); if (!Dqn_Rect_ContainsPoint(world_hit_box, world_mouse_p)) continue; diff --git a/feely_pona.h b/feely_pona.h index aab0a86..e5b7253 100644 --- a/feely_pona.h +++ b/feely_pona.h @@ -3,13 +3,140 @@ #include "feely_pona_unity.h" #endif -struct Feely_Pona +enum FP_EntityFlag { - TELY_Game game; - TELY_AssetFontHandle inter_regular_font; - TELY_AssetFontHandle inter_italic_font; - TELY_AssetFontHandle jetbrains_mono_font; - Dqn_Slice hero_sprite_anims; - TELY_AssetSpriteSheet hero_sprite_sheet; - TELY_AssetAudioHandle test_audio; + FP_EntityFlag_Clickable = 1 << 0, + FP_EntityFlag_MoveByKeyboard = 1 << 1, + FP_EntityFlag_MoveByMouse = 1 << 2, + FP_EntityFlag_DrawHitBox = 1 << 3, + FP_EntityFlag_DeriveHitBoxFromChildrenBoundingBox = 1 << 4, +}; + +enum FP_GameShapeType +{ + FP_GameShapeType_None, + FP_GameShapeType_Circle, + FP_GameShapeType_Rect, + FP_GameShapeType_Line, +}; + +struct FP_GameShape +{ + FP_GameShapeType type; + Dqn_V2 p1; + Dqn_V2 p2; + Dqn_V4 colour; + Dqn_f32 line_thickness; + Dqn_f32 circle_radius; + TELY_RenderShapeMode render_mode; +}; + +const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MASK = 0xFFFF'0000'0000'0000; +const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT = 48; +const uint64_t FP_GAME_ENTITY_HANDLE_GENERATION_MAX = FP_GAME_ENTITY_HANDLE_GENERATION_MASK >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; + +const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MASK = 0x0000'FFFF'FFFF'FFFF; +const uint64_t FP_GAME_ENTITY_HANDLE_INDEX_MAX = FP_GAME_ENTITY_HANDLE_INDEX_MASK - 1; +struct FP_GameEntityHandle +{ + uint64_t id; +}; + +enum FP_GameEntityState +{ + FP_GameEntityState_Nil, + FP_GameEntityState_Idle, + FP_GameEntityState_Attack, + FP_GameEntityState_Run, +}; + +struct FP_GameEntityAnimation +{ + uint16_t index; + uint16_t frame; + uint16_t ticks; + uint16_t ticks_per_frame; +}; + +struct FP_GameWaypoint +{ + Dqn_V2I pos; + FP_GameWaypoint *next; + FP_GameWaypoint *prev; +}; + +struct FP_GameEntity +{ + Dqn_String8 name; + FP_GameEntityHandle handle; + TELY_AssetSpriteSheet *sprite_sheet; + Dqn_Slice sprite_anims; + Dqn_V2 size_scale; + FP_GameEntityAnimation anim; + FP_GameEntityState state; + Dqn_V2 velocity; + + FP_GameEntityHandle stalk_entity; + Dqn_V2I stalk_entity_last_known_tile; + FP_GameWaypoint *waypoints; + + // NOTE: The entity hit box is positioned at the center of the entity. + Dqn_V2 local_hit_box_size; + Dqn_V2 local_hit_box_offset; + + Dqn_V2 attack_box_size; + Dqn_V2 attack_box_offset; + + uint64_t flags; + bool facing_left; + Dqn_V2 local_pos; + Dqn_f64 alive_time_s; + Dqn_FArray shapes; + FP_GameEntity *next; + FP_GameEntity *prev; + FP_GameEntity *first_child; + FP_GameEntity *last_child; + FP_GameEntity *parent; +}; + +struct FP_GameEntityIterator +{ + bool init; + Dqn_usize iteration_count; + + FP_GameEntity *entity; + FP_GameEntity *last_visited; + + FP_GameEntity *entity_parent; + FP_GameEntity *entity_next; + FP_GameEntity *entity_first_child; +}; + +struct FP_GameCamera +{ + Dqn_V2 world_pos; + Dqn_f32 rotate_rads; + Dqn_V2 scale; +}; + +struct FP_Game +{ + TELY_ChunkPool chunk_pool; + TELY_AssetFontHandle inter_regular_font; + TELY_AssetFontHandle inter_italic_font; + TELY_AssetFontHandle jetbrains_mono_font; + TELY_AssetAudioHandle test_audio; + Dqn_Slice hero_sprite_anims; + TELY_AssetSpriteSheet hero_sprite_sheet; + Dqn_FArray parent_entity_stack; + Dqn_VArray entities; + FP_GameEntity *root_entity; + FP_GameEntity *entity_free_list; + FP_GameEntityHandle clicked_entity; + 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; }; diff --git a/feely_pona_game.cpp b/feely_pona_game.cpp index 37e2900..8da3b3a 100644 --- a/feely_pona_game.cpp +++ b/feely_pona_game.cpp @@ -3,19 +3,19 @@ #include "playground_unity.h" #endif -static bool operator==(TELY_GameEntityHandle const &lhs, TELY_GameEntityHandle const &rhs) +static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs) { bool result = lhs.id == rhs.id; return result; } -static bool operator!=(TELY_GameEntityHandle const &lhs, TELY_GameEntityHandle const &rhs) +static bool operator!=(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs) { bool result = !(lhs == rhs); return result; } -static Dqn_M2x3 TELY_Game_CameraModelViewM2x3(TELY_GameCamera camera, TELY_Platform *platform) +static Dqn_M2x3 FP_Game_CameraModelViewM2x3(FP_GameCamera camera, TELY_Platform *platform) { Dqn_M2x3 result = Dqn_M2x3_Identity(); if (platform) { @@ -28,24 +28,24 @@ static Dqn_M2x3 TELY_Game_CameraModelViewM2x3(TELY_GameCamera camera, TELY_Platf return result; } -static TELY_GameEntity *TELY_Game_GetEntity(TELY_Game *game, TELY_GameEntityHandle handle) +static FP_GameEntity *FP_Game_GetEntity(FP_Game *game, FP_GameEntityHandle handle) { - TELY_GameEntity *result = nullptr; + FP_GameEntity *result = nullptr; if (!game) return result; result = game->entities.data; - uint64_t index_from_handle = handle.id & TELY_GAME_ENTITY_HANDLE_INDEX_MASK; + uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; if (index_from_handle >= game->entities.size) return result; - TELY_GameEntity *candidate = game->entities.data + index_from_handle; + FP_GameEntity *candidate = game->entities.data + index_from_handle; if (candidate->handle == handle) result = candidate; return result; } -static bool TELY_Game_DFSPreOrderWalkEntityTree(TELY_Game *game, TELY_GameEntityIterator *it, TELY_GameEntity *root) +static bool FP_Game_DFSPreOrderWalkEntityTree(FP_Game *game, FP_GameEntityIterator *it, FP_GameEntity *root) { if (!game || !it || !root) return false; @@ -88,7 +88,7 @@ static bool TELY_Game_DFSPreOrderWalkEntityTree(TELY_Game *game, TELY_GameEntity return it->entity->handle != root->handle; } -static bool TELY_Game_DFSPostOrderWalkEntityTree(TELY_Game *game, TELY_GameEntityIterator *it, TELY_GameEntity *root) +static bool FP_Game_DFSPostOrderWalkEntityTree(FP_Game *game, FP_GameEntityIterator *it, FP_GameEntity *root) { if (!game || !it || !root) return false; @@ -149,39 +149,39 @@ static bool TELY_Game_DFSPostOrderWalkEntityTree(TELY_Game *game, TELY_GameEntit // NOTE: Parent entity -static void TELY_Game_PushParentEntity(TELY_Game *game, TELY_GameEntityHandle handle) +static void FP_Game_PushParentEntity(FP_Game *game, FP_GameEntityHandle handle) { DQN_ASSERTF(game->parent_entity_stack.size >= 1, "Sentinel/nil entity has not been assigned as the 0th slot yet"); if (game) Dqn_FArray_Add(&game->parent_entity_stack, handle); } -static void TELY_Game_PopParentEntity(TELY_Game *game) +static void FP_Game_PopParentEntity(FP_Game *game) { // NOTE: 0th slot is reserved for the nil entity if (game && game->parent_entity_stack.size > 1) Dqn_FArray_PopBack(&game->parent_entity_stack, 1); } -static TELY_GameEntityHandle TELY_Game_ActiveParentEntity(TELY_Game const *game) +static FP_GameEntityHandle FP_Game_ActiveParentEntity(FP_Game const *game) { - TELY_GameEntityHandle result = {}; + FP_GameEntityHandle result = {}; if (!game || !game->parent_entity_stack.size) return result; result = game->parent_entity_stack.data[game->parent_entity_stack.size - 1]; return result; } -static TELY_GameEntity *TELY_Game_ActiveParentEntityPointer(TELY_Game const *game) +static FP_GameEntity *FP_Game_ActiveParentEntityPointer(FP_Game const *game) { - TELY_GameEntityHandle handle = TELY_Game_ActiveParentEntity(game); - TELY_GameEntity *result = TELY_Game_GetEntity(DQN_CAST(TELY_Game *)game, handle); + FP_GameEntityHandle handle = FP_Game_ActiveParentEntity(game); + FP_GameEntity *result = FP_Game_GetEntity(DQN_CAST(FP_Game *)game, handle); return result; } -static TELY_GameEntity *TELY_Game_MakeEntityPointerFV(TELY_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +static FP_GameEntity *FP_Game_MakeEntityPointerFV(FP_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) { - TELY_GameEntity *result = nullptr; + FP_GameEntity *result = nullptr; if (!game) return result; @@ -194,24 +194,24 @@ static TELY_GameEntity *TELY_Game_MakeEntityPointerFV(TELY_Game *game, DQN_FMT_S game->entity_free_list = game->entity_free_list->next; result->next = nullptr; } else { - if (game->entities.size >= (TELY_GAME_ENTITY_HANDLE_INDEX_MAX + 1)) + if (game->entities.size >= (FP_GAME_ENTITY_HANDLE_INDEX_MAX + 1)) return result; result = Dqn_VArray_Make(&game->entities, 1, Dqn_ZeroMem_Yes); if (!result) return result; - result->handle.id = (game->entities.size - 1) & TELY_GAME_ENTITY_HANDLE_INDEX_MASK; + result->handle.id = (game->entities.size - 1) & FP_GAME_ENTITY_HANDLE_INDEX_MASK; } result->size_scale = Dqn_V2_InitNx1(1); - result->parent = TELY_Game_ActiveParentEntityPointer(game); + result->parent = FP_Game_ActiveParentEntityPointer(game); result->name = TELY_ChunkPool_AllocFmtFV(&game->chunk_pool, fmt, args); - result->waypoints = TELY_ChunkPool_New(&game->chunk_pool, TELY_GameWaypoint); + result->waypoints = TELY_ChunkPool_New(&game->chunk_pool, FP_GameWaypoint); result->waypoints->next = result->waypoints; result->waypoints->prev = result->waypoints; // NOTE: Attach entity as a child to the parent - TELY_GameEntity *parent = result->parent; + FP_GameEntity *parent = result->parent; if (parent->first_child) parent->last_child->next = result; else @@ -225,38 +225,38 @@ static TELY_GameEntity *TELY_Game_MakeEntityPointerFV(TELY_Game *game, DQN_FMT_S return result; } -static TELY_GameEntity *TELY_Game_MakeEntityPointerF(TELY_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +static FP_GameEntity *FP_Game_MakeEntityPointerF(FP_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) { va_list args; va_start(args, fmt); - TELY_GameEntity *result = TELY_Game_MakeEntityPointerFV(game, fmt, args); + FP_GameEntity *result = FP_Game_MakeEntityPointerFV(game, fmt, args); va_end(args); return result; } -static TELY_GameEntityHandle TELY_Game_MakeEntityF(TELY_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +static FP_GameEntityHandle FP_Game_MakeEntityF(FP_Game *game, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) { va_list args; va_start(args, fmt); - TELY_GameEntity *entity = TELY_Game_MakeEntityPointerF(game, fmt, args); + FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, fmt, args); va_end(args); - TELY_GameEntityHandle result = {}; + FP_GameEntityHandle result = {}; if (entity) result = entity->handle; return result; } -static bool TELY_Game_IsNilEntity(TELY_GameEntity *entity) +static bool FP_Game_IsNilEntity(FP_GameEntity *entity) { - bool result = entity ? ((entity->handle.id & TELY_GAME_ENTITY_HANDLE_INDEX_MASK) == 0) : true; + bool result = entity ? ((entity->handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK) == 0) : true; return result; } -static void TELY_Game_DetachEntityIntoFreeList(TELY_Game *game, TELY_GameEntityHandle handle) +static void FP_Game_DetachEntityIntoFreeList(FP_Game *game, FP_GameEntityHandle handle) { - TELY_GameEntity *entity = TELY_Game_GetEntity(game, handle); - if (TELY_Game_IsNilEntity(entity)) + FP_GameEntity *entity = FP_Game_GetEntity(game, handle); + if (FP_Game_IsNilEntity(entity)) return; // NOTE: Entities in the entity tree always have a parent (except for the @@ -267,11 +267,11 @@ static void TELY_Game_DetachEntityIntoFreeList(TELY_Game *game, TELY_GameEntityH if (!DQN_CHECK(entity->parent)) return; - uint64_t const entity_index_from_handle = entity->handle.id & TELY_GAME_ENTITY_HANDLE_INDEX_MASK; + uint64_t const entity_index_from_handle = entity->handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; DQN_ASSERT(entity_index_from_handle < game->entities.size); - uint64_t const entity_generation_raw = entity->handle.id & TELY_GAME_ENTITY_HANDLE_GENERATION_MASK; - uint64_t const entity_generation = entity_generation_raw >> TELY_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; + uint64_t const entity_generation_raw = entity->handle.id & FP_GAME_ENTITY_HANDLE_GENERATION_MASK; + uint64_t const entity_generation = entity_generation_raw >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; uint64_t const new_entity_generation = entity_generation + 1; // NOTE: De-attach entity from adjacent children @@ -282,7 +282,7 @@ static void TELY_Game_DetachEntityIntoFreeList(TELY_Game *game, TELY_GameEntityH entity->next->prev = entity->prev; // NOTE: De-attach from parent - TELY_GameEntity *parent = entity->parent; + FP_GameEntity *parent = entity->parent; if (parent->first_child == entity) parent->first_child = entity->next; @@ -296,7 +296,7 @@ static void TELY_Game_DetachEntityIntoFreeList(TELY_Game *game, TELY_GameEntityH // NOTE: Update the incremented handle disassociating all prior handles // to this entity which would reference older generation values *entity = {}; - entity->handle.id = entity_index_from_handle | (new_entity_generation << TELY_GAME_ENTITY_HANDLE_GENERATION_RSHIFT); + entity->handle.id = entity_index_from_handle | (new_entity_generation << FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT); // NOTE: Attach entity to the free list entity->next = game->entity_free_list; @@ -310,34 +310,34 @@ static void TELY_Game_DetachEntityIntoFreeList(TELY_Game *game, TELY_GameEntityH } } -static void TELY_Game_DeleteEntity(TELY_Game *game, TELY_GameEntityHandle handle) +static void FP_Game_DeleteEntity(FP_Game *game, FP_GameEntityHandle handle) { - uint64_t index_from_handle = handle.id & TELY_GAME_ENTITY_HANDLE_INDEX_MASK; + uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; if (!game || !DQN_CHECK(index_from_handle < game->entities.size)) return; - TELY_GameEntity *root = game->entities.data + index_from_handle; + FP_GameEntity *root = game->entities.data + index_from_handle; if (root->handle != handle) return; // NOTE: The iterator snaps a copy of all the internal n-ary tree pointers // so as we delete we do not accidentally invalidate any of the pointers. - for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, root); ) { + for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, root); ) { DQN_ASSERT(it.entity != root); - TELY_GameEntity *entity = it.entity; - TELY_Game_DetachEntityIntoFreeList(game, entity->handle); + FP_GameEntity *entity = it.entity; + FP_Game_DetachEntityIntoFreeList(game, entity->handle); } - TELY_Game_DetachEntityIntoFreeList(game, root->handle); + FP_Game_DetachEntityIntoFreeList(game, root->handle); } -static Dqn_V2 TELY_Game_CalcEntityWorldPos(TELY_Game const *game, TELY_GameEntityHandle handle) +static Dqn_V2 FP_Game_CalcEntityWorldPos(FP_Game const *game, FP_GameEntityHandle handle) { Dqn_V2 result = {}; if (!game) return result; - for (TELY_GameEntity const *entity = TELY_Game_GetEntity(DQN_CAST(TELY_Game *) game, handle); + for (FP_GameEntity const *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle); entity != game->root_entity; entity = entity->parent) { result += entity->local_pos; @@ -345,68 +345,68 @@ static Dqn_V2 TELY_Game_CalcEntityWorldPos(TELY_Game const *game, TELY_GameEntit return result; } -static Dqn_Rect TELY_Game_CalcEntityLocalHitBox(TELY_Game const *game, TELY_GameEntityHandle handle) +static Dqn_Rect FP_Game_CalcEntityLocalHitBox(FP_Game const *game, FP_GameEntityHandle handle) { - TELY_GameEntity *entity = TELY_Game_GetEntity(DQN_CAST(TELY_Game *)game, handle); + FP_GameEntity *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *)game, handle); Dqn_V2 half_hit_box_size = entity->local_hit_box_size * .5f; Dqn_Rect result = Dqn_Rect_InitV2x2(entity->local_hit_box_offset - half_hit_box_size, entity->local_hit_box_size); return result; } -static Dqn_Rect TELY_Game_CalcEntityWorldHitBox(TELY_Game const *game, TELY_GameEntityHandle handle) +static Dqn_Rect FP_Game_CalcEntityWorldHitBox(FP_Game const *game, FP_GameEntityHandle handle) { - TELY_GameEntity *entity = TELY_Game_GetEntity(DQN_CAST(TELY_Game *) game, handle); - Dqn_V2 world_pos = TELY_Game_CalcEntityWorldPos(game, handle); - Dqn_Rect local_hit_box = TELY_Game_CalcEntityLocalHitBox(game, entity->handle); + FP_GameEntity *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle); + Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, handle); + Dqn_Rect local_hit_box = FP_Game_CalcEntityLocalHitBox(game, entity->handle); Dqn_Rect result = Dqn_Rect_InitV2x2(world_pos + local_hit_box.pos, local_hit_box.size); return result; } -static Dqn_Rect TELY_Game_CalcEntityAttackWorldHitBox(TELY_Game const *game, TELY_GameEntityHandle handle) +static Dqn_Rect FP_Game_CalcEntityAttackWorldHitBox(FP_Game const *game, FP_GameEntityHandle handle) { - TELY_GameEntity *entity = TELY_Game_GetEntity(DQN_CAST(TELY_Game *) game, handle); - Dqn_V2 world_pos = TELY_Game_CalcEntityWorldPos(game, handle); + FP_GameEntity *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle); + Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, handle); Dqn_V2 half_hit_box_size = entity->attack_box_size * .5f; Dqn_Rect result = Dqn_Rect_InitV2x2(world_pos + entity->attack_box_offset - half_hit_box_size, entity->attack_box_size); return result; } -static Dqn_Rect TELY_Game_CalcEntityArrayWorldBoundingBox(TELY_Game const *game, TELY_GameEntityHandle const *handles, Dqn_usize count) +static Dqn_Rect FP_Game_CalcEntityArrayWorldBoundingBox(FP_Game const *game, FP_GameEntityHandle const *handles, Dqn_usize count) { Dqn_Rect result = {}; if (!game || !handles) return result; DQN_FOR_UINDEX(index, count) { - TELY_GameEntityHandle handle = handles[index]; - TELY_GameEntity const *entity = TELY_Game_GetEntity(DQN_CAST(TELY_Game *) game, handle); - Dqn_Rect bbox = TELY_Game_CalcEntityLocalHitBox(game, entity->handle); - for (TELY_GameShape const &shape_ : entity->shapes) { - TELY_GameShape const *shape = &shape_; + FP_GameEntityHandle handle = handles[index]; + FP_GameEntity const *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle); + Dqn_Rect bbox = FP_Game_CalcEntityLocalHitBox(game, entity->handle); + for (FP_GameShape const &shape_ : entity->shapes) { + FP_GameShape const *shape = &shape_; switch (shape->type) { - case TELY_GameShapeType_None: { + case FP_GameShapeType_None: { } break; - case TELY_GameShapeType_Circle: { + case FP_GameShapeType_Circle: { Dqn_Rect rect = Dqn_Rect_InitV2x2(shape->p1 - shape->circle_radius, Dqn_V2_InitNx1(shape->circle_radius * 2.f)); bbox = Dqn_Rect_Union(bbox, rect); } break; - case TELY_GameShapeType_Rect: /*FALLTHRU*/ - case TELY_GameShapeType_Line: { + case FP_GameShapeType_Rect: /*FALLTHRU*/ + case FP_GameShapeType_Line: { Dqn_V2 min = Dqn_V2_Min(shape->p1, shape->p2); Dqn_V2 max = Dqn_V2_Max(shape->p1, shape->p2); Dqn_Rect rect = Dqn_Rect_InitV2x2(min, max - min); - if (shape->type == TELY_GameShapeType_Rect) + if (shape->type == FP_GameShapeType_Rect) rect.pos -= rect.size * .5f; bbox = Dqn_Rect_Union(bbox, rect); } break; } } - bbox.pos += TELY_Game_CalcEntityWorldPos(game, entity->handle); + bbox.pos += FP_Game_CalcEntityWorldPos(game, entity->handle); if (index) result = Dqn_Rect_Union(result, bbox); @@ -416,8 +416,8 @@ static Dqn_Rect TELY_Game_CalcEntityArrayWorldBoundingBox(TELY_Game const *game, return result; } -static Dqn_Rect TELY_Game_CalcEntityWorldBoundingBox(TELY_Game *game, TELY_GameEntityHandle handle) +static Dqn_Rect FP_Game_CalcEntityWorldBoundingBox(FP_Game *game, FP_GameEntityHandle handle) { - Dqn_Rect result = TELY_Game_CalcEntityArrayWorldBoundingBox(game, &handle, 1); + Dqn_Rect result = FP_Game_CalcEntityArrayWorldBoundingBox(game, &handle, 1); return result; } diff --git a/feely_pona_game.h b/feely_pona_game.h deleted file mode 100644 index 6a0fa99..0000000 --- a/feely_pona_game.h +++ /dev/null @@ -1,171 +0,0 @@ -#if defined(__clang__) -#pragma once -#include "feely_pona_unity.h" -#endif - -enum TELY_EntityFlag -{ - TELY_EntityFlag_Clickable = 1 << 0, - TELY_EntityFlag_MoveByKeyboard = 1 << 1, - TELY_EntityFlag_MoveByMouse = 1 << 2, - TELY_EntityFlag_DrawHitBox = 1 << 3, - TELY_EntityFlag_DeriveHitBoxFromChildrenBoundingBox = 1 << 4, -}; - -enum TELY_GameShapeType -{ - TELY_GameShapeType_None, - TELY_GameShapeType_Circle, - TELY_GameShapeType_Rect, - TELY_GameShapeType_Line, -}; - -struct TELY_GameShape -{ - TELY_GameShapeType type; - Dqn_V2 p1; - Dqn_V2 p2; - Dqn_V4 colour; - Dqn_f32 line_thickness; - Dqn_f32 circle_radius; - TELY_RenderShapeMode render_mode; -}; - -const uint64_t TELY_GAME_ENTITY_HANDLE_GENERATION_MASK = 0xFFFF'0000'0000'0000; -const uint64_t TELY_GAME_ENTITY_HANDLE_GENERATION_RSHIFT = 48; -const uint64_t TELY_GAME_ENTITY_HANDLE_GENERATION_MAX = TELY_GAME_ENTITY_HANDLE_GENERATION_MASK >> TELY_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; - -const uint64_t TELY_GAME_ENTITY_HANDLE_INDEX_MASK = 0x0000'FFFF'FFFF'FFFF; -const uint64_t TELY_GAME_ENTITY_HANDLE_INDEX_MAX = TELY_GAME_ENTITY_HANDLE_INDEX_MASK - 1; -struct TELY_GameEntityHandle -{ - uint64_t id; -}; - -enum TELY_GameEntityState -{ - TELY_GameEntityState_Nil, - TELY_GameEntityState_Idle, - TELY_GameEntityState_Attack, - TELY_GameEntityState_Run, -}; - -struct TELY_GameEntityAnimation -{ - uint16_t index; - uint16_t frame; - uint16_t ticks; - uint16_t ticks_per_frame; -}; - -struct TELY_GameWaypoint -{ - Dqn_V2I pos; - TELY_GameWaypoint *next; - TELY_GameWaypoint *prev; -}; - -struct TELY_GameEntity -{ - Dqn_String8 name; - TELY_GameEntityHandle handle; - TELY_AssetSpriteSheet *sprite_sheet; - Dqn_Slice sprite_anims; - Dqn_V2 size_scale; - TELY_GameEntityAnimation anim; - TELY_GameEntityState state; - Dqn_V2 velocity; - - TELY_GameEntityHandle stalk_entity; - Dqn_V2I stalk_entity_last_known_tile; - TELY_GameWaypoint *waypoints; - - // NOTE: The entity hit box is positioned at the center of the entity. - Dqn_V2 local_hit_box_size; - Dqn_V2 local_hit_box_offset; - - Dqn_V2 attack_box_size; - Dqn_V2 attack_box_offset; - - uint64_t flags; - bool facing_left; - Dqn_V2 local_pos; - Dqn_f64 alive_time_s; - Dqn_FArray shapes; - TELY_GameEntity *next; - TELY_GameEntity *prev; - TELY_GameEntity *first_child; - TELY_GameEntity *last_child; - TELY_GameEntity *parent; -}; - -struct TELY_GameEntityIterator -{ - bool init; - Dqn_usize iteration_count; - - TELY_GameEntity *entity; - TELY_GameEntity *last_visited; - - TELY_GameEntity *entity_parent; - TELY_GameEntity *entity_next; - TELY_GameEntity *entity_first_child; -}; - -struct TELY_FreyaGameMath -{ - TELY_GameEntityHandle lec01_group_box; - TELY_GameEntityHandle lec01_axis; - TELY_GameEntityHandle lec01_point_a; - TELY_GameEntityHandle lec01_point_b; - - TELY_GameEntityHandle lec01_task01_group_box; - TELY_GameEntityHandle lec01_task01_radial_trigger; - Dqn_f32 lec01_task01_radial_trigger_radius; - TELY_GameEntityHandle lec01_task01_player; - - TELY_GameEntityHandle lec01_task02_group_box; - TELY_GameEntityHandle lec01_task02_ray_begin; - TELY_GameEntityHandle lec01_task02_ray_end; - TELY_GameEntityHandle lec01_task02_surface; -}; - -struct TELY_GameCamera -{ - Dqn_V2 world_pos; - Dqn_f32 rotate_rads; - Dqn_V2 scale; -}; - -struct TELY_Game -{ - TELY_Platform *platform; - TELY_RFui rfui; - TELY_UI ui; - TELY_ChunkPool chunk_pool; - TELY_AssetFontHandle inter_regular_font; - TELY_AssetFontHandle inter_italic_font; - TELY_AssetFontHandle jetbrains_mono_font; - TELY_AssetAudioHandle test_audio; - - Dqn_Slice hero_sprite_anims; - TELY_AssetSpriteSheet hero_sprite_sheet; - - Dqn_FArray parent_entity_stack; - Dqn_VArray entities; - TELY_GameEntity *root_entity; - TELY_GameEntity *entity_free_list; - - TELY_GameEntityHandle clicked_entity; - TELY_GameEntityHandle hot_entity; - TELY_GameEntityHandle active_entity; - - TELY_GameEntityHandle prev_clicked_entity; - TELY_GameEntityHandle prev_hot_entity; - TELY_GameEntityHandle prev_active_entity; - - TELY_FreyaGameMath freya_game_math; - - TELY_GameCamera camera; - -}; diff --git a/feely_pona_unity.h b/feely_pona_unity.h index 271af4b..ddbc367 100644 --- a/feely_pona_unity.h +++ b/feely_pona_unity.h @@ -62,7 +62,6 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte // NOTE: feely_pona ================================================================================ -#include "feely_pona_game.h" #include "feely_pona.h" #include "feely_pona_game.cpp"