diff --git a/Editor/src/EditorLayer.cpp b/Editor/src/EditorLayer.cpp index c3566b9b..1b388f1d 100644 --- a/Editor/src/EditorLayer.cpp +++ b/Editor/src/EditorLayer.cpp @@ -3,6 +3,8 @@ #include "Windows/EditorInterface.h" #include "Misc/GizmoDrawer.h" +#include "src/Core/Input.h" + #include @@ -65,6 +67,8 @@ void EditorLayer::OnUpdate() m_EditorInterface->Update(Nuake::Engine::GetTimestep()); Nuake::Engine::EndDraw(); + + Nuake::Input::Update(); } void EditorLayer::OnDetach() diff --git a/Editor/src/NewEditor.cpp b/Editor/src/NewEditor.cpp index 0dbc2f2d..35d8bb0f 100644 --- a/Editor/src/NewEditor.cpp +++ b/Editor/src/NewEditor.cpp @@ -31,7 +31,7 @@ namespace Nuake bool dragging2 = false; void NewEditor::Update(Timestep ts) { - if (Input::IsKeyPressed(GLFW_KEY_F1)) + if (Input::IsKeyPressed(Key::F1)) { m_UserInterface->Reload(); FetchNodes(); diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index e9333064..a10fdae3 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -324,39 +324,47 @@ namespace Nuake { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2)); ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0)); - if (Engine::IsPlayMode()) - { - if (ImGui::Button(ICON_FA_PAUSE, ImVec2(30, 30)) || (Input::IsKeyDown(GLFW_KEY_F5))) - { - Engine::ExitPlayMode(); + ImGui::Dummy({ ImGui::GetContentRegionAvail().x / 2.0f - (76.0f / 2.0f), 8.0f }); + ImGui::SameLine(); - Engine::LoadScene(SceneSnapshot); - Selection = EditorSelection(); - SetStatusMessage("Ready"); + if (Engine::IsPlayMode() && Engine::GetTimeScale() != 0.0f) + { + if (ImGui::Button(ICON_FA_PAUSE, ImVec2(30, 30)) || (Input::IsKeyPressed(Key::F6))) + { + Engine::SetGameState(GameState::Paused); + + SetStatusMessage("Paused"); } } else { - if (ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30))) + if (ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30)) || Input::IsKeyPressed(Key::F5)) { - 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()) @@ -374,7 +382,7 @@ namespace Nuake { ImGui::BeginDisabled(); } - if ((ImGui::Button(ICON_FA_STOP, ImVec2(30, 30)) || Input::IsKeyPressed(GLFW_KEY_F5)) && Engine::IsPlayMode()) + if ((ImGui::Button(ICON_FA_STOP, ImVec2(30, 30)) || Input::IsKeyPressed(Key::F5)) && Engine::IsPlayMode()) { Engine::ExitPlayMode(); @@ -1953,7 +1961,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 @@ -1961,17 +1969,17 @@ namespace Nuake { if (ImGui::Begin("Example: Simple overlay", &m_ShowOverlay, window_flags)) { ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100); - if (ImGui::Button(ICON_FA_ARROWS_ALT) || Input::IsKeyDown(GLFW_KEY_W)) + if (ImGui::Button(ICON_FA_ARROWS_ALT) || Input::IsKeyDown(Key::W)) { CurrentOperation = ImGuizmo::OPERATION::TRANSLATE; } ImGui::SameLine(); - if (ImGui::Button(ICON_FA_SYNC_ALT) || Input::IsKeyDown(GLFW_KEY_E)) + if (ImGui::Button(ICON_FA_SYNC_ALT) || Input::IsKeyDown(Key::E)) { CurrentOperation = ImGuizmo::OPERATION::ROTATE; } ImGui::SameLine(); - if (ImGui::Button(ICON_FA_EXPAND_ALT) || Input::IsKeyDown(GLFW_KEY_R)) + if (ImGui::Button(ICON_FA_EXPAND_ALT) || Input::IsKeyDown(Key::R)) { CurrentOperation = ImGuizmo::OPERATION::SCALE; } @@ -2382,13 +2390,13 @@ namespace Nuake { editorCam->Update(ts, m_IsHoveringViewport && m_IsViewportFocused); const bool entityIsSelected = Selection.Type == EditorSelectionType::Entity && Selection.Entity.IsValid(); - if (editorCam->IsFlying() && entityIsSelected && Input::IsKeyPressed(GLFW_KEY_F)) + if (editorCam->IsFlying() && entityIsSelected && Input::IsKeyPressed(Key::F)) { editorCam->IsMoving = true; editorCam->TargetPos = Selection.Entity.GetComponent().GetGlobalPosition(); } - if (entityIsSelected && Input::IsKeyPressed(GLFW_KEY_ESCAPE)) + if (entityIsSelected && Input::IsKeyPressed(Key::ESCAPE)) { Selection = EditorSelection(); } diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index 2cbe34a5..73c095f3 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,13 +67,15 @@ 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; } + + Input::Update(); } - Input::Update(); + } void Engine::EnterPlayMode() @@ -77,7 +83,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 +91,7 @@ namespace Nuake if (GetCurrentScene()->OnInit()) { - s_IsPlayMode = true; + s_GameState = GameState::Playing; } else { @@ -97,11 +103,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(); diff --git a/Nuake/src/Core/Input.cpp b/Nuake/src/Core/Input.cpp index 81166c4f..bda51eef 100644 --- a/Nuake/src/Core/Input.cpp +++ b/Nuake/src/Core/Input.cpp @@ -22,29 +22,27 @@ namespace Nuake #pragma region Keys // Only true if the key is currently being pressed - bool Input::IsKeyDown(int keycode) + bool Input::IsKeyDown(Key keycode) { auto window = Window::Get()->GetHandle(); - int state = glfwGetKey(window, keycode); + int state = glfwGetKey(window, (int)keycode); bool result = state == GLFW_PRESS; - m_Keys[keycode] = state; - return result; } // Only true if the key is pressed for the first frame. no repeat. - bool Input::IsKeyPressed(int keycode) + bool Input::IsKeyPressed(Key keycode) { auto window = Window::Get()->GetHandle(); - int state = glfwGetKey(window, keycode); + int state = glfwGetKey(window, (int)keycode); bool result = state == GLFW_PRESS; // First time pressed? - if (m_Keys.find(keycode) == m_Keys.end() || m_Keys[keycode] == false) + if (m_Keys.find((int)keycode) == m_Keys.end() || m_Keys[(int)keycode] == false) { if (result) - m_Keys[keycode] = true; + m_Keys[(int)keycode] = true; return result; } @@ -172,7 +170,7 @@ namespace Nuake // Reset all input to false. for (auto& k : m_Keys) { - if (!IsKeyDown(k.first)) + if (!IsKeyDown((Key)k.first)) { k.second = false; } diff --git a/Nuake/src/Core/Input.h b/Nuake/src/Core/Input.h index d83b937c..4629c9b5 100644 --- a/Nuake/src/Core/Input.h +++ b/Nuake/src/Core/Input.h @@ -138,8 +138,8 @@ namespace Nuake static bool m_MouseButtons[5]; static std::map m_Keys; public: - static bool IsKeyPressed(int keycode); - static bool IsKeyDown(int keycode); + static bool IsKeyPressed(Key keycode); + static bool IsKeyDown(Key keycode); static bool IsKeyReleased(int keycode); static float YScroll; diff --git a/Nuake/src/Scene/EditorCamera.cpp b/Nuake/src/Scene/EditorCamera.cpp index 6f007b0c..e27cea4e 100644 --- a/Nuake/src/Scene/EditorCamera.cpp +++ b/Nuake/src/Scene/EditorCamera.cpp @@ -61,7 +61,7 @@ namespace Nuake Input::HideMouse(); } - if (Input::IsKeyDown(GLFW_KEY_LEFT_ALT)) + if (Input::IsKeyDown(Key::LEFT_ALT)) { if (Input::YScroll != 0.0f) { @@ -96,31 +96,31 @@ namespace Nuake if (m_Type == CAMERA_TYPE::ORTHO) { - if (Input::IsKeyDown(GLFW_KEY_RIGHT)) + if (Input::IsKeyDown(Key::RIGHT)) Translation.x += Speed * ts; - if (Input::IsKeyDown(GLFW_KEY_LEFT)) + if (Input::IsKeyDown(Key::LEFT)) Translation.x -= Speed * ts; - if (Input::IsKeyDown(GLFW_KEY_UP)) + if (Input::IsKeyDown(Key::UP)) Translation.y += Speed * ts; - if (Input::IsKeyDown(GLFW_KEY_DOWN)) + if (Input::IsKeyDown(Key::DOWN)) Translation.y -= Speed * ts; } else { auto movement = Vector3(0, 0, 0); - if (Input::IsKeyDown(GLFW_KEY_D)) + if (Input::IsKeyDown(Key::D)) movement -= Right * (Speed * ts); - if (Input::IsKeyDown(GLFW_KEY_A)) + if (Input::IsKeyDown(Key::A)) movement += Right * (Speed * ts); - if (Input::IsKeyDown(GLFW_KEY_W)) + if (Input::IsKeyDown(Key::W)) movement += Direction * (Speed * ts); - if (Input::IsKeyDown(GLFW_KEY_S)) + if (Input::IsKeyDown(Key::S)) movement -= Direction * (Speed * ts); - if (Input::IsKeyDown(GLFW_KEY_LEFT_SHIFT)) + if (Input::IsKeyDown(Key::LEFT_SHIFT)) movement -= Up * (Speed * ts); - if (Input::IsKeyDown(GLFW_KEY_SPACE)) + if (Input::IsKeyDown(Key::SPACE)) movement += Up * (Speed * ts); Translation += Vector3(movement); diff --git a/Nuake/src/Scripting/Modules/InputModule.h b/Nuake/src/Scripting/Modules/InputModule.h index 64784d1c..bfc43123 100644 --- a/Nuake/src/Scripting/Modules/InputModule.h +++ b/Nuake/src/Scripting/Modules/InputModule.h @@ -69,14 +69,14 @@ namespace Nuake { static void IsKeyDown(WrenVM* vm) { int key = (int)wrenGetSlotDouble(vm, 1); - bool result = Input::IsKeyDown(key); + bool result = Input::IsKeyDown((Key)key); wrenSetSlotBool(vm, 0, result); } static void IsKeyPressed(WrenVM* vm) { int key = (int)wrenGetSlotDouble(vm, 1); - bool result = Input::IsKeyPressed(key); + bool result = Input::IsKeyPressed((Key)key); wrenSetSlotBool(vm, 0, result); } diff --git a/Nuake/src/Scripting/NetModules/InputNetAPI.cpp b/Nuake/src/Scripting/NetModules/InputNetAPI.cpp index 20a2a866..013f9727 100644 --- a/Nuake/src/Scripting/NetModules/InputNetAPI.cpp +++ b/Nuake/src/Scripting/NetModules/InputNetAPI.cpp @@ -25,12 +25,12 @@ namespace Nuake { bool IsKeyDown(int keyCode) { - return Input::IsKeyDown(keyCode); + return Input::IsKeyDown((Key)keyCode); } bool IsKeyPressed(int keyCode) { - return Input::IsKeyPressed(keyCode); + return Input::IsKeyPressed((Key)keyCode); } Coral::Array GetMousePosition()