ShitEngine 1.4.2
基于 C++20 与 SDL3 的轻量级 2D 游戏引擎
载入中...
搜索中...
未找到
GameObject.h
浏览该文件的文档.
1#pragma once
2#include <string>
3#include <unordered_map>
4#include <typeindex>
5#include <memory>
6#include <utility>
7
8#include "../Core/Config.h"
12#include "../Scene/Scene.h"
13
14namespace Shit {
15 class Scene; // 前向声明
16 template <typename T> class WeakComponentRef; // 前向声明(组件弱引用,见文件末尾定义)
17
23 class SHIT_API GameObject final {
24 friend class Scene;
25 private:
26 GameObject(const std::string& name);
27
28 public:
29 ~GameObject() = default;
30
31 // 禁止拷贝和移动
32 GameObject(const GameObject&) = delete;
33 GameObject& operator=(const GameObject&) = delete;
34 GameObject(GameObject&&) = delete;
35 GameObject& operator=(GameObject&&) = delete;
36
37 void destroy();
38
39 // --- 父子关系 ---
47 void setParent(GameObject* parent);
48
49 GameObject* getParent() const { return m_parent; }
50 const std::vector<GameObject*>& getChildren() const { return m_children; }
51
53 void addChild(GameObject* child) { if (child) child->setParent(this); }
54
55 // --- getter & setter ---
56 const std::string& getName() const { return m_name; }
57 const std::string& getTag() const { return m_tag; }
58 Scene* getScene() const { return m_scene; }
59 bool isNeedDestroy() const { return m_needDestroy; }
60
62 bool isActive() const { return m_active; }
64 bool isActiveInHierarchy() const {
65 if (!m_active) return false;
66 for (const GameObject* p = m_parent; p; p = p->m_parent)
67 if (!p->m_active) return false;
68 return true;
69 }
70 void setActive(bool active) {
71 if (active == m_active) return;
72 m_active = active; // 渲染/行为/UI/物理按 isActiveInHierarchy 过滤
73 if (m_scene) m_scene->bumpGeneration();
74 }
75
76 void setName(const std::string& name) {
77 if (name == m_name) return;
78 m_name = name; // 场景树显示名随结构变更同步(编辑器据此刷新树)
79 if (m_scene) m_scene->bumpGeneration();
80 }
81 void setTag(const std::string& tag) {
82 if (tag == m_tag) return;
83 m_tag = tag; // 编辑器属性面板可编辑,改后需联动刷新
84 if (m_scene) m_scene->bumpGeneration();
85 }
86 void setScene(Scene* scene);
87 void setNeedDestroy(bool needDestroy) { m_needDestroy = needDestroy; }
88 std::unordered_map<std::type_index, std::unique_ptr<Component>>& getComponents() { return m_components; }
89
93 template <typename Fn>
94 void forEachComponent(Fn&& fn) {
95 std::vector<Component*> snapshot;
96 snapshot.reserve(m_components.size());
97 for (auto& [type, comp] : m_components) {
98 if (comp) snapshot.push_back(comp.get());
99 }
100 for (Component* comp : snapshot) {
101 bool owned = false;
102 for (auto& [type, c] : m_components) {
103 if (c.get() == comp) { owned = true; break; }
104 }
105 if (owned) fn(comp);
106 }
107 }
108
110 template <typename T>
112 return WeakComponentRef<T>(this, m_lifetime);
113 }
114
121
129 template <typename T, typename... Args>
130 T* addComponent(Args&&... args) {
131 static_assert(std::is_base_of_v<Component, T>, "添加的组件必须继承自 Component!");
132
133 auto type_index = std::type_index(typeid(T));
134
135 if (hasComponent<T>()) { // 是否已经存在
136 return getComponent<T>();
137 }
138
139 // 创建组件
140 auto new_component = std::make_unique<T>(std::forward<Args>(args)...);
141 T* new_component_ptr = new_component.get();
142 new_component->setOwner(this);
143
144 // 先插入容器,再触发生命周期回调。若 onAttach/onCreate 内销毁了 owner
145 //(如 removeGameObject 立即清理),对已释放对象写 map 会堆破坏;先入表则
146 // 回调内可以安全地把自己移除,clean() 也能遍历到它。
147 m_components[type_index] = std::unique_ptr<Component>(new_component.release());
148 if (m_scene) m_scene->bumpGeneration(); // 组件结构变更:通知场景代数递增
149
150 // 捕获回调可能用到的数据:回调内可能销毁 owner(this),之后不能再触碰 this
151 Scene* scene = m_scene;
152 std::weak_ptr<void> lifetime = m_lifetime;
153 const std::string goName = m_name;
154
155new_component_ptr->onCreate(); // onCreate:轻量初始化
156 if (lifetime.expired()) return nullptr; // 回调销毁了 owner → 组件已随 clean() 释放
157
158 // onCreate 回调可能 removeComponent 移除了本组件(owner 存活时 lifetime 检查不生效),
159 // 先确认组件仍归属本对象,再 isRegistered/onAttach,避免解引用已析构实例
160 {
161 auto it = m_components.find(type_index);
162 if (it == m_components.end() || it->second.get() != new_component_ptr) return nullptr;
163 }
164
165 // 若已挂载场景则立即执行 onAttach(注册到 System)。
166 // 注册状态由组件自身的 onAttach 维护(基类默认置 true),此处不强制置位,
167 // 以便"组件先加、驱动系统后注册"时能被 System::init 补挂。
168 if (scene && !new_component_ptr->isRegistered()) {
169 new_component_ptr->onAttach();
170 }
171 if (lifetime.expired()) return nullptr; // onAttach 销毁了 owner
172
173 // P20: 组件 UUID 入场景索引(引用字段寻址;幂等,与 setScene 全量 sweep 兼容)
174 // 防御:onCreate/onAttach 回调可能已 removeComponent 移除并析构本组件
175 //(owner 未销毁时 lifetime 检查不生效),先确认组件仍归属本对象再索引。
176 if (scene) {
177 auto it = m_components.find(type_index);
178 if (it != m_components.end() && it->second.get() == new_component_ptr) {
179 scene->indexComponentUuid(new_component_ptr);
180 }
181 }
182
183 ST_CORE_TRACE("GameObject : {} 已添加 组件 {}", goName, typeid(T).name());
184
185 return new_component_ptr;
186 }
187
193 template <typename T>
195 static_assert(std::is_base_of_v<Component, T>, "获取的组件必须继承自 Component!");
196 auto type_index = std::type_index(typeid(T));
197
198 if (auto it = m_components.find(type_index); it != m_components.end()) {
199 return static_cast<T*>(it->second.get());
200 }
201 return nullptr;
202 }
203
209 template <typename T>
211 static_assert(std::is_base_of_v<Component, T>, "检查的组件必须继承自 Component!");
212
213 return m_components.contains(std::type_index(typeid(T)));
214 }
215
222 template <typename T>
224 static_assert(std::is_base_of_v<Component, T>, "移除的组件必须继承自 Component!");
225 removeComponent(std::type_index(typeid(T)));
226 }
227
232 void removeComponent(const std::type_index &typeIndex) {
233 if (auto it = m_components.find(typeIndex); it != m_components.end()) {
234 // 先从容器取出再调回调,避免回调内再次 removeComponent 造成迭代器失效/重复回调
235 auto comp = std::move(it->second);
236 m_components.erase(it);
237 if (m_scene) m_scene->bumpGeneration(); // 组件结构变更:通知场景代数递增
238 // P20: 组件 UUID 出索引(引用字段随即失效;onDetach 内再 unregister 也幂等)
239 if (m_scene) m_scene->unindexComponentUuid(comp.get());
240 comp->onDetach();
241 comp->onDestroy();
242 }
243 }
244
245 private:
246 void clean(); // 清理(只能 Scene 调用)
247 void removeFromParentChildren(); // 从当前父物体的子列表中移除自己
248
249 std::string m_name; // 游戏物体名称
250 std::string m_tag; // 标签
251 bool m_active = true; // 是否启用(失活对象不渲染/不更新行为/UI/物理,随父链级联)
252 Scene* m_scene = nullptr; // 所在 Scene 指针
253 std::unordered_map<std::type_index, std::unique_ptr<Component>> m_components; // 挂载的组件
254 bool m_needDestroy = false; // 是否需要销毁(由 Scene 负责销毁)
255
256 GameObject* m_parent = nullptr; // 父物体(裸指针,所有权归 Scene)
257 std::vector<GameObject*> m_children; // 子物体列表(裸指针,仅表达层级)
258
259 // 生命周期令牌:本对象随 unique_ptr 销毁时,所有持 weak_ptr 的 WeakComponentRef 自动失效,
260 // 避免 WeakComponentRef 在 owner 已被销毁后解引用悬垂的 GameObject 指针。
261 std::shared_ptr<void> m_lifetime = std::make_shared<int>(0);
262 };
263
280 template <typename T>
282 public:
283 WeakComponentRef() = default;
284 explicit WeakComponentRef(GameObject* owner, const std::weak_ptr<void>& lifetime)
285 : m_owner(owner), m_lifetime(lifetime) {}
286
288 T* get() const {
289 if (!m_owner || m_lifetime.expired()) return nullptr;
290 return m_owner->template getComponent<T>();
291 }
292
294 bool valid() const { return get() != nullptr; }
295
297 T* operator->() const { return get(); }
298 explicit operator bool() const { return valid(); }
299
301 GameObject* getOwner() const { return m_owner; }
302
303 private:
304 GameObject* m_owner = nullptr;
305 std::weak_ptr<void> m_lifetime;
306 };
307}
#define SHIT_API
定义 Core.h:14
#define ST_CORE_TRACE(...)
定义 Log.h:67
组件基类
定义 Component.h:25
游戏物体类
定义 GameObject.h:23
~GameObject()=default
friend class Scene
定义 GameObject.h:24
void setNeedDestroy(bool needDestroy)
定义 GameObject.h:87
void setParent(GameObject *parent)
设置父物体
void addChild(GameObject *child)
添加子物体(等价于 child->setParent(this))
定义 GameObject.h:53
Scene * getScene() const
定义 GameObject.h:58
const std::vector< GameObject * > & getChildren() const
获取子物体列表
定义 GameObject.h:50
bool isActive() const
自身启用标志(isActiveInHierarchy 为含父链的最终生效状态)
定义 GameObject.h:62
void setScene(Scene *scene)
设置所属场景(同时触发未注册组件的 onAttach)
void destroy()
标记为待销毁(帧末由 Scene 统一清理);级联标记所有子物体
const std::string & getName() const
定义 GameObject.h:56
GameObject & operator=(const GameObject &)=delete
Component * addComponentInstance(Component *component)
动态添加组件实例(Prefab 实例化等反射场景用,所有权转移给 GameObject)
GameObject * getParent() const
获取父物体
定义 GameObject.h:49
GameObject & operator=(GameObject &&)=delete
void removeComponent()
移除某个组件
定义 GameObject.h:223
void setTag(const std::string &tag)
定义 GameObject.h:81
void forEachComponent(Fn &&fn)
只读遍历全部组件(供系统补扫等使用,避免暴露内部可变 map) 安全遍历:先快照指针再逐回调,且回调前重验组件仍归属本对象—— 回调内 removeComponent 修改 map 不会使迭代器失效,已...
定义 GameObject.h:94
std::unordered_map< std::type_index, std::unique_ptr< Component > > & getComponents()
获取全部组件(按 type_index 索引)
定义 GameObject.h:88
void setActive(bool active)
定义 GameObject.h:70
void setName(const std::string &name)
定义 GameObject.h:76
bool hasComponent()
检查是否存在某个组件
定义 GameObject.h:210
T * addComponent(Args &&... args)
添加组件
定义 GameObject.h:130
bool isActiveInHierarchy() const
层级生效状态:自身与所有祖先都启用(Unity 语义:父失活子随失活)
定义 GameObject.h:64
GameObject(const GameObject &)=delete
WeakComponentRef< T > getWeakRef()
创建指向本对象上 T 组件的弱引用(组件被移除/对象销毁后自动失效)
定义 GameObject.h:111
T * getComponent()
获取组件
定义 GameObject.h:194
void removeComponent(const std::type_index &typeIndex)
按类型索引移除组件(编辑器/反射场景用,与 removeComponent<T>() 等价)
定义 GameObject.h:232
GameObject(GameObject &&)=delete
const std::string & getTag() const
定义 GameObject.h:57
bool isNeedDestroy() const
定义 GameObject.h:59
场景类
定义 Scene.h:36
组件弱引用
定义 GameObject.h:281
bool valid() const
组件当前是否有效(onAttach 后、removeComponent 前,且 owner 未被销毁)
定义 GameObject.h:294
T * operator->() const
便捷解引用(调用前建议先 valid() 检查或直接解引用判空)
定义 GameObject.h:297
WeakComponentRef(GameObject *owner, const std::weak_ptr< void > &lifetime)
定义 GameObject.h:284
GameObject * getOwner() const
获取所属 GameObject(可能已被销毁,调用方需自行保证安全)
定义 GameObject.h:301
T * get() const
获取组件(组件已移除或对象已销毁则返回 nullptr)
定义 GameObject.h:288
定义 AnimationClip.h:12
@ T
定义 KeyCode.h:37