ShitEngine
基于 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
61 void setName(const std::string& name) { m_name = name; }
62 void setTag(const std::string& tag) { m_tag = tag; }
63 void setScene(Scene* scene);
64 void setNeedDestroy(bool needDestroy) { m_needDestroy = needDestroy; }
65 std::unordered_map<std::type_index, std::unique_ptr<Component>>& getComponents() { return m_components; }
66
68 template <typename Fn>
69 void forEachComponent(Fn&& fn) {
70 for (auto& [type, comp] : m_components) {
71 if (comp) fn(comp.get());
72 }
73 }
74
76 template <typename T>
78 return WeakComponentRef<T>(this, m_lifetime);
79 }
80
88
95
96 template <typename T, typename... Args>
97 T* addComponent(Args&&... args) {
98 static_assert(std::is_base_of_v<Component, T>, "添加的组件必须继承自 Component!");
99
100 auto type_index = std::type_index(typeid(T));
101
102 if (hasComponent<T>()) { // 是否已经存在
103 return getComponent<T>();
104 }
105
106 // 创建组件
107 auto new_component = std::make_unique<T>(std::forward<Args>(args)...);
108 T* new_component_ptr = new_component.get();
109 new_component->setOwner(this);
110
111 // 先插入容器,再触发生命周期回调。若 onAttach/onCreate 内销毁了 owner
112 //(如 removeGameObject 立即清理),对已释放对象写 map 会堆破坏;先入表则
113 // 回调内可以安全地把自己移除,clean() 也能遍历到它。
114 m_components[type_index] = std::unique_ptr<Component>(new_component.release());
115
116 // 捕获回调可能用到的数据:回调内可能销毁 owner(this),之后不能再触碰 this
117 Scene* scene = m_scene;
118 std::weak_ptr<void> lifetime = m_lifetime;
119 const std::string goName = m_name;
120
121 new_component_ptr->onCreate(); // onCreate:轻量初始化
122 if (lifetime.expired()) return nullptr; // 回调销毁了 owner → 组件已随 clean() 释放
123
124 // 若已挂载场景则立即执行 onAttach(注册到 System)。
125 // 注册状态由组件自身的 onAttach 维护(基类默认置 true),此处不强制置位,
126 // 以便"组件先加、驱动系统后注册"时能被 System::init 补挂。
127 if (scene && !new_component_ptr->isRegistered()) {
128 new_component_ptr->onAttach();
129 }
130 if (lifetime.expired()) return nullptr; // onAttach 销毁了 owner
131
132 ST_CORE_TRACE("GameObject : {} 已添加 组件 {}", goName, typeid(T).name());
133
134 return new_component_ptr;
135 }
136
142 template <typename T>
144 static_assert(std::is_base_of_v<Component, T>, "获取的组件必须继承自 Component!");
145 auto type_index = std::type_index(typeid(T));
146
147 if (auto it = m_components.find(type_index); it != m_components.end()) {
148 return static_cast<T*>(it->second.get());
149 }
150 return nullptr;
151 }
152
158 template <typename T>
160 static_assert(std::is_base_of_v<Component, T>, "检查的组件必须继承自 Component!");
161
162 return m_components.contains(std::type_index(typeid(T)));
163 }
164
171 template <typename T>
173 static_assert(std::is_base_of_v<Component, T>, "移除的组件必须继承自 Component!");
174 auto type_index = std::type_index(typeid(T));
175
176 if (auto it = m_components.find(type_index); it != m_components.end()) {
177 // 先从容器取出再调回调,避免回调内再次 removeComponent 造成迭代器失效/重复回调
178 auto comp = std::move(it->second);
179 m_components.erase(it);
180 comp->onDetach();
181 comp->onDestroy();
182 }
183 }
184
185 private:
186 void clean(); // 清理(只能 Scene 调用)
187 void removeFromParentChildren(); // 从当前父物体的子列表中移除自己
188
189 std::string m_name; // 游戏物体名称
190 std::string m_tag; // 标签
191 Scene* m_scene = nullptr; // 所在 Scene 指针
192 std::unordered_map<std::type_index, std::unique_ptr<Component>> m_components; // 挂载的组件
193 bool m_needDestroy = false; // 是否需要销毁(由 Scene 负责销毁)
194
195 GameObject* m_parent = nullptr; // 父物体(裸指针,所有权归 Scene)
196 std::vector<GameObject*> m_children; // 子物体列表(裸指针,仅表达层级)
197
198 // 生命周期令牌:本对象随 unique_ptr 销毁时,所有持 weak_ptr 的 WeakComponentRef 自动失效,
199 // 避免 WeakComponentRef 在 owner 已被销毁后解引用悬垂的 GameObject 指针。
200 std::shared_ptr<void> m_lifetime = std::make_shared<int>(0);
201 };
202
219 template <typename T>
221 public:
222 WeakComponentRef() = default;
223 explicit WeakComponentRef(GameObject* owner, const std::weak_ptr<void>& lifetime)
224 : m_owner(owner), m_lifetime(lifetime) {}
225
227 T* get() const {
228 if (!m_owner || m_lifetime.expired()) return nullptr;
229 return m_owner->template getComponent<T>();
230 }
231
233 bool valid() const { return get() != nullptr; }
234
236 T* operator->() const { return get(); }
237 explicit operator bool() const { return valid(); }
238
240 GameObject* getOwner() const { return m_owner; }
241
242 private:
243 GameObject* m_owner = nullptr;
244 std::weak_ptr<void> m_lifetime;
245 };
246}
#define SHIT_API
定义 Core.h:14
#define ST_CORE_TRACE(...)
定义 Log.h:49
组件基类
定义 Component.h:20
游戏物体类
定义 GameObject.h:23
~GameObject()=default
friend class Scene
定义 GameObject.h:24
void setNeedDestroy(bool needDestroy)
定义 GameObject.h:64
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
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)
添加组件
GameObject * getParent() const
获取父物体
定义 GameObject.h:49
GameObject & operator=(GameObject &&)=delete
void removeComponent()
移除某个组件
定义 GameObject.h:172
void setTag(const std::string &tag)
设置标签(用于分类,如 "enemy"、"player")
定义 GameObject.h:62
void forEachComponent(Fn &&fn)
只读遍历全部组件(供系统补扫等使用,避免暴露内部可变 map)
定义 GameObject.h:69
std::unordered_map< std::type_index, std::unique_ptr< Component > > & getComponents()
获取全部组件(按 type_index 索引)
定义 GameObject.h:65
void setName(const std::string &name)
定义 GameObject.h:61
bool hasComponent()
检查是否存在某个组件
定义 GameObject.h:159
T * addComponent(Args &&... args)
定义 GameObject.h:97
GameObject(const GameObject &)=delete
WeakComponentRef< T > getWeakRef()
创建指向本对象上 T 组件的弱引用(组件被移除/对象销毁后自动失效)
定义 GameObject.h:77
T * getComponent()
获取组件
定义 GameObject.h:143
GameObject(GameObject &&)=delete
const std::string & getTag() const
定义 GameObject.h:57
bool isNeedDestroy() const
定义 GameObject.h:59
场景类
定义 Scene.h:34
组件弱引用
定义 GameObject.h:220
bool valid() const
组件当前是否有效(onAttach 后、removeComponent 前,且 owner 未被销毁)
定义 GameObject.h:233
T * operator->() const
便捷解引用(调用前建议先 valid() 检查或直接解引用判空)
定义 GameObject.h:236
WeakComponentRef(GameObject *owner, const std::weak_ptr< void > &lifetime)
定义 GameObject.h:223
GameObject * getOwner() const
获取所属 GameObject(可能已被销毁,调用方需自行保证安全)
定义 GameObject.h:240
T * get() const
获取组件(组件已移除或对象已销毁则返回 nullptr)
定义 GameObject.h:227
定义 AudioPlayer.h:10
@ T
定义 KeyCode.h:31