diff --git a/Engine/Editor/CMakeLists.txt b/Engine/Editor/CMakeLists.txt index b1e15e18f..f8bc6d29a 100644 --- a/Engine/Editor/CMakeLists.txt +++ b/Engine/Editor/CMakeLists.txt @@ -78,6 +78,8 @@ target_precompile_headers(Editor PRIVATE + + diff --git a/Engine/Editor/private/EditorECS/ecsEditor.cpp b/Engine/Editor/private/EditorECS/ecsEditor.cpp index 2a6515ebc..095502725 100644 --- a/Engine/Editor/private/EditorECS/ecsEditor.cpp +++ b/Engine/Editor/private/EditorECS/ecsEditor.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -25,10 +25,14 @@ namespace GameEngine::EntitySystem::EditorECS } }); - world.system() - .each([&](flecs::entity e, Position& position, CameraPtr& camera, const Speed& speed) + world.system() + .each([&](flecs::entity e, CameraPtr& cameraPtr, const Speed& speed) { - if (!Core::g_MainWindowsApplication->IsMouseCaptured() || !Core::g_MainWindowsApplication->IsFocused()) [[unlikely]] + static const CameraManagerPtr* cameraManagerPtr = world.get(); + + if (cameraPtr.ptr != cameraManagerPtr->ptr->GetActiveCamera() || + !Core::g_MainWindowsApplication->IsMouseCaptured() || + !Core::g_MainWindowsApplication->IsFocused()) [[unlikely]] { return; } @@ -38,29 +42,30 @@ namespace GameEngine::EntitySystem::EditorECS mouseMovement.dx *= 0.25 * (Math::Constants::PI / 180.f); mouseMovement.dy *= 0.25 * (Math::Constants::PI / 180.f); - camera.ptr->Rotate(mouseMovement.dx, mouseMovement.dy); + Core::Camera* camera = cameraManagerPtr->ptr->GetActiveCamera(); + + camera->Rotate(mouseMovement.dx, mouseMovement.dy); Math::Vector3f currentMoveDir = Math::Vector3f::Zero(); if (Core::InputHandler::GetInstance()->IsKeyPressed(Core::KeyboardButton::A)) { - currentMoveDir = currentMoveDir - camera.ptr->GetRightDir(); + currentMoveDir = currentMoveDir - camera->GetRightDir(); } if (Core::InputHandler::GetInstance()->IsKeyPressed(Core::KeyboardButton::D)) { - currentMoveDir = currentMoveDir + camera.ptr->GetRightDir(); + currentMoveDir = currentMoveDir + camera->GetRightDir(); } if (Core::InputHandler::GetInstance()->IsKeyPressed(Core::KeyboardButton::S)) { - currentMoveDir = currentMoveDir - camera.ptr->GetViewDir(); + currentMoveDir = currentMoveDir - camera->GetViewDir(); } if (Core::InputHandler::GetInstance()->IsKeyPressed(Core::KeyboardButton::W)) { - currentMoveDir = currentMoveDir + camera.ptr->GetViewDir(); + currentMoveDir = currentMoveDir + camera->GetViewDir(); } - position.x = position.x + currentMoveDir.Normalized().x * speed.value * world.delta_time(); - position.y = position.y + currentMoveDir.Normalized().y * speed.value * world.delta_time(); - position.z = position.z + currentMoveDir.Normalized().z * speed.value * world.delta_time(); - camera.ptr->SetPosition(Math::Vector3f(position.x, position.y, position.z)); + + Math::Vector3f position = camera->GetPosition() + currentMoveDir.Normalized() * speed.value * world.delta_time(); + camera->SetPosition(position); }); } }; diff --git a/Engine/Editor/private/GameEditor.cpp b/Engine/Editor/private/GameEditor.cpp index b8f38aa9e..e00438915 100644 --- a/Engine/Editor/private/GameEditor.cpp +++ b/Engine/Editor/private/GameEditor.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -18,9 +18,7 @@ namespace GameEngine ) : PlatformLoop(PlatformLoopFunc) { - Core::g_MainCamera = new Core::Camera(); - Core::g_MainCamera->SetPosition(Math::Vector3f(0.0f, 12.0f, -10.0f)); - Core::g_MainCamera->SetViewDir(Math::Vector3f(0.0f, -6.0f, 12.0f)); + Core::g_CameraManager = std::make_unique(); GUI::GUIContext::GetInstance()->PlatformInit(); m_renderThread = std::make_unique(); @@ -31,10 +29,11 @@ namespace GameEngine flecs::world world; world = m_EntityManager->GetWorld().get_world(); // huge refactoring requires or flecs custom fix because this api redundancy is just annoying + m_EntityManager->GetWorld().set(EntitySystem::EditorECS::CameraManagerPtr{ Core::g_CameraManager.get() }); + flecs::entity camera = m_EntityManager->GetWorld().entity() - .set(EntitySystem::EditorECS::Position{ 0.0f, 12.0f, -10.0f }) - .set(EntitySystem::EditorECS::Speed{ 10.f }) - .set(EntitySystem::EditorECS::CameraPtr{ Core::g_MainCamera }); + .set(EntitySystem::EditorECS::CameraPtr{ Core::g_CameraManager->CreateCamera() }) + .set(EntitySystem::EditorECS::Speed{ 10.f }); EntitySystem::EditorECS::RegisterEditorEcsControlSystems(m_EntityManager->GetWorld()); diff --git a/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.cpp b/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.cpp index b12ba322c..c4e682d76 100644 --- a/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.cpp +++ b/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.cpp @@ -1,28 +1,43 @@ #include -namespace -{ - void ParsePosition( - const GameEngine::EntitySystem::LevelEditorECS::PositionDesc& positionDesc, - GameEngine::EntitySystem::EditorECS::Position& position - ) - { - assert(positionDesc.value); - assert(std::ranges::count(*positionDesc.value, ',') == 2); - const char* compValue = positionDesc.value->c_str(); +namespace GameEngine { + Math::Vector3f ParseStringToFloat3(const World::LevelObject::ComponentDesc& componentDesc) { + + assert(std::ranges::count(componentDesc, ',') == 2); + + Math::Vector3f vec = Math::Vector3f::Zero(); + + const char* compValue = componentDesc.c_str(); char* end; float f = std::strtof(compValue, &end); - position.x = f; + vec.x = f; compValue = end + 1; f = std::strtof(compValue, &end); - position.y = f; + vec.y = f; compValue = end + 1; f = std::strtof(compValue, &end); - position.z = f; + vec.z = f; + + return vec; + } +} + +namespace +{ + void ParsePosition( + const GameEngine::EntitySystem::LevelEditorECS::PositionDesc& positionDesc, + GameEngine::EntitySystem::EditorECS::Position& position + ) + { + assert(positionDesc.value); + GameEngine::Math::Vector3f vecPos = GameEngine::ParseStringToFloat3(*positionDesc.value); + position.x = vecPos.x; + position.y = vecPos.y; + position.z = vecPos.z; } } diff --git a/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.h b/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.h index 85961e209..8be4e66c4 100644 --- a/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.h +++ b/Engine/Editor/private/LevelEditor/ECS/ecsLevelEditor.h @@ -4,13 +4,19 @@ #include #include +#include -namespace GameEngine::EntitySystem::LevelEditorECS -{ - struct PositionDesc - { - const World::LevelObject::ComponentDesc* value; - }; +namespace GameEngine { + Math::Vector3f ParseStringToFloat3(const World::LevelObject::ComponentDesc& componentDesc); + + namespace EntitySystem::LevelEditorECS { + + struct PositionDesc + { + const World::LevelObject::ComponentDesc* value; + }; + + void RegisterLevelEditorEcsSystems(flecs::world& world); + } - void RegisterLevelEditorEcsSystems(flecs::world& world); } \ No newline at end of file diff --git a/Engine/Editor/private/LevelEditor/LevelEditor.cpp b/Engine/Editor/private/LevelEditor/LevelEditor.cpp index 08367b2c8..9cd8df795 100644 --- a/Engine/Editor/private/LevelEditor/LevelEditor.cpp +++ b/Engine/Editor/private/LevelEditor/LevelEditor.cpp @@ -15,46 +15,15 @@ namespace GameEngine { LevelEditor::LevelEditor(flecs::world& world) { + m_World = world.get_world(); m_Level = LevelSerializer::Deserialize(Core::g_FileSystem->GetFilePath("Levels/Main.xml").generic_string()); for (World::LevelObject& levelObject : m_Level->GetLevelObjects()) { - flecs::entity entity = world.entity(levelObject.GetName().c_str()); - - World::LevelObject::ComponentList& componentList = levelObject.GetComponents(); - - World::LevelObject::ComponentList::iterator positionAttribute = std::ranges::find_if(componentList, - [](World::LevelObject::Component& component) - { - return !std::strcmp(component.first.c_str(), "Position"); - } - ); - - World::LevelObject::ComponentList::iterator geometryAttribute = std::ranges::find_if(componentList, - [](World::LevelObject::Component& component) - { - return !std::strcmp(component.first.c_str(), "GeometryPtr"); - } - ); - - if (positionAttribute != componentList.end() && - geometryAttribute != componentList.end()) - { - assert(World::WorldParser::GetCustomComponents().contains(geometryAttribute->second)); - - entity.set(EntitySystem::LevelEditorECS::PositionDesc{ &positionAttribute->second }); - - // Can be set to 0 since it doesn't matter now, will be updated by the system - entity.set(EntitySystem::EditorECS::Position{ 0.0f, 0.0f, 0.0f }); - entity.set(GeometryPtr{ - reinterpret_cast( - World::WorldParser::GetCustomComponents()[geometryAttribute->second] - ) - }); - } + AddLevelEditorEntity(levelObject); } - EntitySystem::LevelEditorECS::RegisterLevelEditorEcsSystems(world); + EntitySystem::LevelEditorECS::RegisterLevelEditorEcsSystems(m_World); } void LevelEditor::Draw() @@ -67,15 +36,36 @@ namespace GameEngine { if (ImGui::TreeNode(levelObject.GetName().c_str())) { + static const std::set VECTOR3_COMPONENTS = { + "Position", "Velocity", "Gravity", + }; for (World::LevelObject::Component& component : levelObject.GetComponents()) { - ImGui::InputText(component.first.c_str(), &component.second); + if (VECTOR3_COMPONENTS.contains(component.first)) + { + Math::Vector3f vec = ParseStringToFloat3(component.second); + + float arrayPos[3] = { vec.x, vec.y, vec.z }; + ImGui::InputFloat3(component.first.c_str(), arrayPos); + component.second = + std::to_string(arrayPos[0]) + "," + + std::to_string(arrayPos[1]) + "," + + std::to_string(arrayPos[2]); + } + else + { + ImGui::InputText(component.first.c_str(), &component.second); + } } ImGui::TreePop(); } } } + if (ImGui::Button("Add Default Object")) + { + AddDefaultObject(); + } if (ImGui::Button("Save")) { @@ -109,5 +99,71 @@ namespace GameEngine assert(m_Level.has_value()); LevelSerializer::Serialize(Core::g_FileSystem->GetFilePath("Levels/Main.xml").generic_string(), m_Level.value()); } + + void LevelEditor::AddDefaultObject() + { + if (!m_Level.has_value()) + { + return; + } + + std::string baseName = "NewObject1"; + std::string objectName = baseName; + uint16_t counter = 1; + + World::Level::LevelObjectList& objects = m_Level.value().GetLevelObjects(); + while ( std::ranges::find_if(objects, [&](const World::LevelObject& obj) { return obj.GetName() == objectName; }) != objects.end() ) { + objectName = baseName + std::to_string(++counter); + } + + World::LevelObject newLevelObject; + newLevelObject.SetName(objectName.c_str()); + newLevelObject.AddComponent("Position", "0.0,0.0,0.0"); + newLevelObject.AddComponent("Velocity", "0.0,0.0,0.0"); + newLevelObject.AddComponent("Gravity", "0.0,-9.8,0.0"); + newLevelObject.AddComponent("BouncePlane", "0.0,1.0,0.0,5.0"); + newLevelObject.AddComponent("Bounciness", "1.0"); + newLevelObject.AddComponent("GeometryPtr", "Cube"); + + m_Level.value().AddLevelObject(newLevelObject); + AddLevelEditorEntity(m_Level.value().GetLevelObjects().back()); + } + + void LevelEditor::AddLevelEditorEntity(World::LevelObject& levelObject) + { + flecs::entity entity = m_World.entity(levelObject.GetName().c_str()); + + World::LevelObject::ComponentList& componentList = levelObject.GetComponents(); + + World::LevelObject::ComponentList::iterator positionAttribute = std::ranges::find_if(componentList, + [](World::LevelObject::Component& component) + { + return !std::strcmp(component.first.c_str(), "Position"); + } + ); + + World::LevelObject::ComponentList::iterator geometryAttribute = std::ranges::find_if(componentList, + [](World::LevelObject::Component& component) + { + return !std::strcmp(component.first.c_str(), "GeometryPtr"); + } + ); + + if (positionAttribute != componentList.end() && + geometryAttribute != componentList.end()) + { + assert(World::WorldParser::GetCustomComponents().contains(geometryAttribute->second)); + + entity.set(EntitySystem::LevelEditorECS::PositionDesc{ &positionAttribute->second }); + + // Can be set to 0 since it doesn't matter now, will be updated by the system + entity.set(EntitySystem::EditorECS::Position{ 0.0f, 0.0f, 0.0f }); + entity.set(GeometryPtr{ + reinterpret_cast( + World::WorldParser::GetCustomComponents()[geometryAttribute->second] + ) + }); + } + } } } \ No newline at end of file diff --git a/Engine/Editor/public/EditorECS/ecsEditor.h b/Engine/Editor/public/EditorECS/ecsEditor.h index 82974e366..023a48dd5 100644 --- a/Engine/Editor/public/EditorECS/ecsEditor.h +++ b/Engine/Editor/public/EditorECS/ecsEditor.h @@ -4,11 +4,18 @@ namespace GameEngine::Core { + class CameraManager; class Camera; + } namespace GameEngine::EntitySystem::EditorECS { + struct CameraManagerPtr + { + Core::CameraManager* ptr; + }; + struct CameraPtr { Core::Camera* ptr; diff --git a/Engine/Editor/public/LevelEditor/LevelEditor.h b/Engine/Editor/public/LevelEditor/LevelEditor.h index 6607f8b8f..288332804 100644 --- a/Engine/Editor/public/LevelEditor/LevelEditor.h +++ b/Engine/Editor/public/LevelEditor/LevelEditor.h @@ -22,6 +22,8 @@ namespace GameEngine private: void Save(); + void AddDefaultObject(); + void AddLevelEditorEntity(World::LevelObject& levelObject); private: Core::Timer m_SaveButtonMessageTimer; @@ -29,6 +31,7 @@ namespace GameEngine float m_TimeToShowSaveButtonMessage = 3.f; std::optional m_Level = std::nullopt; + flecs::world m_World; }; } } \ No newline at end of file diff --git a/Engine/Source/Core/CMakeLists.txt b/Engine/Source/Core/CMakeLists.txt index 140177e59..6f5593fad 100644 --- a/Engine/Source/Core/CMakeLists.txt +++ b/Engine/Source/Core/CMakeLists.txt @@ -108,4 +108,8 @@ target_precompile_headers(Core + + + + ) \ No newline at end of file diff --git a/Engine/Source/Core/private/Camera.cpp b/Engine/Source/Core/private/Camera.cpp index f094e6e2b..6a0fd5ae1 100644 --- a/Engine/Source/Core/private/Camera.cpp +++ b/Engine/Source/Core/private/Camera.cpp @@ -2,8 +2,6 @@ namespace GameEngine::Core { - Camera* g_MainCamera = nullptr; - Math::Matrix4x4f Camera::GetViewMatrix() { return Math::ViewMatrixLH(m_Position, m_ViewDir, Math::Vector3f(0.0f, 1.0f, 0.0f)); diff --git a/Engine/Source/Core/private/CameraManager.cpp b/Engine/Source/Core/private/CameraManager.cpp new file mode 100644 index 000000000..fbc094b51 --- /dev/null +++ b/Engine/Source/Core/private/CameraManager.cpp @@ -0,0 +1,114 @@ +#include + +namespace GameEngine::Core +{ + std::unique_ptr g_CameraManager = nullptr; + + Camera* CameraManager::CreateCamera() + { + Camera* newCamera = new Camera(); + newCamera->SetPosition(startCameraPosition); + newCamera->SetViewDir(startCameraViewDir); + + AddCamera(newCamera); + return newCamera; + } + + void CameraManager::AddCamera(Camera* camera) + { + if (m_CurrCameraIt == m_CameraList.end()) + { + m_CameraList.push_back(std::unique_ptr(camera)); + m_CurrCameraIt = std::prev(m_CameraList.end()); + return; + } + + m_CurrCameraIt = m_CameraList.insert(std::next(m_CurrCameraIt), std::unique_ptr(camera)); + } + + Camera* CameraManager::GetActiveCamera() + { + assert(m_CurrCameraIt != m_CameraList.end()); + return m_CurrCameraIt->get(); + } + + void CameraManager::SetActiveCamera(Camera* camera) + { + It newCameraIt = FindIterator(camera); + + if (newCameraIt == m_CameraList.end()) + { + return; + } + + m_CurrCameraIt = newCameraIt; + } + + void CameraManager::SwitchNextCamera() + { + if (m_CameraList.empty()) + { + return; + } + + ++m_CurrCameraIt; + + if (m_CurrCameraIt == m_CameraList.end()) + { + m_CurrCameraIt = m_CameraList.begin(); + } + } + + void CameraManager::SwitchPrevCamera() + { + if (m_CameraList.empty()) + { + return; + } + + if (m_CurrCameraIt == m_CameraList.begin()) + { + m_CurrCameraIt = std::prev(m_CameraList.end()); + } + else + { + --m_CurrCameraIt; + } + } + + void CameraManager::DeleteCamera(Camera* camera) + { + It forDelCameraIt = FindIterator(camera); + + if (forDelCameraIt == m_CameraList.end()) + { + return; + } + + if (m_CurrCameraIt == forDelCameraIt) + { + if (GetCamerasCount() == 1) + { + m_CurrCameraIt = m_CameraList.end(); + } + else + { + SwitchNextCamera(); + } + } + m_CameraList.erase(forDelCameraIt); + } + + CameraManager::It CameraManager::FindIterator(Camera* camera) + { + It it = std::find_if( + m_CameraList.begin(), + m_CameraList.end(), + [&](const Camera::Ptr& p) + { + return p.get() == camera; + } + ); + return it; + } +} \ No newline at end of file diff --git a/Engine/Source/Core/private/Input/Buttons.cpp b/Engine/Source/Core/private/Input/Buttons.cpp index 5910a73eb..2e5440882 100644 --- a/Engine/Source/Core/private/Input/Buttons.cpp +++ b/Engine/Source/Core/private/Input/Buttons.cpp @@ -12,6 +12,12 @@ namespace GameEngine::Core {"w", KeyboardButton::W}, {"s", KeyboardButton::S}, {"d", KeyboardButton::D}, + {"q", KeyboardButton::Q}, + {"e", KeyboardButton::E}, + {"c", KeyboardButton::C}, + {"f", KeyboardButton::F}, + {"t", KeyboardButton::T}, + {"r", KeyboardButton::R}, {"spacebar", KeyboardButton::SPACEBAR}, {"f2", KeyboardButton::F2} }; diff --git a/Engine/Source/Core/private/Input/Controller.cpp b/Engine/Source/Core/private/Input/Controller.cpp index d58b9341c..7aa9a202f 100644 --- a/Engine/Source/Core/private/Input/Controller.cpp +++ b/Engine/Source/Core/private/Input/Controller.cpp @@ -45,4 +45,30 @@ namespace GameEngine::Core return false; } + + bool Controller::WasPressed(const std::string& event) + { + if (m_MouseEventMap.contains(event)) + { + return InputHandler::GetInstance()->WasKeyPressed(m_MouseEventMap[event]); + } + if (m_KeyboardEventMap.contains(event)) + { + return InputHandler::GetInstance()->WasKeyPressed(m_KeyboardEventMap[event]); + } + + return false; + } + + void Controller::SetWasPressed(const std::string& event) + { + if (m_MouseEventMap.contains(event)) + { + InputHandler::GetInstance()->SetWasKeyPressed(m_MouseEventMap[event]); + } + if (m_KeyboardEventMap.contains(event)) + { + InputHandler::GetInstance()->SetWasKeyPressed(m_KeyboardEventMap[event]); + } + } } \ No newline at end of file diff --git a/Engine/Source/Core/private/Input/InputHandler.cpp b/Engine/Source/Core/private/Input/InputHandler.cpp index 1395fbca0..08a10f741 100644 --- a/Engine/Source/Core/private/Input/InputHandler.cpp +++ b/Engine/Source/Core/private/Input/InputHandler.cpp @@ -30,7 +30,17 @@ namespace GameEngine::Core return; } - m_PressedButtons.set(static_cast(kb), true); + m_PressedButtons.set(2 * static_cast(kb), true); + } + + void InputHandler::SetWasKeyPressed(KeyboardButton kb) + { + if (kb == KeyboardButton::UNKNOWN) [[unlikely]] + { + return; + } + + m_PressedButtons.set(2 * static_cast(kb) + 1, true); } void InputHandler::KeyReleased(KeyboardButton kb) @@ -41,7 +51,8 @@ namespace GameEngine::Core return; } - m_PressedButtons.set(static_cast(kb), false); + m_PressedButtons.set(2 * static_cast(kb), false); + m_PressedButtons.set(2 * static_cast(kb) + 1, false); } void InputHandler::KeyPressed(MouseButton mb) @@ -52,7 +63,17 @@ namespace GameEngine::Core return; } - m_PressedButtons.set(KeyboardButtonCount + static_cast(mb), true); + m_PressedButtons.set(2 * KeyboardButtonCount + 2 * static_cast(mb), true); + } + + void InputHandler::SetWasKeyPressed(MouseButton mb) + { + if (mb == MouseButton::UNKNOWN) [[unlikely]] + { + return; + } + + m_PressedButtons.set(2 * KeyboardButtonCount + 2 * static_cast(mb) + 1, true); } void InputHandler::KeyReleased(MouseButton mb) @@ -63,19 +84,32 @@ namespace GameEngine::Core return; } - m_PressedButtons.set(KeyboardButtonCount + static_cast(mb), false); + m_PressedButtons.set(2 * KeyboardButtonCount + 2 * static_cast(mb), false); + m_PressedButtons.set(2 * KeyboardButtonCount + 2 * static_cast(mb) + 1, false); } bool InputHandler::IsKeyPressed(KeyboardButton kb) const { assert(kb != KeyboardButton::UNKNOWN); - return m_PressedButtons.test(static_cast(kb)); + return m_PressedButtons.test(2 * static_cast(kb)); } bool InputHandler::IsKeyPressed(MouseButton mb) const { assert(mb != MouseButton::UNKNOWN); - return m_PressedButtons.test(KeyboardButtonCount + static_cast(mb)); + return m_PressedButtons.test(2 * KeyboardButtonCount + 2 * static_cast(mb)); + } + + bool InputHandler::WasKeyPressed(KeyboardButton kb) const + { + assert(kb != KeyboardButton::UNKNOWN); + return m_PressedButtons.test(2 * static_cast(kb) + 1); + } + + bool InputHandler::WasKeyPressed(MouseButton mb) const + { + assert(mb != MouseButton::UNKNOWN); + return m_PressedButtons.test(2 * KeyboardButtonCount + 2 * static_cast(mb) + 1); } void InputHandler::OnMouseMove(float dx, float dy) diff --git a/Engine/Source/Core/private/Input/Windows/WindowsKeyboardButtons.h b/Engine/Source/Core/private/Input/Windows/WindowsKeyboardButtons.h index 369e8b91d..e64f0f5b1 100644 --- a/Engine/Source/Core/private/Input/Windows/WindowsKeyboardButtons.h +++ b/Engine/Source/Core/private/Input/Windows/WindowsKeyboardButtons.h @@ -26,6 +26,18 @@ namespace GameEngine return KeyboardButton::W; case 'D': return KeyboardButton::D; + case 'Q': + return KeyboardButton::Q; + case 'E': + return KeyboardButton::E; + case 'C': + return KeyboardButton::C; + case 'F': + return KeyboardButton::F; + case 'T': + return KeyboardButton::T; + case 'R': + return KeyboardButton::R; case VK_SPACE: return KeyboardButton::SPACEBAR; case VK_F2: diff --git a/Engine/Source/Core/public/Camera.h b/Engine/Source/Core/public/Camera.h index 78bc5a304..d7225bf6a 100644 --- a/Engine/Source/Core/public/Camera.h +++ b/Engine/Source/Core/public/Camera.h @@ -11,6 +11,8 @@ namespace GameEngine class CORE_API Camera final { public: + using Ptr = std::unique_ptr; + Camera() = default; public: @@ -27,7 +29,5 @@ namespace GameEngine Math::Vector3f m_Position; Math::Vector3f m_ViewDir; }; - - extern CORE_API Camera* g_MainCamera; } } \ No newline at end of file diff --git a/Engine/Source/Core/public/CameraManager.h b/Engine/Source/Core/public/CameraManager.h new file mode 100644 index 000000000..c05868344 --- /dev/null +++ b/Engine/Source/Core/public/CameraManager.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +namespace GameEngine +{ + namespace Core + { + class CORE_API CameraManager final + { + public: + using CameraList = std::list; + using It = CameraList::iterator; + + CameraManager() + : m_CurrCameraIt(m_CameraList.end()) {} + + CameraManager(const CameraManager&) = delete; + CameraManager& operator=(const CameraManager&) = delete; + + CameraManager(CameraManager&&) = default; + CameraManager& operator=(CameraManager&&) = default; + + public: + Camera* CreateCamera(); + void DeleteCamera(Camera* camera); + Camera* GetActiveCamera(); + void SwitchNextCamera(); + void SwitchPrevCamera(); + void SetActiveCamera(Camera* camera); + size_t GetCamerasCount() const { return m_CameraList.size(); } + + private: + void AddCamera(Camera* camera); + It FindIterator(Camera* camera); + + private: + CameraList m_CameraList; + It m_CurrCameraIt; + + inline static Math::Vector3f startCameraPosition = Math::Vector3f(0.0f, 12.0f, -10.0f); + inline static Math::Vector3f startCameraViewDir = Math::Vector3f(0.0f, -6.0f, 12.0f); + }; + + extern CORE_API std::unique_ptr g_CameraManager; + } +} \ No newline at end of file diff --git a/Engine/Source/Core/public/Input/Buttons.h b/Engine/Source/Core/public/Input/Buttons.h index edb51e3b2..016d816f2 100644 --- a/Engine/Source/Core/public/Input/Buttons.h +++ b/Engine/Source/Core/public/Input/Buttons.h @@ -12,6 +12,12 @@ namespace GameEngine S, W, D, + Q, + E, + C, + F, + T, + R, UP, DOWN, LEFT, diff --git a/Engine/Source/Core/public/Input/Controller.h b/Engine/Source/Core/public/Input/Controller.h index 399a317c6..d71cda3bb 100644 --- a/Engine/Source/Core/public/Input/Controller.h +++ b/Engine/Source/Core/public/Input/Controller.h @@ -17,6 +17,8 @@ namespace GameEngine public: bool IsPressed(const std::string& event); + bool WasPressed(const std::string& event); + void SetWasPressed(const std::string& event); private: std::unordered_map m_KeyboardEventMap; diff --git a/Engine/Source/Core/public/Input/InputHandler.h b/Engine/Source/Core/public/Input/InputHandler.h index fdd7fc759..5a2d7af09 100644 --- a/Engine/Source/Core/public/Input/InputHandler.h +++ b/Engine/Source/Core/public/Input/InputHandler.h @@ -30,11 +30,15 @@ namespace GameEngine::Core void Update(float dt); void KeyPressed(KeyboardButton kb); + void SetWasKeyPressed(KeyboardButton mb); void KeyReleased(KeyboardButton kb); void KeyPressed(MouseButton kb); + void SetWasKeyPressed(MouseButton mb); void KeyReleased(MouseButton mb); bool IsKeyPressed(KeyboardButton kb) const; bool IsKeyPressed(MouseButton mb) const; + bool WasKeyPressed(KeyboardButton kb) const; + bool WasKeyPressed(MouseButton mb) const; void OnMouseMove(float dx, float dy); const MouseMovevement& GetMouseMovement() const { return m_MouseMovevement; } @@ -42,9 +46,11 @@ namespace GameEngine::Core private: MouseMovevement m_MouseMovevement; + // First half of the bitset is for "is pressed" states, second half is for "was pressed" states + // [ KB_pressed[0] KB_was_pressed[0] KB_pressed[1] KB_was_pressed[1] ... MB_pressed[0] MB_was_pressed[0] MB_pressed[1] MB_was_pressed[1] ... ] std::bitset< - KeyboardButtonCount + - MouseButtonCount + 2 * KeyboardButtonCount + + 2 * MouseButtonCount > m_PressedButtons; static InputHandler* m_Instance; diff --git a/Engine/Source/Game/private/Game.cpp b/Engine/Source/Game/private/Game.cpp index 030fcc352..f5ee6b72e 100644 --- a/Engine/Source/Game/private/Game.cpp +++ b/Engine/Source/Game/private/Game.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -12,9 +12,7 @@ namespace GameEngine ) : PlatformLoop(PlatformLoopFunc) { - Core::g_MainCamera = new Core::Camera(); - Core::g_MainCamera->SetPosition(Math::Vector3f(0.0f, 12.0f, -10.0f)); - Core::g_MainCamera->SetViewDir(Math::Vector3f(0.0f, -6.0f, 12.0f)); + Core::g_CameraManager = std::make_unique(); m_renderThread = std::make_unique(); diff --git a/Engine/Source/RenderEngine/private/RenderEngine.cpp b/Engine/Source/RenderEngine/private/RenderEngine.cpp index 1af3a97b3..e80a1f32e 100644 --- a/Engine/Source/RenderEngine/private/RenderEngine.cpp +++ b/Engine/Source/RenderEngine/private/RenderEngine.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -169,7 +169,7 @@ namespace GameEngine::Render assert(materialID != RenderObject::k_invalidMaterialID); // Projection and view matrices should be a part of Camera class - Math::Matrix4x4f view = Core::g_MainCamera->GetViewMatrix(); + Math::Matrix4x4f view = Core::g_CameraManager->GetActiveCamera()->GetViewMatrix(); Math::Matrix4x4f proj = Math::ProjectionMatrixLH(0.25f * Math::Constants::PI, Core::g_MainWindowsApplication->GetAspectRatio(), 1.0f, 1000.0f); Math::Vector3f position = renderObject->GetPosition(frame); diff --git a/Engine/Source/World/CMakeLists.txt b/Engine/Source/World/CMakeLists.txt index 07f44f994..4a8bfe97d 100644 --- a/Engine/Source/World/CMakeLists.txt +++ b/Engine/Source/World/CMakeLists.txt @@ -62,6 +62,7 @@ target_precompile_headers(World PRIVATE + diff --git a/Engine/Source/World/public/Level.h b/Engine/Source/World/public/Level.h index f172aa868..a74f1b99d 100644 --- a/Engine/Source/World/public/Level.h +++ b/Engine/Source/World/public/Level.h @@ -9,7 +9,7 @@ namespace GameEngine::World class WORLD_API Level final { public: - using LevelObjectList = std::vector; + using LevelObjectList = std::list; public: Level() = delete; diff --git a/Samples/SimpleScene/Assets/Configs/Input_default.ini b/Samples/SimpleScene/Assets/Configs/Input_default.ini index af01be52c..c32cf667f 100644 --- a/Samples/SimpleScene/Assets/Configs/Input_default.ini +++ b/Samples/SimpleScene/Assets/Configs/Input_default.ini @@ -3,4 +3,10 @@ GoLeft=a GoRight=d GoForward=w GoBack=s -Jump=spacebar \ No newline at end of file +Jump=spacebar +CreateCamera=c +DeleteCamera=f +NextCamera=e +PrevCamera=q +SaveCamera=t +LoadCamera=r \ No newline at end of file diff --git a/Samples/SimpleScene/Assets/Levels/FixedCamerasToObjects.xml b/Samples/SimpleScene/Assets/Levels/FixedCamerasToObjects.xml new file mode 100644 index 000000000..1b3314543 --- /dev/null +++ b/Samples/SimpleScene/Assets/Levels/FixedCamerasToObjects.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/Samples/SimpleScene/Assets/Levels/main.xml b/Samples/SimpleScene/Assets/Levels/main.xml index 2df506c3d..3dba54c71 100644 --- a/Samples/SimpleScene/Assets/Levels/main.xml +++ b/Samples/SimpleScene/Assets/Levels/main.xml @@ -1,4 +1,4 @@ - - + + diff --git a/Samples/SimpleScene/Source/private/GameFramework/GameFramework.cpp b/Samples/SimpleScene/Source/private/GameFramework/GameFramework.cpp index df7fd8eca..34d4ca35c 100644 --- a/Samples/SimpleScene/Source/private/GameFramework/GameFramework.cpp +++ b/Samples/SimpleScene/Source/private/GameFramework/GameFramework.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include using namespace GameEngine; @@ -19,12 +19,18 @@ void GameFramework::Init() World::GameWorld::GetInstance()->LoadLevel( m_World, Core::g_FileSystem->GetFilePath("Levels/Main.xml").generic_string() + //Core::g_FileSystem->GetFilePath("Levels/FixedCamerasToObjects.xml").generic_string() ); + m_World.set(CameraManagerPtr{ Core::g_CameraManager.get() }); + + flecs::entity cameraSavingSystem = m_World.entity() + .set(SavedCameraPtr{}) + .set(ControllerPtr{ new Core::Controller(Core::g_FileSystem->GetConfigPath("Input_default.ini")) }); + flecs::entity camera = m_World.entity() - .set(Position{ 0.0f, 12.0f, -10.0f }) + .set(CameraPtr{ Core::g_CameraManager->CreateCamera() }) .set(Speed{ 10.f }) - .set(CameraPtr{ Core::g_MainCamera }) .set(ControllerPtr{ new Core::Controller(Core::g_FileSystem->GetConfigPath("Input_default.ini")) }); } @@ -71,6 +77,11 @@ void GameFramework::RegisterComponentsReflection() m_World.component() .member("value"); + + m_World.component() + .member("dx") + .member("dy") + .member("dz"); } void GameFramework::RegisterSystems() diff --git a/Samples/SimpleScene/Source/private/ecsControl.cpp b/Samples/SimpleScene/Source/private/ecsControl.cpp index d6f278597..a9c9c1566 100644 --- a/Samples/SimpleScene/Source/private/ecsControl.cpp +++ b/Samples/SimpleScene/Source/private/ecsControl.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -10,39 +10,80 @@ using namespace GameEngine; + +static void ProcessButtonPress(const ControllerPtr& controller, + const char* actionName, + const std::function& action) +{ + if (controller.ptr->IsPressed(actionName)) + { + if (!controller.ptr->WasPressed(actionName)) + { + action(); + controller.ptr->SetWasPressed(actionName); + } + } +} + void RegisterEcsControlSystems(flecs::world& world) { - world.system() - .each([&](flecs::entity e, Position& position, CameraPtr& camera, const Speed& speed, const ControllerPtr& controller) + world.system() + .each([&](flecs::entity e, CameraPtr& cameraPtr, const Speed& speed, const ControllerPtr& controller) { - Core::InputHandler::MouseMovevement mouseMovement = Core::InputHandler::GetInstance()->GetMouseMovement(); + static const CameraManagerPtr* cameraManagerPtr = world.get(); - mouseMovement.dx *= 0.25 * Math::Constants::PI / 180.f; - mouseMovement.dy *= 0.25 * Math::Constants::PI / 180.f; + if (cameraPtr.ptr == cameraManagerPtr->ptr->GetActiveCamera()) + { + Core::InputHandler::MouseMovevement mouseMovement = Core::InputHandler::GetInstance()->GetMouseMovement(); - camera.ptr->Rotate(mouseMovement.dx, mouseMovement.dy); + mouseMovement.dx *= 0.25 * Math::Constants::PI / 180.f; + mouseMovement.dy *= 0.25 * Math::Constants::PI / 180.f; - Math::Vector3f currentMoveDir = Math::Vector3f::Zero(); - if (controller.ptr->IsPressed("GoLeft")) - { - currentMoveDir = currentMoveDir - camera.ptr->GetRightDir(); - } - if (controller.ptr->IsPressed("GoRight")) - { - currentMoveDir = currentMoveDir + camera.ptr->GetRightDir(); - } - if (controller.ptr->IsPressed("GoBack")) - { - currentMoveDir = currentMoveDir - camera.ptr->GetViewDir(); - } - if (controller.ptr->IsPressed("GoForward")) - { - currentMoveDir = currentMoveDir + camera.ptr->GetViewDir(); + Core::Camera* camera = cameraPtr.ptr; + + camera->Rotate(mouseMovement.dx, mouseMovement.dy); + + Math::Vector3f currentMoveDir = Math::Vector3f::Zero(); + if (controller.ptr->IsPressed("GoLeft")) + { + currentMoveDir = currentMoveDir - camera->GetRightDir(); + } + if (controller.ptr->IsPressed("GoRight")) + { + currentMoveDir = currentMoveDir + camera->GetRightDir(); + } + if (controller.ptr->IsPressed("GoBack")) + { + currentMoveDir = currentMoveDir - camera->GetViewDir(); + } + if (controller.ptr->IsPressed("GoForward")) + { + currentMoveDir = currentMoveDir + camera->GetViewDir(); + } + + Math::Vector3f position = camera->GetPosition() + currentMoveDir.Normalized() * speed.value * world.delta_time(); + camera->SetPosition(position); + + ProcessButtonPress(controller, "CreateCamera", + [&]() { world.entity().set(CameraPtr{ cameraManagerPtr->ptr->CreateCamera() }) + .set(Speed{ speed.value }) + .set(ControllerPtr{ new Core::Controller(Core::g_FileSystem->GetConfigPath("Input_default.ini")) }); } + ); + + ProcessButtonPress(controller, "NextCamera", + [&]() { cameraManagerPtr->ptr->SwitchNextCamera(); } + ); + ProcessButtonPress(controller, "PrevCamera", + [&]() { cameraManagerPtr->ptr->SwitchPrevCamera(); } + ); + + if (cameraManagerPtr->ptr->GetCamerasCount() > 1) + { + ProcessButtonPress(controller, "DeleteCamera", + [&]() { cameraManagerPtr->ptr->DeleteCamera(camera); e.destruct(); } + ); + } } - position.x = position.x + currentMoveDir.Normalized().x * speed.value * world.delta_time(); - position.y = position.y + currentMoveDir.Normalized().y * speed.value * world.delta_time(); - position.z = position.z + currentMoveDir.Normalized().z * speed.value * world.delta_time(); - camera.ptr->SetPosition(Math::Vector3f(position.x, position.y, position.z)); }); world.system() @@ -57,5 +98,38 @@ void RegisterEcsControlSystems(flecs::world& world) } } }); + + world.system() + .each([&](flecs::entity e, SavedCameraPtr& savedCameraPtr, const ControllerPtr& controller) + { + static const CameraManagerPtr* cameraManagerPtr = world.get(); + + ProcessButtonPress(controller, "SaveCamera", + [&]() { savedCameraPtr.ptr = cameraManagerPtr->ptr->GetActiveCamera(); } + ); + ProcessButtonPress(controller, "LoadCamera", + [&]() { cameraManagerPtr->ptr->SetActiveCamera(savedCameraPtr.ptr); } + ); + }); + + world.system() + .each([&](flecs::entity e, DeltaFixedCamera& delta) + { + static const CameraManagerPtr* cameraManagerPtr = world.get(); + + if (!e.has(world.lookup("CameraPtr").id())) + { + e.set(CameraPtr{ cameraManagerPtr->ptr->CreateCamera() }); + } + }); + + world.system() + .each([&](DeltaFixedCamera& delta, CameraPtr& cameraPtr, const Position& pos) + { + if (cameraPtr.ptr) + { + cameraPtr.ptr->SetPosition(Math::Vector3f(pos.x + delta.dx, pos.y + delta.dy, pos.z + delta.dz)); + } + }); } diff --git a/Samples/SimpleScene/Source/public/ecsControl.h b/Samples/SimpleScene/Source/public/ecsControl.h index c322735f9..cac6a75e7 100644 --- a/Samples/SimpleScene/Source/public/ecsControl.h +++ b/Samples/SimpleScene/Source/public/ecsControl.h @@ -4,6 +4,7 @@ namespace GameEngine::Core { + class CameraManager; class Camera; class Controller; } @@ -18,7 +19,25 @@ struct JumpSpeed float value; }; +struct CameraManagerPtr +{ + GameEngine::Core::CameraManager* ptr; +}; + struct CameraPtr +{ + GameEngine::Core::Camera* ptr = nullptr; +}; + + +struct DeltaFixedCamera +{ + float dx; + float dy; + float dz; +}; + +struct SavedCameraPtr { GameEngine::Core::Camera* ptr; };