diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 136822a1..05140942 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -325,39 +325,44 @@ namespace Nuake { ImGui::Dummy({ ImGui::GetContentRegionAvail().x / 2.0f - (76.0f / 2.0f), 8.0f }); ImGui::SameLine(); - if (Engine::IsPlayMode()) + if (Engine::IsPlayMode() && Engine::GetTimeScale() != 0.0f) { if (ImGui::Button(ICON_FA_PAUSE, ImVec2(30, 30)) || (Input::IsKeyDown(GLFW_KEY_F5))) { - Engine::ExitPlayMode(); + Engine::SetGameState(GameState::Paused); - Engine::LoadScene(SceneSnapshot); - Selection = EditorSelection(); - SetStatusMessage("Ready"); + SetStatusMessage("Paused"); } } else { if (ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30))) { - this->SceneSnapshot = Engine::GetCurrentScene()->Copy(); - - SetStatusMessage("Building .Net solution..."); - auto job = [this]() - { - ScriptingEngineNet::Get().BuildProjectAssembly(Engine::GetProject()); - }; - - Selection = EditorSelection(); - - JobSystem::Get().Dispatch(job, [this]() + if (Engine::GetGameState() == GameState::Paused) { - SetStatusMessage("Entering play mode..."); - Engine::EnterPlayMode(); + Engine::SetGameState(GameState::Playing); + } + else + { + this->SceneSnapshot = Engine::GetCurrentScene()->Copy(); - std::string statusMessage = ICON_FA_RUNNING + std::string(" Playing..."); - SetStatusMessage(statusMessage.c_str(), { 97.0 / 255.0, 0, 1, 1}); - }); + SetStatusMessage("Building .Net solution..."); + auto job = [this]() + { + ScriptingEngineNet::Get().BuildProjectAssembly(Engine::GetProject()); + }; + + Selection = EditorSelection(); + + JobSystem::Get().Dispatch(job, [this]() + { + SetStatusMessage("Entering play mode..."); + Engine::EnterPlayMode(); + + std::string statusMessage = ICON_FA_RUNNING + std::string(" Playing..."); + SetStatusMessage(statusMessage.c_str(), { 97.0 / 255.0, 0, 1, 1 }); + }); + } } if (ImGui::BeginItemTooltip()) @@ -1954,7 +1959,7 @@ namespace Nuake { ImVec2 work_area_size = ImGui::GetCurrentWindow()->Size; ImVec2 window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE)); ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); - ImGui::SetNextWindowPos(window_pos + ImVec2(0, 36), ImGuiCond_Always, window_pos_pivot); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowViewport(viewport->ID); } ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index 2cbe34a5..ae89eaed 100644 --- a/Nuake/Engine.cpp +++ b/Nuake/Engine.cpp @@ -15,16 +15,19 @@ namespace Nuake { + + Ref Engine::s_CurrentProject; Ref Engine::s_CurrentWindow; - bool Engine::s_IsPlayMode = false; + GameState Engine::s_GameState = GameState::Stopped; float Engine::s_LastFrameTime = 0.0f; float Engine::s_FixedUpdateRate = 1.0f / 90.0f; float Engine::s_FixedUpdateDifference = 0.f; float Engine::s_Time = 0.f; Timestep Engine::s_TimeStep = 0.f; + float Engine::s_TimeScale = 1.0f; void Engine::Init() { @@ -48,14 +51,15 @@ namespace Nuake s_LastFrameTime = s_Time; // Dont update if no scene is loaded. - if (s_CurrentWindow->GetScene()) + if (s_CurrentWindow->GetScene() && GetGameState() == GameState::Playing) { - s_CurrentWindow->Update(s_TimeStep); + float scaledTimeStep = s_TimeStep * s_TimeScale; + s_CurrentWindow->Update(scaledTimeStep); // Play mode update all the entities, Editor does not. if (!Engine::IsPlayMode()) { - GetCurrentScene()->EditorUpdate(s_TimeStep); + GetCurrentScene()->EditorUpdate(scaledTimeStep); } s_FixedUpdateDifference += s_TimeStep; @@ -63,7 +67,7 @@ namespace Nuake // Fixed update while (s_FixedUpdateDifference >= s_FixedUpdateRate) { - s_CurrentWindow->FixedUpdate(s_FixedUpdateRate); + s_CurrentWindow->FixedUpdate(s_FixedUpdateRate * s_TimeScale); s_FixedUpdateDifference -= s_FixedUpdateRate; } @@ -77,7 +81,7 @@ namespace Nuake s_LastFrameTime = (float)glfwGetTime();; // Reset timestep timer. // Dont trigger init if already in player mode. - if (IsPlayMode()) + if (s_GameState == GameState::Playing) { Logger::Log("Cannot enter play mode if is already in play mode.", "engine", WARNING); return; @@ -85,7 +89,7 @@ namespace Nuake if (GetCurrentScene()->OnInit()) { - s_IsPlayMode = true; + s_GameState = GameState::Playing; } else { @@ -97,11 +101,11 @@ namespace Nuake void Engine::ExitPlayMode() { // Dont trigger exit if already not in play mode. - if (IsPlayMode()) + if (s_GameState == GameState::Playing) { GetCurrentScene()->OnExit(); Input::ShowMouse(); - s_IsPlayMode = false; + s_GameState = GameState::Stopped; } } diff --git a/Nuake/Engine.h b/Nuake/Engine.h index 73804048..eb149701 100644 --- a/Nuake/Engine.h +++ b/Nuake/Engine.h @@ -12,6 +12,13 @@ // Welcome to the Nuake source code. namespace Nuake { + enum GameState + { + Playing, + Paused, + Stopped + }; + class Engine { private: @@ -19,14 +26,14 @@ namespace Nuake static Ref s_CurrentProject; static Ref s_CurrentScene; - static bool s_IsPlayMode; + static GameState s_GameState; static float s_LastFrameTime; static float s_FixedUpdateRate; static float s_FixedUpdateDifference; static float s_Time; static Timestep s_TimeStep; - + static float s_TimeScale; public: static void Init(); // Initialize the engine. static void Tick(); // Updates everything, called every frame. @@ -39,10 +46,14 @@ namespace Nuake static void Draw(); // Start new frame static void EndDraw(); // Swap buffer - static bool IsPlayMode() { return s_IsPlayMode; } + static void SetGameState(GameState gameState) { s_GameState = gameState; } + static GameState GetGameState() { return s_GameState; } + static bool IsPlayMode() { return s_GameState == GameState::Playing; } static inline float GetTime() { return s_Time; } static inline Timestep GetTimestep() { return s_TimeStep; } + static inline void SetTimeScale(float timeScale) { s_TimeScale = timeScale; } + static inline float GetTimeScale() { return s_TimeScale; } static Ref GetCurrentWindow();