#include "Scene/Scene.h" #include "Components/GameObject.h" #include namespace XCEngine { namespace Components { Scene::Scene() : m_name("Untitled") { } Scene::Scene(const std::string& name) : m_name(name) { } Scene::~Scene() { m_gameObjects.clear(); } GameObject* Scene::CreateGameObject(const std::string& name, GameObject* parent) { auto gameObject = std::make_unique(name); GameObject* ptr = gameObject.get(); GameObject::GetGlobalRegistry()[ptr->m_id] = ptr; m_gameObjectIDs.insert(ptr->m_id); m_gameObjects.emplace(ptr->m_id, std::move(gameObject)); if (parent) { ptr->SetParent(parent); } else { m_rootGameObjects.push_back(ptr->m_id); } ptr->m_scene = this; ptr->Awake(); m_onGameObjectCreated.Invoke(ptr); return ptr; } void Scene::DestroyGameObject(GameObject* gameObject) { if (!gameObject || gameObject->m_scene != this) { return; } for (auto* child : gameObject->GetChildren()) { DestroyGameObject(child); } if (gameObject->m_parent) { auto& siblings = gameObject->m_parent->m_children; siblings.erase(std::remove(siblings.begin(), siblings.end(), gameObject), siblings.end()); } else { m_rootGameObjects.erase( std::remove(m_rootGameObjects.begin(), m_rootGameObjects.end(), gameObject->m_id), m_rootGameObjects.end() ); } m_onGameObjectDestroyed.Invoke(gameObject); gameObject->OnDestroy(); m_gameObjectIDs.erase(gameObject->m_id); m_gameObjects.erase(gameObject->m_id); } GameObject* Scene::Find(const std::string& name) const { for (auto* go : GetRootGameObjects()) { if (go->GetName() == name) { return go; } GameObject* found = FindInChildren(go, name); if (found) { return found; } } return nullptr; } GameObject* Scene::FindInChildren(GameObject* parent, const std::string& name) const { for (size_t i = 0; i < parent->GetChildCount(); ++i) { GameObject* child = parent->GetChild(i); if (child->GetName() == name) { return child; } GameObject* found = FindInChildren(child, name); if (found) { return found; } } return nullptr; } GameObject* Scene::FindGameObjectWithTag(const std::string& tag) const { for (auto* go : GetRootGameObjects()) { if (go->GetName() == tag) { return go; } GameObject* found = FindInChildren(go, tag); if (found) { return found; } } return nullptr; } std::vector Scene::GetRootGameObjects() const { std::vector result; for (auto id : m_rootGameObjects) { auto it = m_gameObjects.find(id); if (it != m_gameObjects.end()) { result.push_back(it->second.get()); } } return result; } void Scene::Update(float deltaTime) { for (auto* go : GetRootGameObjects()) { if (go->IsActiveInHierarchy()) { go->Update(deltaTime); } } } void Scene::FixedUpdate(float fixedDeltaTime) { for (auto* go : GetRootGameObjects()) { if (go->IsActiveInHierarchy()) { go->FixedUpdate(); } } } void Scene::LateUpdate(float deltaTime) { for (auto* go : GetRootGameObjects()) { if (go->IsActiveInHierarchy()) { go->LateUpdate(deltaTime); } } } void Scene::Load(const std::string& filePath) { std::ifstream file(filePath); if (!file.is_open()) { return; } m_gameObjects.clear(); m_rootGameObjects.clear(); m_gameObjectIDs.clear(); std::string line; while (std::getline(file, line)) { if (line.empty() || line[0] == '#') continue; std::istringstream iss(line); std::string token; std::getline(iss, token, '='); if (token == "scene") { std::getline(iss, m_name, ';'); } else if (token == "gameobject") { auto go = std::make_unique(); go->Deserialize(iss); go->m_scene = this; GameObject* ptr = go.get(); GameObject::GetGlobalRegistry()[ptr->m_id] = ptr; m_gameObjectIDs.insert(ptr->m_id); m_rootGameObjects.push_back(ptr->m_id); m_gameObjects.emplace(ptr->m_id, std::move(go)); } } } void Scene::Save(const std::string& filePath) { std::ofstream file(filePath); if (!file.is_open()) { return; } file << "# XCEngine Scene File\n"; file << "scene=" << m_name << ";\n"; file << "active=" << (m_active ? "1" : "0") << ";\n\n"; for (auto* go : GetRootGameObjects()) { file << "gameobject="; go->Serialize(file); file << "\n"; } } } // namespace Components } // namespace XCEngine