fix: alot of stuff changed. Mostly bugfixxes / architechture changes
This commit is contained in:
+186
-86
@@ -1,163 +1,263 @@
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <SDL_scancode.h>
|
||||
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
// #include "ServiceLocator.h"
|
||||
// #include "Input/InputManager.h"
|
||||
// #include "Managers/Renderer.h"
|
||||
|
||||
|
||||
unsigned int Scene::m_idCounter = 0;
|
||||
|
||||
Scene::Scene(const std::string& name) : m_name(name) {
|
||||
namespace {
|
||||
class IterationGuard {
|
||||
public:
|
||||
explicit IterationGuard(Scene& scene) : m_Scene(scene) {
|
||||
m_Scene.BeginIteration();
|
||||
}
|
||||
|
||||
~IterationGuard() {
|
||||
m_Scene.EndIteration();
|
||||
}
|
||||
|
||||
private:
|
||||
Scene& m_Scene;
|
||||
};
|
||||
}
|
||||
|
||||
Scene::~Scene() = default;
|
||||
Scene::Scene(const std::string& name)
|
||||
: m_name(name),
|
||||
m_id(++m_idCounter) {
|
||||
}
|
||||
|
||||
// void Scene::Add(std::shared_ptr<GameObject> object) {
|
||||
// // m_objects.emplace_back(std::move(object));
|
||||
// m_pendingAdditions.emplace_back(std::move(object));
|
||||
// }
|
||||
Scene::~Scene() {
|
||||
Unload();
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
GameObject* Scene::CreateGameObject(std::string name)
|
||||
{
|
||||
auto obj = std::make_shared<GameObject>(std::move(name));
|
||||
|
||||
GameObject* rawPtr = obj.get();
|
||||
|
||||
obj->SetScene(this);
|
||||
m_pendingAdditions.emplace_back(std::move(obj));
|
||||
GameObject* Scene::CreateGameObject(std::string name) {
|
||||
auto object = std::make_shared<GameObject>(std::move(name));
|
||||
GameObject* rawPtr = object.get();
|
||||
|
||||
object->SetScene(this);
|
||||
m_pendingAdditions.emplace_back(std::move(object));
|
||||
return rawPtr;
|
||||
}
|
||||
|
||||
void Scene::Remove(GameObject* object) {
|
||||
std::erase_if(m_objects, [object](const std::shared_ptr<GameObject>& obj) {
|
||||
return obj.get() == object;
|
||||
});
|
||||
if (object == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::erase_if(m_pendingAdditions, [object](const std::shared_ptr<GameObject>& obj) {
|
||||
return obj.get() == object;
|
||||
});
|
||||
const auto containsObject = [object](const auto& objects) {
|
||||
return std::any_of(objects.begin(), objects.end(), [object](const auto& candidate) {
|
||||
return candidate != nullptr && candidate.get() == object;
|
||||
});
|
||||
};
|
||||
|
||||
if (!containsObject(m_objects) && !containsObject(m_pendingAdditions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
object->Destroy();
|
||||
|
||||
if (IsIterating()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto eraseDestroyed = [](auto& objects) {
|
||||
for (const auto& candidate : objects) {
|
||||
if (candidate != nullptr && candidate->IsBeingDestroyed()) {
|
||||
candidate->SetScene(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::erase_if(objects, [](const auto& candidate) {
|
||||
return candidate == nullptr || candidate->IsBeingDestroyed();
|
||||
});
|
||||
};
|
||||
|
||||
// Destroying an object also marks its descendants. Remove all of those
|
||||
// marked entries together, after destruction has finished.
|
||||
eraseDestroyed(m_objects);
|
||||
eraseDestroyed(m_pendingAdditions);
|
||||
}
|
||||
|
||||
void Scene::RemoveAll() {
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr) {
|
||||
object->Destroy();
|
||||
}
|
||||
}
|
||||
for (const auto& object : m_pendingAdditions) {
|
||||
if (object != nullptr) {
|
||||
object->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsIterating()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr) {
|
||||
object->SetScene(nullptr);
|
||||
}
|
||||
}
|
||||
for (const auto& object : m_pendingAdditions) {
|
||||
if (object != nullptr) {
|
||||
object->SetScene(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
m_objects.clear();
|
||||
m_pendingAdditions.clear();
|
||||
}
|
||||
|
||||
void Scene::Load() {
|
||||
OnSceneLoaded.Invoke();
|
||||
if (m_registerBindings) {
|
||||
m_registerBindings();
|
||||
}
|
||||
LoadBindings();
|
||||
}
|
||||
|
||||
void Scene::Update() {
|
||||
void Scene::Update(float dt) {
|
||||
CommitPendingAdditions();
|
||||
IterationGuard iteration(*this);
|
||||
|
||||
for (const auto& object : m_objects) {
|
||||
if (object->IsActiveInHierarchy()) {
|
||||
object->Update();
|
||||
if (object != nullptr && !object->IsBeingDestroyed() && object->IsActiveInHierarchy()) {
|
||||
object->Update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Scene::FixedUpdate(float dt) {
|
||||
for (const auto& object: m_objects) {
|
||||
if (object->IsActiveInHierarchy()) {
|
||||
object->FixedUpdate();
|
||||
CommitPendingAdditions();
|
||||
IterationGuard iteration(*this);
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr && !object->IsBeingDestroyed() && object->IsActiveInHierarchy()) {
|
||||
object->FixedUpdate(dt);
|
||||
}
|
||||
}
|
||||
|
||||
m_Physics.FixedUpdate(dt);
|
||||
}
|
||||
|
||||
void Scene::LateUpdate() {
|
||||
for (const auto& object: m_objects) {
|
||||
if (object->IsActiveInHierarchy()) {
|
||||
object->LateUpdate();
|
||||
void Scene::LateUpdate(float dt) {
|
||||
IterationGuard iteration(*this);
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr && !object->IsBeingDestroyed() && object->IsActiveInHierarchy()) {
|
||||
object->LateUpdate(dt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Scene::Render(const RenderContext& ctx) const {
|
||||
for (const auto& object: m_objects) {
|
||||
if (object->IsActiveInHierarchy()) {
|
||||
void Scene::Render(const RenderContext& ctx) {
|
||||
IterationGuard iteration(*this);
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr && !object->IsBeingDestroyed() && object->IsActiveInHierarchy()) {
|
||||
object->Render(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Scene::RenderImgui() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Scene::CleanupDestroyedGameObjects() {
|
||||
if (m_BeingUnloaded) {
|
||||
//Scene is gone anyways, kill everything
|
||||
m_objects.clear();
|
||||
if (IsIterating()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& gameObject: m_objects) {
|
||||
//First check if a gameobjects components needs to be destroyed
|
||||
gameObject->CleanupComponents();
|
||||
const auto cleanup = [](auto& objects) {
|
||||
for (const auto& object : objects) {
|
||||
if (object != nullptr && object->IsBeingDestroyed()) {
|
||||
object->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& object : objects) {
|
||||
if (object != nullptr && !object->IsBeingDestroyed()) {
|
||||
object->CleanupComponents();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& object : objects) {
|
||||
if (object != nullptr && object->IsBeingDestroyed()) {
|
||||
object->SetScene(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::erase_if(objects, [](const auto& object) {
|
||||
return object == nullptr || object->IsBeingDestroyed();
|
||||
});
|
||||
};
|
||||
|
||||
cleanup(m_objects);
|
||||
cleanup(m_pendingAdditions);
|
||||
}
|
||||
|
||||
void Scene::BeginIteration() {
|
||||
++m_IterationDepth;
|
||||
}
|
||||
|
||||
void Scene::EndIteration() {
|
||||
if (m_IterationDepth == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// //Strange for loop since im deleting during looping over it
|
||||
// for (auto it = m_objects.begin(); it != m_objects.end();) {
|
||||
// if ((*it)->IsBeingDestroyed()) {
|
||||
// it = m_objects.erase(it);
|
||||
// } else {
|
||||
// ++it;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::erase_if(m_objects, [] (const std::shared_ptr<GameObject>& gameObject) {
|
||||
return gameObject->IsBeingDestroyed();
|
||||
});
|
||||
--m_IterationDepth;
|
||||
if (m_IterationDepth == 0) {
|
||||
CleanupDestroyedGameObjects();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::Unload() {
|
||||
if (m_unregisterBindings) {
|
||||
m_unregisterBindings();
|
||||
if (m_BeingUnloaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
UnloadBindings();
|
||||
m_BeingUnloaded = true;
|
||||
}
|
||||
|
||||
void Scene::DestroyGameObjects() {
|
||||
if (m_BeingUnloaded) {
|
||||
|
||||
for (auto& obj : m_pendingAdditions) {
|
||||
m_objects.emplace_back(std::move(obj));
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr) {
|
||||
object->Destroy();
|
||||
}
|
||||
m_pendingAdditions.clear();
|
||||
|
||||
//Scene is gone anyways, kill everything
|
||||
for (const auto& gameObject: m_objects) {
|
||||
gameObject->Destroy();
|
||||
}
|
||||
for (const auto& object : m_pendingAdditions) {
|
||||
if (object != nullptr) {
|
||||
object->Destroy();
|
||||
}
|
||||
} else {
|
||||
assert(m_BeingUnloaded && "Scene is being cleared but not unloaded? Weird");
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::CommitPendingAdditions() {
|
||||
if (m_pendingAdditions.empty()) {
|
||||
if (m_pendingAdditions.empty() || IsIterating()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& obj : m_pendingAdditions) {
|
||||
m_objects.emplace_back(std::move(obj));
|
||||
for (auto& object : m_pendingAdditions) {
|
||||
if (object != nullptr && !object->IsBeingDestroyed()) {
|
||||
m_Physics.RegisterGameObject(*object);
|
||||
m_objects.emplace_back(std::move(object));
|
||||
}
|
||||
}
|
||||
|
||||
m_pendingAdditions.clear();
|
||||
}
|
||||
std::erase_if(m_pendingAdditions, [](const auto& object) {
|
||||
return object == nullptr || object->IsBeingDestroyed();
|
||||
});
|
||||
}
|
||||
|
||||
void Scene::RefreshPhysics() {
|
||||
for (const auto& object : m_objects) {
|
||||
if (object != nullptr) {
|
||||
m_Physics.RefreshGameObject(*object);
|
||||
}
|
||||
}
|
||||
for (const auto& object : m_pendingAdditions) {
|
||||
if (object != nullptr) {
|
||||
m_Physics.RefreshGameObject(*object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,57 @@
|
||||
#include <destrum/Scene/SceneManager.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
void SceneManager::Update() {
|
||||
m_scenes[m_ActiveSceneIndex]->Update();
|
||||
Scene& SceneManager::GetCurrentScene() const {
|
||||
if (m_scenes.empty()) {
|
||||
throw std::out_of_range("No scenes are available");
|
||||
}
|
||||
|
||||
if (m_ActiveSceneIndex < 0 || m_ActiveSceneIndex >= static_cast<int>(m_scenes.size())) {
|
||||
throw std::out_of_range("Active scene index is invalid");
|
||||
}
|
||||
|
||||
return *m_scenes[static_cast<std::size_t>(m_ActiveSceneIndex)];
|
||||
}
|
||||
|
||||
void SceneManager::Update(float dt) {
|
||||
if (m_scenes.empty()) return;
|
||||
(void)GetCurrentScene();
|
||||
const auto scene = m_scenes.at(static_cast<std::size_t>(m_ActiveSceneIndex));
|
||||
scene->Update(dt);
|
||||
}
|
||||
|
||||
void SceneManager::FixedUpdate(float dt) {
|
||||
m_scenes[m_ActiveSceneIndex]->FixedUpdate(dt);
|
||||
if (m_scenes.empty()) return;
|
||||
(void)GetCurrentScene();
|
||||
const auto scene = m_scenes.at(static_cast<std::size_t>(m_ActiveSceneIndex));
|
||||
scene->FixedUpdate(dt);
|
||||
}
|
||||
|
||||
void SceneManager::LateUpdate() {
|
||||
m_scenes[m_ActiveSceneIndex]->LateUpdate();
|
||||
void SceneManager::LateUpdate(float dt) {
|
||||
if (m_scenes.empty()) return;
|
||||
(void)GetCurrentScene();
|
||||
const auto scene = m_scenes.at(static_cast<std::size_t>(m_ActiveSceneIndex));
|
||||
scene->LateUpdate(dt);
|
||||
}
|
||||
|
||||
void SceneManager::Render(const RenderContext& ctx) {
|
||||
m_scenes[m_ActiveSceneIndex]->Render(ctx);
|
||||
if (m_scenes.empty()) return;
|
||||
(void)GetCurrentScene();
|
||||
const auto scene = m_scenes.at(static_cast<std::size_t>(m_ActiveSceneIndex));
|
||||
scene->Render(ctx);
|
||||
}
|
||||
|
||||
void SceneManager::RenderImgui() {
|
||||
m_scenes[m_ActiveSceneIndex]->RenderImgui();
|
||||
if (m_scenes.empty()) return;
|
||||
(void)GetCurrentScene();
|
||||
const auto scene = m_scenes.at(static_cast<std::size_t>(m_ActiveSceneIndex));
|
||||
scene->RenderImgui();
|
||||
}
|
||||
|
||||
void SceneManager::HandleGameObjectDestroy() {
|
||||
@@ -43,6 +73,12 @@ void SceneManager::UnloadAllScenes() {
|
||||
}
|
||||
|
||||
void SceneManager::HandleSceneDestroy() {
|
||||
const std::shared_ptr<Scene> activeScene =
|
||||
m_ActiveSceneIndex >= 0 &&
|
||||
m_ActiveSceneIndex < static_cast<int>(m_scenes.size())
|
||||
? m_scenes[static_cast<std::size_t>(m_ActiveSceneIndex)]
|
||||
: nullptr;
|
||||
|
||||
for (auto it = m_scenes.begin(); it != m_scenes.end();) {
|
||||
if ((*it)->IsBeingUnloaded()) {
|
||||
it = m_scenes.erase(it);
|
||||
@@ -50,15 +86,37 @@ void SceneManager::HandleSceneDestroy() {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scenes.empty()) {
|
||||
m_ActiveSceneIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeScene != nullptr) {
|
||||
const auto activeIt = std::find(m_scenes.begin(), m_scenes.end(), activeScene);
|
||||
if (activeIt != m_scenes.end()) {
|
||||
m_ActiveSceneIndex = static_cast<int>(std::distance(m_scenes.begin(), activeIt));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_ActiveSceneIndex = std::clamp(
|
||||
m_ActiveSceneIndex,
|
||||
0,
|
||||
static_cast<int>(m_scenes.size()) - 1);
|
||||
}
|
||||
|
||||
void SceneManager::HandleScene() {
|
||||
DestroyGameObjects();
|
||||
HandleGameObjectDestroy();
|
||||
HandleSceneDestroy();
|
||||
}
|
||||
|
||||
void SceneManager::Destroy() {
|
||||
if (m_scenes.empty()) {
|
||||
m_ActiveSceneIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
UnloadAllScenes();
|
||||
DestroyGameObjects();
|
||||
HandleGameObjectDestroy();
|
||||
@@ -71,13 +129,20 @@ void SceneManager::SwitchScene(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(m_scenes.size())) {
|
||||
throw std::out_of_range("Scene index out of range");
|
||||
}
|
||||
m_scenes[m_ActiveSceneIndex]->UnloadBindings();
|
||||
if (index == m_ActiveSceneIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_scenes[static_cast<std::size_t>(m_ActiveSceneIndex)]->UnloadBindings();
|
||||
m_ActiveSceneIndex = index;
|
||||
m_scenes[m_ActiveSceneIndex]->LoadBindings();
|
||||
m_scenes[static_cast<std::size_t>(m_ActiveSceneIndex)]->LoadBindings();
|
||||
}
|
||||
|
||||
Scene &SceneManager::CreateScene(const std::string &name) {
|
||||
const auto &scene = std::shared_ptr<Scene>(new Scene(name));
|
||||
const auto scene = std::shared_ptr<Scene>(new Scene(name));
|
||||
m_scenes.push_back(scene);
|
||||
if (m_scenes.size() == 1) {
|
||||
m_ActiveSceneIndex = 0;
|
||||
}
|
||||
return *scene;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user