SleakEngine 0.1.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
GameObject.hpp
Go to the documentation of this file.
1#ifndef _GAMEOBJECT_H_
2#define _GAMEOBJECT_H_
3
4#include "Object.hpp"
5#include <Core/Logger.hpp>
6#include <ECS/Component.hpp>
8#include <Memory/RefPtr.hpp>
9#include <type_traits>
10#include <string>
11
12namespace Sleak {
13 namespace Math {class Vector3D;};
14 class SceneBase;
15 /// Scene entity holding components and an optional parent/child transform
16 /// hierarchy. Scene owns the instance; destroy via Scene::DestroyObject().
17 ///
18 /// A GameObject on its own does nothing. Behavior comes from the
19 /// components attached to it: a TransformComponent for placement, a
20 /// MeshComponent and MaterialComponent to be drawn, a ColliderComponent
21 /// and RigidbodyComponent to be simulated, and your own Component
22 /// subclasses for gameplay.
23 ///
24 /// AddComponent<T>() constructs the component in place, forwarding
25 /// extra arguments to its constructor after the owner pointer. Only one
26 /// component of a given type is allowed per object: a second
27 /// AddComponent<T>() logs a warning and does nothing. GetComponent<T>()
28 /// resolves through `dynamic_cast`, so it also matches subclasses.
29 ///
30 /// The scene that received the object through SceneBase::AddObject()
31 /// owns it. Never `delete` a GameObject. Use SceneBase::DestroyObject()
32 /// for deferred destruction, which is what you want while iterating, or
33 /// SceneBase::RemoveObject() for immediate destruction.
34 ///
35 /// A parent owns every child that was not itself added to a scene, so a
36 /// hierarchy built with SetParent() (for example by ModelLoader) only
37 /// needs its root added. Deleting a parent deletes those children too.
38 ///
39 /// Camera, Light, and its subclasses all derive from GameObject, so
40 /// they are added and found the same way as anything else.
41 ///
42 /// @code{.cpp}
43 /// auto* crate = Sleak::GameObject::CreateCube(
44 /// Sleak::Math::Vector3D(0.0f, 1.0f, 0.0f));
45 /// crate->SetTag("Destructible");
46 ///
47 /// crate->AddComponent<Sleak::MaterialComponent>(
48 /// Sleak::RefPtr<Sleak::Material>(new Sleak::Material()));
49 /// crate->AddComponent<Sleak::RigidbodyComponent>(
50 /// Sleak::BodyType::Dynamic);
51 ///
52 /// if (auto* t = crate->GetComponent<Sleak::TransformComponent>()) {
53 /// t->SetScale(Sleak::Math::Vector3D(2.0f, 2.0f, 2.0f));
54 /// }
55 ///
56 /// AddObject(crate); // the scene now owns it
57 /// @endcode
58 ///
59 /// @see Component, SceneBase, TransformComponent, MeshComponent,
60 /// MaterialComponent, Camera
61 /// @ingroup scene
62 class ENGINE_API GameObject : public Object {
63 public:
64 GameObject(const std::string& name = "GameObject")
65 : Object(name), m_isActive(true), bIsInitialized(false),
66 m_pendingDestroy(false), m_parent(nullptr) {}
67
68 ~GameObject() override;
69
70 /// Constructs and attaches a component of type T. Warns and no-ops if one already exists.
71 template<typename T, typename... Args>
72 void AddComponent(Args&&... args) {
73 static_assert(std::is_base_of<Component, T>::value, "T must derive from Component!");
74
75 if (GetComponent<T>() != nullptr) {
76 SLEAK_WARN("The component already exists!");
77 return;
78 }
79
80 RefPtr<Component> newComponent = RefPtr<T>(new T(this, std::forward<Args>(args)...));
81 if (bIsInitialized) InitializeComponent(newComponent.get());
82 Components.add(std::move(newComponent));
83 }
84
85 /// Destroys and detaches the first component of type T, if present.
86 template<typename T>
88 static_assert(std::is_base_of<Component, T>::value, "T must derive from Component!");
89
90 for (size_t i = 0; i < Components.GetSize(); ++i) {
91 if (dynamic_cast<T*>(Components[i].get()) != nullptr) {
92 Components[i]->OnDestroy();
93 Components.erase(i);
94 break;
95 }
96 }
97 }
98
99 /// Finds the first attached component of type T, or nullptr.
100 template <typename T>
102 static_assert(std::is_base_of_v<Component, T>,
103 "T must derive from Component!");
104
105 for (size_t i = 0; i < Components.GetSize(); ++i) {
106 Component* rawPtr = Components[i].get();
107 if (!rawPtr) continue;
108
109 T* component = dynamic_cast<T*>(rawPtr);
110 if (component) return component;
111 }
112
113 return nullptr;
114 }
115
116 /// True if a component of type T is attached.
117 template <typename T>
119 static_assert(std::is_base_of_v<Component, T>,
120 "T must derive from Component!");
121 return GetComponent<T>() != nullptr;
122 }
123
124 /// Initializes the object, components and children; repeats no-op.
125 virtual void Initialize();
126 bool IsInitialized() const { return bIsInitialized; }
127 virtual void Update(float deltaTime);
128 virtual void FixedUpdate(float fixedDeltaTime);
129 virtual void LateUpdate(float deltaTime);
130
131 /// Enables or disables the object, firing OnEnable/OnDisable on its components.
132 void SetActive(bool active);
133 bool IsActive() const { return m_isActive; }
134
135 void SetTag(const std::string& tag) { m_tag = tag; }
136 const std::string& GetTag() const { return m_tag; }
137
138 /// Reparents this object, updating both the old and new parent's child lists.
139 void SetParent(GameObject* parent);
140 GameObject* GetParent() const { return m_parent; }
141 const List<GameObject*>& GetChildren() const { return m_children; }
142 void AddChild(GameObject* child);
143 void RemoveChild(GameObject* child);
144 bool HasParent() const { return m_parent != nullptr; }
145 bool HasChildren() const { return m_children.GetSize() > 0; }
146 /// True once a scene took ownership through SceneBase::AddObject().
147 bool IsOwnedByScene() const { return m_ownedByScene; }
148
149 virtual bool IsLight() const { return false; }
150
151 /// Flags the object for deferred destruction on the next scene pass.
152 void MarkForDestroy() { m_pendingDestroy = true; }
153 bool IsPendingDestroy() const { return m_pendingDestroy; }
154
155 /// Built-in primitive factories, mainly for prototyping and debug scenes.
156 static GameObject* CreatePlane(Math::Vector3D position, int width = 100, int height = 100);
157 static GameObject* CreateCube(Math::Vector3D position);
158 static GameObject* CreateSphere(Math::Vector3D position, int stack = 16, int slices = 16);
159 static GameObject* CreateCapsule(Math::Vector3D position, int segments = 16, int rings = 8, float height = 1, float radius = 0.5);
160 static GameObject* CreateCylinder(Math::Vector3D position, int segments = 16, float height = 1, float radius = 0.5);
161 static GameObject* CreateTorus(Math::Vector3D position, int segments = 16, int rings = 8, float innerRadius = 8, float outerRadius = 9);
162
163 protected:
165
166 private:
167 bool m_isActive;
168 bool m_pendingDestroy;
169 bool m_ownedByScene = false;
170 std::string m_tag = "Untagged";
171
172 List<RefPtr<Component>> Components;
173
174 // Hierarchy
175 GameObject* m_parent;
176 List<GameObject*> m_children;
177
178 /// Calls OnDestroy() on and drops every attached component.
179 void DestroyComponents();
180 /// Initializes a component once, then enables it if active.
181 void InitializeComponent(Component* component);
182
183 friend class SceneBase;
184 };
185}
186
187#endif // _GAMEOBJECT_H_
int width
int height
#define SLEAK_WARN(...)
Definition Logger.hpp:21
bool HasComponent()
True if a component of type T is attached.
GameObject * GetParent() const
void AddComponent(Args &&... args)
Constructs and attaches a component of type T. Warns and no-ops if one already exists.
const List< GameObject * > & GetChildren() const
bool HasParent() const
void MarkForDestroy()
Flags the object for deferred destruction on the next scene pass.
bool IsOwnedByScene() const
True once a scene took ownership through SceneBase::AddObject().
bool IsActive() const
bool HasChildren() const
bool IsPendingDestroy() const
virtual bool IsLight() const
T * GetComponent()
Finds the first attached component of type T, or nullptr.
void SetTag(const std::string &tag)
GameObject(const std::string &name="GameObject")
static GameObject * CreateTorus(Math::Vector3D position, int segments=16, int rings=8, float innerRadius=8, float outerRadius=9)
friend class SceneBase
bool IsInitialized() const
const std::string & GetTag() const
void RemoveComponent()
Destroys and detaches the first component of type T, if present.
Implements a dynamic array-like list for storing and managing a collection of elements.
Definition List.hpp:20
Object(const std::string &name="Object")
Definition Object.hpp:14
T * get() const
Definition RefPtr.hpp:170
Vectors, matrices, quaternions, colors, AABBs, and random helpers.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10