#pragma once #include "Component.h" #include "TransformComponent.h" #include #include #include #include #include #include #include #include #include namespace XCEngine { namespace Components { class Scene; class GameObject { public: using ID = uint64_t; static constexpr ID INVALID_ID = 0; GameObject(); explicit GameObject(const std::string& name); ~GameObject(); ID GetID() const { return m_id; } uint64_t GetUUID() const { return m_uuid; } const std::string& GetName() const { return m_name; } void SetName(const std::string& name) { m_name = name; } const std::string& GetTag() const { return m_tag; } void SetTag(const std::string& tag) { m_tag = tag.empty() ? std::string("Untagged") : tag; } bool CompareTag(const std::string& tag) const { return m_tag == tag; } uint8_t GetLayer() const { return m_layer; } void SetLayer(uint8_t layer) { m_layer = std::min(layer, 31u); } void DetachFromParent(); Scene* GetScene() const { return m_scene; } TransformComponent* GetTransform() { return m_transform; } const TransformComponent* GetTransform() const { return m_transform; } template T* AddComponent(Args&&... args) { if constexpr (std::is_base_of_v) { return dynamic_cast(m_transform); } auto component = std::make_unique(std::forward(args)...); component->m_gameObject = this; T* ptr = component.get(); m_components.emplace_back(std::move(component)); NotifyComponentAdded(ptr); return ptr; } template T* GetComponent() { if (T* casted = dynamic_cast(m_transform)) { return casted; } for (auto& comp : m_components) { if (T* casted = dynamic_cast(comp.get())) { return casted; } } return nullptr; } template const T* GetComponent() const { if (const T* casted = dynamic_cast(m_transform)) { return casted; } for (auto& comp : m_components) { if (T* casted = dynamic_cast(comp.get())) { return casted; } } return nullptr; } template std::vector GetComponents() { std::vector result; if (T* casted = dynamic_cast(m_transform)) { result.push_back(casted); } for (auto& comp : m_components) { if (T* casted = dynamic_cast(comp.get())) { result.push_back(casted); } } return result; } template std::vector GetComponents() const { std::vector result; if (const T* casted = dynamic_cast(m_transform)) { result.push_back(casted); } for (auto& comp : m_components) { if (const T* casted = dynamic_cast(comp.get())) { result.push_back(casted); } } return result; } template void RemoveComponent() { if (dynamic_cast(m_transform)) { return; } for (auto it = m_components.begin(); it != m_components.end(); ++it) { if (T* casted = dynamic_cast(it->get())) { NotifyComponentRemoving(casted); m_components.erase(it); return; } } } bool RemoveComponent(Component* component) { if (!component || component == m_transform) { return false; } auto it = std::find_if(m_components.begin(), m_components.end(), [component](const std::unique_ptr& entry) { return entry.get() == component; }); if (it == m_components.end()) { return false; } NotifyComponentRemoving(component); m_components.erase(it); return true; } template T* GetComponentInChildren() { T* comp = GetComponent(); if (comp) { return comp; } for (auto* child : m_children) { comp = child->GetComponentInChildren(); if (comp) { return comp; } } return nullptr; } template T* GetComponentInParent() { if (m_parent) { T* comp = m_parent->GetComponent(); if (comp) { return comp; } return m_parent->GetComponentInParent(); } return nullptr; } template std::vector GetComponentsInChildren() { std::vector result; std::vector comps = GetComponents(); result.insert(result.end(), comps.begin(), comps.end()); for (auto* child : m_children) { std::vector childComps = child->GetComponentsInChildren(); result.insert(result.end(), childComps.begin(), childComps.end()); } return result; } GameObject* GetParent() const { return m_parent; } void SetParent(GameObject* parent); void SetParent(GameObject* parent, bool worldPositionStays); void SetParent(GameObject* parent, size_t siblingIndex, bool worldPositionStays); size_t GetChildCount() const { return m_children.size(); } GameObject* GetChild(size_t index) const; std::vector GetChildren() const; void DetachChildren(); bool IsActive() const { return m_activeSelf; } void SetActive(bool active); bool IsActiveInHierarchy() const; static GameObject* Find(const std::string& name); static std::vector FindObjectsOfType(); static std::vector FindGameObjectsWithTag(const std::string& tag); void Awake(); void Start(); void Update(float deltaTime); void FixedUpdate(); void LateUpdate(float deltaTime); void OnDestroy(); void Destroy(); void Serialize(std::ostream& os) const; void Deserialize(std::istream& is); private: void NotifyComponentAdded(Component* component); void NotifyComponentRemoving(Component* component); void NotifyComponentsBecameActive(); void NotifyComponentsBecameInactive(); void PropagateActiveInHierarchyChange(bool oldParentActiveInHierarchy, bool newParentActiveInHierarchy); ID m_id = INVALID_ID; uint64_t m_uuid = 0; std::string m_name; std::string m_tag = "Untagged"; bool m_activeSelf = true; bool m_started = false; uint8_t m_layer = 0; GameObject* m_parent = nullptr; std::vector m_children; Scene* m_scene = nullptr; TransformComponent* m_transform = nullptr; std::vector> m_components; static ID s_nextID; static std::unordered_map& GetGlobalRegistry(); friend class Scene; friend class SceneManager; }; } // namespace Components } // namespace XCEngine