2026-03-20 19:59:06 +08:00
|
|
|
#include "Scene/Scene.h"
|
|
|
|
|
#include "Components/GameObject.h"
|
2026-03-22 03:42:40 +08:00
|
|
|
#include <sstream>
|
2026-03-20 19:59:06 +08:00
|
|
|
|
|
|
|
|
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<GameObject>(name);
|
|
|
|
|
GameObject* ptr = gameObject.get();
|
|
|
|
|
|
2026-03-21 12:12:32 +08:00
|
|
|
GameObject::GetGlobalRegistry()[ptr->m_id] = ptr;
|
2026-03-20 19:59:06 +08:00
|
|
|
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<GameObject*> Scene::GetRootGameObjects() const {
|
|
|
|
|
std::vector<GameObject*> 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) {
|
2026-03-22 03:42:40 +08:00
|
|
|
std::ifstream file(filePath);
|
|
|
|
|
if (!file.is_open()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 19:59:06 +08:00
|
|
|
m_gameObjects.clear();
|
|
|
|
|
m_rootGameObjects.clear();
|
2026-03-22 03:42:40 +08:00
|
|
|
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<GameObject>();
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-20 19:59:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Scene::Save(const std::string& filePath) {
|
2026-03-22 03:42:40 +08:00
|
|
|
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";
|
|
|
|
|
}
|
2026-03-20 19:59:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Components
|
|
|
|
|
} // namespace XCEngine
|