diff --git a/External/tely b/External/tely index 9b91e7e..1b331f9 160000 --- a/External/tely +++ b/External/tely @@ -1 +1 @@ -Subproject commit 9b91e7e1b9bb3a6eb103aeb5de457c4a56fee331 +Subproject commit 1b331f9ab37baa31b345d5be8d71a8c4c7946f87 diff --git a/feely_pona.cpp b/feely_pona.cpp index ec4a24f..74a3a67 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -192,6 +192,21 @@ void TELY_DLL_Init(void *user_data) enemy->flags |= TELY_EntityFlag_MoveByMouse; } + // NOTE: Wall + { + TELY_GameEntity *entity = TELY_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; + + TELY_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes); + wall->type = TELY_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); @@ -214,12 +229,38 @@ void TELY_Game_EntityChangeState(TELY_GameEntity *entity, TELY_GameEntityState s { if (entity->state == state) return; + entity->state = state; entity->anim.frame = 0; entity->anim.ticks = 0; + + // 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: { + } break; + + case TELY_GameEntityState_Idle: { + desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Idle")); + } break; + + case TELY_GameEntityState_Attack: { + desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Attack A")); + } break; + + case TELY_GameEntityState_Run: { + desired_sprite_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Running")); + } break; + } + + if (entity->sprite_sheet && entity->sprite_anims.size) { + TELY_AssetSpriteAnimation const *sprite_anim = entity->sprite_anims.data + entity->anim.index; + entity->anim.index = desired_sprite_anim_index; + } } -void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) +Dqn_f32 const FP_TILE_SIZE = 37.f; +void FP_GameUpdate(TELY_Platform *platform, TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput *input) { if (TELY_Platform_InputKeyIsReleased(input->mouse_left)) game->clicked_entity = game->prev_active_entity; @@ -252,6 +293,12 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput } } } + + if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) { + // NOTE: Do A* algorithm + Dqn_V2 world_pos = TELY_Game_CalcEntityWorldPos(game, player->handle); + Dqn_V2I player_tile = platform->core.window_size / FP_TILE_SIZE; + } } else { game->camera.world_pos += dir_vector * 5.f; } @@ -278,7 +325,24 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(input->delta_s); Dqn_f32 t_squared = DQN_SQUARED(t); entity->velocity = (acceleration * t) + entity->velocity * 0.82f; - entity->local_pos += (acceleration * 0.5f * t_squared) + (entity->velocity * t); + + 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 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; + if (collider->handle == entity->handle) + continue; + + // TODO(doyle): Minkowski sweep? + Dqn_Rect collider_world_hit_box = TELY_Game_CalcEntityWorldHitBox(game, collider->handle); + if (Dqn_Rect_Intersects(new_world_hit_box, collider_world_hit_box)) { + } + } } // NOTE: Move entity by mouse ============================================================== @@ -309,51 +373,36 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput entity->local_hit_box_size = padded_bbox.size; } - // NOTE: Handle animation state ============================================================ - uint16_t desired_anim_index = 0; - switch (entity->state) { - case TELY_GameEntityState_Idle: { - desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Idle")); - } break; - - case TELY_GameEntityState_Attack: { - desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Attack A")); - } break; - - case TELY_GameEntityState_Run: { - desired_anim_index = TELY_Asset_GetSpriteAnim(entity->sprite_anims, DQN_STRING8("Run")); - } break; - } - + // NOTE: Tick entity action ================================================================ { + bool action_is_done = false; TELY_AssetSpriteAnimation const *sprite_anim = entity->sprite_anims.data + entity->anim.index; - if (desired_anim_index == entity->anim.index) { // NOTE: Current anim matches, check if its finished + if (sprite_anim) { if (entity->anim.frame >= sprite_anim->count) { // NOTE: Animation is finished entity->anim.frame = 0; entity->anim.ticks = 0; - switch (entity->state) { - case TELY_GameEntityState_Idle: { - } break; - - case TELY_GameEntityState_Attack: { - entity->state = TELY_GameEntityState_Idle; - } break; - - case TELY_GameEntityState_Run: { - if (dir_vector.x == 0 && dir_vector.y == 0) { - entity->state = TELY_GameEntityState_Idle; - } - } break; - } + action_is_done = true; } else { if (entity->anim.ticks++ > 4 /*ticks_per_anim_frame*/) { entity->anim.frame++; entity->anim.ticks = 0; } } - } else { - // NOTE: Current animation does not match the desired animation, change anim - entity->anim.index = desired_anim_index; + } + + 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); + } break; + + case TELY_GameEntityState_Run: { + if (dir_vector.x == 0 && dir_vector.y == 0) + TELY_Game_EntityChangeState(entity, TELY_GameEntityState_Idle); + } break; + } } } @@ -379,13 +428,10 @@ void FP_GameUpdate(TELY_Game *game, TELY_Renderer *renderer, TELY_PlatformInput } } - // NOTE: Resolve collision ==================================================================== + // NOTE: Do attacks ============================================================================ for (TELY_GameEntityIterator attacker_it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &attacker_it, game->root_entity); ) { TELY_GameEntity *attacker = attacker_it.entity; - // NOTE: Resolve box collision - Dqn_Rect attacker_hit_box = TELY_Game_CalcEntityWorldHitBox(game, attacker->handle); - // NOTE: Resolve attack boxes if (Dqn_V2_Area(attacker->attack_box_size)) { Dqn_Rect attacker_box = TELY_Game_CalcEntityAttackWorldHitBox(game, attacker->handle); @@ -426,6 +472,23 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend Dqn_M2x3 model_view = TELY_Game_CameraModelViewM2x3(game->camera, platform); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(model_view, input->mouse_p); + // NOTE: Draw tiles ============================================================================ + Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / FP_TILE_SIZE); + Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(platform->core.window_size.h / FP_TILE_SIZE); + + for (Dqn_usize x = 0; x < tile_count_x; x++) { + Dqn_V2 start = Dqn_V2_InitNx2((x + 1) * FP_TILE_SIZE, 0); + Dqn_V2 end = Dqn_V2_InitNx2(start.x, platform->core.window_size.h); + TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f); + } + + for (Dqn_usize y = 0; y < tile_count_y; y++) { + Dqn_V2 start = Dqn_V2_InitNx2(0, (y + 1) * FP_TILE_SIZE); + Dqn_V2 end = Dqn_V2_InitNx2(platform->core.window_size.w, start.y); + TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f); + } + + // NOTE: Draw entities ========================================================================= for (TELY_GameEntityIterator it = {}; TELY_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { TELY_GameEntity *entity = it.entity; entity->alive_time_s += input->delta_s; @@ -498,14 +561,20 @@ void FP_GameRender(TELY_Game *game, TELY_Platform *platform, TELY_Renderer *rend 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); - if (game->hot_entity == entity->handle && (entity->name.size)) { - Dqn_V2 entity_world_pos = TELY_Game_CalcEntityWorldPos(game, entity->handle); + } + + 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_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8 label = Dqn_String8_InitF(scratch.allocator, - "%.*s (%.1f, %.1f)", + "%.*s (%.1f, %.1f) (%I32d, %I32d)", DQN_STRING_FMT(entity->name), entity_world_pos.x, - entity_world_pos.y); + entity_world_pos.y, + player_tile.x, + player_tile.y); TELY_Render_Text(renderer, world_mouse_p, Dqn_V2_InitNx2(0.f, 1), label); } } @@ -606,7 +675,7 @@ void TELY_DLL_FrameUpdate(void *user_data) } } - FP_GameUpdate(game, renderer, input); + FP_GameUpdate(platform, game, renderer, input); FP_GameRender(game, platform, renderer); TELY_Audio_MixPlaybackSamples(audio, assets); }