diff --git a/Data/Textures/atlas.png b/Data/Textures/atlas.png index dd1eb97..b68c307 100644 --- a/Data/Textures/atlas.png +++ b/Data/Textures/atlas.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f25c65541654b96e2e3942aa1ac45b670940487c7d388c699c49fc6884f03ee -size 14756150 +oid sha256:1123b9d2d9202ce98919e445fc4aab7ae821ebe16485e24c0d3695cc875cc503 +size 15439150 diff --git a/Data/Textures/atlas.txt b/Data/Textures/atlas.txt index 6ed1e5a..8227dc7 100644 --- a/Data/Textures/atlas.txt +++ b/Data/Textures/atlas.txt @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cfbacdb431bd35e6e435d0282b9619b208f4565cb7c4ba63795dc4e700ad0b2 -size 14082 +oid sha256:60ef08c75c9f5a877e887ab4ea723859e5283fe57343fe86fa31218d73ee54fa +size 14169 diff --git a/Data/Textures/atlas/intro_screen_perry_joins_the_fight.png b/Data/Textures/atlas/intro_screen_perry_joins_the_fight.png new file mode 100644 index 0000000..4cdce96 --- /dev/null +++ b/Data/Textures/atlas/intro_screen_perry_joins_the_fight.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e44545bf42ca5dbe45598ac6321175eef113eb635cfad0a477f7cfd88fb9d091 +size 418960 diff --git a/Data/Textures/sprite_spec.txt b/Data/Textures/sprite_spec.txt index 8079793..712af29 100644 --- a/Data/Textures/sprite_spec.txt +++ b/Data/Textures/sprite_spec.txt @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20660032328425a538cfbb94dd6b83e74708c55489473ec27d5dc050f21a8cf1 -size 2230 +oid sha256:62d78af7a85007ab5eabd9078f9461018fca76b0484f1ea2d48a17d221e645f5 +size 2268 diff --git a/feely_pona.cpp b/feely_pona.cpp index 605ce88..476e111 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -124,9 +124,10 @@ static bool FP_ListenForNewPlayer(TELY_PlatformInput *input, FP_Game *game) if (keyboard_pressed || gamepad_pressed) { FP_GameEntityHandle terry_handle = {}; if (play->players.size) { - FP_GameEntityHandle player = play->players.data[play->players.size - 1]; - Dqn_V2 player_pos = FP_Game_CalcEntityWorldPos(game, player); - terry_handle = FP_Entity_CreatePerry(game, player_pos, "Perry"); + FP_GameEntityHandle player = play->players.data[play->players.size - 1]; + Dqn_V2 player_pos = FP_Game_CalcEntityWorldPos(game, player); + terry_handle = FP_Entity_CreatePerry(game, player_pos, "Perry"); + game->play.perry_joined = FP_GamePerryJoins_Enters; } else { terry_handle = FP_Entity_CreateTerry(game, Dqn_V2_InitNx2(1380, 11), "Perry"); } @@ -1294,9 +1295,9 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate); game->play.update_counter++; - game->play.clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f); Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop); - if (game->play.state == FP_GameState_Play) { + if (game->play.state == FP_GameState_Play && game->play.perry_joined != FP_GamePerryJoins_Enters) { + game->play.clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f); DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_DISABLE(4127) // Conditional expression is constant 'FP_DEVELOPER_MODE' @@ -2176,6 +2177,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input game->play.state = FP_GameState_LoseGame; } + game->play.global_camera_trauma01 = DQN_MAX(0.f, game->play.global_camera_trauma01 - 0.05f); + // NOTE: Camera ================================================================================ FP_GamePlay *play = &game->play; @@ -2261,6 +2264,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, // NOTE: The heart shake is trauma^3 to emphasise the severity of losing heart health FP_GameEntity *heart = FP_Game_GetEntity(game, game->play.heart); trauma01 = DQN_MAX(trauma01, DQN_SQUARED(heart->trauma01) * heart->trauma01); + trauma01 = DQN_MAX(trauma01, DQN_SQUARED(game->play.global_camera_trauma01)); // NOTE: Calculate camera position based on camera shake Dqn_f32 max_shake_dist = 400.f; @@ -2273,7 +2277,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, shake_camera.world_pos += shake_offset * interp_rate; } - FP_GameCameraM2x3 camera_xforms = FP_Game_CameraModelViewM2x3(shake_camera); TELY_Render_PushTransform(renderer, camera_xforms.model_view); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p); @@ -2681,6 +2684,81 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, } } + // NOTE: Draw perry ============================================================================ + if (game->play.perry_joined == FP_GamePerryJoins_Enters) { + TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); + DQN_DEFER { TELY_Render_PopTransform(renderer); }; + + // NOTE: Shake the world =================================================================== + + Dqn_Rect window_rect = {}; + window_rect.size = Dqn_V2_InitV2I(platform->core.window_size); + + Dqn_f32 tex_scalar = {}; + { + TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.intro_screen_terry); + Dqn_Rect tex_rect = game->atlas_sprite_sheet.rects.data[anim->index]; + Dqn_f32 desired_width = window_rect.size.x * .25f; + tex_scalar = desired_width / tex_rect.size.w; + } + + game->play.perry_join_bg_alpha += (1.f - game->play.perry_join_bg_alpha) * (DQN_CAST(Dqn_f32)input->delta_s * 8.f); + game->play.perry_join_bg_alpha = DQN_MIN(game->play.perry_join_bg_alpha, .8f); + TELY_Render_RectColourV4(renderer, + window_rect, + TELY_RenderShapeMode_Fill, + TELY_Colour_V4Alpha(TELY_COLOUR_BLACK_V4, game->play.perry_join_bg_alpha)); + + if (game->play.perry_join_bg_alpha > 0.5f) { + if (!game->play.perry_join_splash_screen_shake_triggered) { + game->play.global_camera_trauma01 = 1.f; + game->play.perry_join_splash_screen_shake_triggered = true; + game->play.perry_join_flash_alpha = 1.f; + game->play.perry_join_splash_screen_end_ms = DQN_CAST(uint64_t)((DQN_CAST(Dqn_f32)input->timer_s * 1000.f) + 2000); + } + } + + if (game->play.perry_join_splash_screen_shake_triggered) { + game->play.perry_join_flash_alpha -= game->play.perry_join_bg_alpha * (DQN_CAST(Dqn_f32)input->delta_s * 4.f); + game->play.perry_join_flash_alpha = DQN_MAX(game->play.perry_join_flash_alpha, .0f); + TELY_Render_RectColourV4(renderer, + window_rect, + TELY_RenderShapeMode_Fill, + TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, game->play.perry_join_flash_alpha)); + + TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.intro_screen_perry_joins_the_fight); + Dqn_Rect tex_rect = game->atlas_sprite_sheet.rects.data[anim->index]; + + Dqn_f32 sin_t = (DQN_SINF(DQN_CAST(Dqn_f32)input->timer_s * 3.f) + 1) / 2.f; + Dqn_Rect dest_rect = {}; + dest_rect.size = tex_rect.size * (tex_scalar * 1.5f) + (tex_rect.size * (0.005f * sin_t)); + dest_rect.pos = Dqn_Rect_InterpolatedPoint(window_rect, Dqn_V2_InitNx2(1, 1)) - dest_rect.size; + + Dqn_f32 max_shake_dist = 50.f; + Dqn_f32 half_shake_dist = max_shake_dist * .5f; + Dqn_V2 shake_offset = {}; + shake_offset.x = (Dqn_PCG32_NextF32(&game->play.rng) * max_shake_dist - half_shake_dist) * game->play.global_camera_trauma01; + shake_offset.y = (Dqn_PCG32_NextF32(&game->play.rng) * max_shake_dist - half_shake_dist) * game->play.global_camera_trauma01; + dest_rect.pos += shake_offset; + + if ((input->timer_s * 1000) > (game->play.perry_join_splash_screen_end_ms)) { + game->play.perry_join_splash_pos_offset.x -= dest_rect.size.x * (12.f * DQN_CAST(Dqn_f32)input->delta_s); + dest_rect.pos += game->play.perry_join_splash_pos_offset; + if (dest_rect.pos.x < -dest_rect.size.x) + game->play.perry_joined = FP_GamePerryJoins_PostEnter; + } + + TELY_Render_TextureColourV4(renderer, + game->atlas_sprite_sheet.tex_handle, + tex_rect, + dest_rect, + Dqn_V2_Zero /*rotate origin*/, + 0.f /*rotation*/, + TELY_COLOUR_WHITE_V4); + + } + } + // NOTE: Render overlay UI ===================================================================== if (!game->play.debug_hide_hud && (game->play.state == FP_GameState_Pause || game->play.state == FP_GameState_Play)) { @@ -3519,6 +3597,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, 0.f /*rotation*/, TELY_COLOUR_WHITE_V4); } + } else { // NOTE: Draw end screen logo ====================================================== TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.end_screen); diff --git a/feely_pona.h b/feely_pona.h index d9e15ab..0c5f8fb 100644 --- a/feely_pona.h +++ b/feely_pona.h @@ -58,10 +58,11 @@ struct FP_GlobalAnimations Dqn_String8 icon_phone = DQN_STRING8("icon_phone"); Dqn_String8 icon_stamina = DQN_STRING8("icon_stamina"); - Dqn_String8 intro_screen_arrows = DQN_STRING8("intro_screen_arrows"); - Dqn_String8 intro_screen_subtitle = DQN_STRING8("intro_screen_subtitle"); - Dqn_String8 intro_screen_terry = DQN_STRING8("intro_screen_terry"); - Dqn_String8 intro_screen_title = DQN_STRING8("intro_screen_title"); + Dqn_String8 intro_screen_arrows = DQN_STRING8("intro_screen_arrows"); + Dqn_String8 intro_screen_subtitle = DQN_STRING8("intro_screen_subtitle"); + Dqn_String8 intro_screen_terry = DQN_STRING8("intro_screen_terry"); + Dqn_String8 intro_screen_title = DQN_STRING8("intro_screen_title"); + Dqn_String8 intro_screen_perry_joins_the_fight = DQN_STRING8("intro_screen_perry_joins_the_fight"); Dqn_String8 kennel_terry = DQN_STRING8("kennel_terry"); diff --git a/feely_pona_game.h b/feely_pona_game.h index f6170b8..49f1f92 100644 --- a/feely_pona_game.h +++ b/feely_pona_game.h @@ -342,6 +342,13 @@ enum FP_GameState FP_GameState_LoseGame, }; +enum FP_GamePerryJoined +{ + FP_GamePerryJoins_NotYet, + FP_GamePerryJoins_Enters, + FP_GamePerryJoins_PostEnter, +}; + struct FP_GamePlay { TELY_ChunkPool *chunk_pool; @@ -392,7 +399,15 @@ struct FP_GamePlay uint32_t enemies_spawned_this_wave; uint64_t wave_cooldown_timestamp_ms; + Dqn_f32 global_camera_trauma01; FP_GameState state; + FP_GamePerryJoined perry_joined; + Dqn_f32 perry_join_bg_alpha; + Dqn_f32 perry_join_flash_alpha; + bool perry_join_splash_screen_shake_triggered; + Dqn_V2 perry_join_splash_screen_pos; + uint64_t perry_join_splash_screen_end_ms; + Dqn_V2 perry_join_splash_pos_offset; }; struct FP_Game