#include "Components/GameObject.h" #include "Components/TransformComponent.h" #include "Scene/Scene.h" namespace XCEngine { namespace Components { GameObject::ID GameObject::s_nextID = 1; GameObject::GameObject() : m_name("GameObject") { m_id = s_nextID++; static std::random_device rd; static std::mt19937_64 gen(rd()); static std::uniform_int_distribution dis(1, UINT64_MAX); m_uuid = dis(gen); m_transform = new TransformComponent(); m_transform->m_gameObject = this; } GameObject::GameObject(const std::string& name) : m_name(name) { m_id = s_nextID++; static std::random_device rd; static std::mt19937_64 gen(rd()); static std::uniform_int_distribution dis(1, UINT64_MAX); m_uuid = dis(gen); m_transform = new TransformComponent(); m_transform->m_gameObject = this; } GameObject::~GameObject() { GetGlobalRegistry().erase(m_id); if (m_transform) { delete m_transform; m_transform = nullptr; } m_components.clear(); } std::unordered_map& GameObject::GetGlobalRegistry() { static std::unordered_map registry; return registry; } void GameObject::SetParent(GameObject* parent) { SetParent(parent, true); } void GameObject::SetParent(GameObject* parent, bool worldPositionStays) { if (m_parent == parent || parent == this) { return; } if (m_parent) { auto& siblings = m_parent->m_children; siblings.erase(std::remove(siblings.begin(), siblings.end(), this), siblings.end()); } else if (m_scene) { auto& roots = m_scene->m_rootGameObjects; roots.erase(std::remove(roots.begin(), roots.end(), m_id), roots.end()); } m_parent = parent; if (m_parent) { m_parent->m_children.push_back(this); } else if (m_scene) { auto& roots = m_scene->m_rootGameObjects; if (std::find(roots.begin(), roots.end(), m_id) == roots.end()) { roots.push_back(m_id); } } GetTransform()->SetParent(parent ? parent->GetTransform() : nullptr, worldPositionStays); } GameObject* GameObject::GetChild(size_t index) const { if (index < m_children.size()) { return m_children[index]; } return nullptr; } std::vector GameObject::GetChildren() const { return m_children; } void GameObject::DetachChildren() { auto children = m_children; for (auto* child : children) { if (child) { child->SetParent(nullptr, true); } } } void GameObject::DetachFromParent() { if (m_parent) { SetParent(nullptr, true); } } void GameObject::SetActive(bool active) { if (m_activeSelf != active) { m_activeSelf = active; if (m_parent == nullptr || m_parent->IsActiveInHierarchy()) { } } } bool GameObject::IsActiveInHierarchy() const { if (!m_activeSelf) { return false; } if (m_parent) { return m_parent->IsActiveInHierarchy(); } return true; } GameObject* GameObject::Find(const std::string& name) { auto& registry = GetGlobalRegistry(); for (auto& pair : registry) { if (pair.second->GetName() == name) { return pair.second; } } return nullptr; } std::vector GameObject::FindObjectsOfType() { auto& registry = GetGlobalRegistry(); std::vector result; for (auto& pair : registry) { result.push_back(pair.second); } return result; } std::vector GameObject::FindGameObjectsWithTag(const std::string& tag) { auto& registry = GetGlobalRegistry(); std::vector result; for (auto& pair : registry) { if (pair.second->GetName() == tag) { result.push_back(pair.second); } } return result; } void GameObject::Awake() { for (auto& comp : m_components) { comp->Awake(); } } void GameObject::Start() { for (auto& comp : m_components) { if (comp->IsEnabled()) { comp->Start(); } } } void GameObject::Update(float deltaTime) { for (auto& comp : m_components) { if (comp->IsEnabled()) { comp->Update(deltaTime); } } } void GameObject::FixedUpdate() { for (auto& comp : m_components) { if (comp->IsEnabled()) { comp->FixedUpdate(); } } } void GameObject::LateUpdate(float deltaTime) { for (auto& comp : m_components) { if (comp->IsEnabled()) { comp->LateUpdate(deltaTime); } } } void GameObject::OnDestroy() { for (auto& comp : m_components) { comp->OnDestroy(); } } void GameObject::Destroy() { OnDestroy(); if (m_scene) { m_scene->DestroyGameObject(this); } } void GameObject::Serialize(std::ostream& os) const { os << "name=" << m_name << ";"; os << "active=" << (m_activeSelf ? "1" : "0") << ";"; os << "id=" << m_id << ";"; os << "transform="; m_transform->Serialize(os); os << ";"; } void GameObject::Deserialize(std::istream& is) { std::string token; while (is.peek() != -1 && is.peek() != '\n' && is.peek() != '\r') { if (is.peek() == ';') { is.get(); if (is.peek() == ';') break; continue; } char key[64]; is.get(key, 64, '='); if (key[0] == '\0') break; is.get(); if (strcmp(key, "name") == 0) { std::getline(is, m_name, ';'); } else if (strcmp(key, "active") == 0) { char val; is.get(val); m_activeSelf = (val == '1'); if (is.peek() == ';') is.get(); } else if (strcmp(key, "id") == 0) { is >> m_id; if (is.peek() == ';') is.get(); } else if (strcmp(key, "transform") == 0) { m_transform->Deserialize(is); if (is.peek() == ';') is.get(); } else { std::getline(is, token, ';'); } } } } // namespace Components } // namespace XCEngine