初始化obs/Unity仓库

This commit is contained in:
2026-05-03 14:06:26 +08:00
commit 0d9e5282f3
95 changed files with 14419 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
### **Unity 场景物体查找API核心笔记**
在Unity中,动态查找场景中的游戏对象(GameObject)或组件(Component)是一项基本操作。不同的API适用于不同的场景,理解它们的区别和性能开销至关重要。
#### **一、 全局场景查找 (Scene-Wide Search)**
这类API会遍历整个场景的层级树来寻找匹配的对象。**它们的共同点是性能开销较大,绝对禁止在 `Update()``FixedUpdate()` 等高频函数中每帧调用。** 最适合在 `Awake()``Start()` 中用于初始化引用。
1. **按名称查找:`GameObject.Find()`**
- **API:** `public static GameObject Find(string name);`
- **作用:** 根据物体的**确切名称**查找一个**激活的(active)**游戏对象。如果存在多个同名对象,它会返回哪一个是不确定的。
- **返回:** `GameObject`。如果找不到则返回 `null`
- **笔记:** 这是最不推荐的查找方式之一。因为它依赖于硬编码的字符串,当场景中物体改名时代码就会失效。性能非常差,应尽量避免使用。
2. **按标签查找:`FindWithTag()` / `FindGameObjectsWithTag()`**
- **API (单个):** `public static GameObject FindWithTag(string tag);`
- **API (多个):** `public static GameObject[] FindGameObjectsWithTag(string tag);`
- **作用:** 根据标签(Tag)查找一个或所有激活的游戏对象。标签需要在Inspector中预先为GameObject设置。
- **返回:** 单个返回 `GameObject`,多个返回 `GameObject[]` 数组。
- **笔记:** 比按名字查找要好,因为它不依赖于具体名称,更灵活。但本质上仍然需要遍历场景,性能开销依然很大。
3. **按组件类型查找:`FindObjectOfType()` / `FindObjectsOfType()` (常用)**
- **API (单个):** `public static T FindObjectOfType<T>() where T : Object;`
- **API (多个):** `public static T[] FindObjectsOfType<T>() where T : Object;`
- **作用:** 查找场景中挂载了特定组件 `T` 的一个或所有激活的对象。`T` 可以是任何继承自 `Component` 的脚本或Unity内置组件(如 `Camera`, `Light`)。
- **返回:** 单个返回组件 `T` 的引用,多个返回 `T[]` 数组。
- **笔记:** 这是最常用和推荐的**全局查找**方法。它不依赖名称或标签,而是直接关联代码逻辑(组件类型),更加健壮。但同样,性能开销大,**仅限初始化时使用**。
- **现代化替代方案:** Unity 推荐使用 `FindAnyObjectByType<T>()``FindObjectsByType<T>(...)` 作为更新、性能更好的替代品。
#### **二、 局部层级查找 (Hierarchy Search)**
这类API只在当前GameObject的子级或父级中进行查找,范围小,**性能远高于全局查找**。
1. **在自身上查找组件:`GetComponent<T>()`**
- **API:** `public T GetComponent<T>();`
- **作用:** 获取挂载在**同一个**游戏对象上的组件 `T`
- **笔记:** 这是最常用、最高效的获取自身组件的方法。
2. **在子级中查找:`transform.Find()` / `GetComponentInChildren<T>()`**
- **API (按名找子物体):** `public Transform transform.Find(string name);`
- **API (按组件找子物体):** `public T GetComponentInChildren<T>();`
- **作用:**
- `transform.Find()`: 根据名称查找一个**直接子级**的 `Transform`。注意,它不会递归查找孙子级。
- `GetComponentInChildren<T>()`: 查找自身或其**所有子级**(包括孙子级等)中第一个挂载了组件 `T` 的对象。
- **笔记:** `GetComponentInChildren` 非常适合用来获取预制体(Prefab)内部的某个部件,例如获取枪械模型上的“枪口特效”组件。
3. **在父级中查找:`GetComponentInParent<T>()`**
- **API:** `public T GetComponentInParent<T>();`
- **作用:** 查找自身或其**所有父级**中第一个挂载了组件 `T` 的对象。
- **笔记:** 常用于UI或模块化设计。例如,一个按钮可以向上查找到它所属的那个“根面板”控制器脚本。
---
### **三、 性能与最佳实践总结 (至关重要)**
| 方法 | 查找范围 | 性能 | 推荐用法 |
| ------------------------ | -------- | ----------- | ------------------------------------------------------------------- |
| **公开变量引用** | 无 (手动指定) | **极高 (最佳)** | **首选方案!** 在脚本中声明 `public GameObject myObject;`,然后在Inspector中手动拖拽赋值。 |
| `GetComponent<T>` | 自身 | 非常高 | 在 `Awake`/`Start` 中获取自身其他组件。 |
| `GetComponentInChildren` | 自身及所有子级 | 较高 | 初始化时获取Prefab内部的固定部件。 |
| `GetComponentInParent` | 自身及所有父级 | 较高 | 模块化组件向上查找控制器或根对象。 |
| `FindObjectsOfType<T>` | 整个场景 | **很低** | **仅限**在管理器类的 `Awake` 中,用于查找并注册场景中所有特定类型的对象。 |
| `GameObject.Find()` | 整个场景 | **极低 (最差)** | **强烈不推荐**,仅用于快速原型或调试,正式项目中应被替换。 |
#### **核心原则笔记:**
1. **首选“拖拽引用”:** 在脚本中声明一个 `public``[SerializeField] private` 变量,然后在Unity编辑器里手动将场景中的物体拖拽到该变量上。这是**零开销**、最安全、最高效的方式。
2. **“Find”仅用于初始化:** 所有全局查找 (`Find`, `FindObjectOfType` 等) 都应该只在 `Awake()``Start()` 函数中调用**一次**,并将结果缓存到一个私有变量中,供后续使用。
3. **杜绝在Update中使用Find** **永远不要**在 `Update()`, `FixedUpdate()`, `LateUpdate()` 中直接调用任何全局查找API。这是导致游戏卡顿的常见原因之一。
4. **善用局部查找:** 当物体关系固定时(如Prefab内部),优先使用 `GetComponentInChildren``transform.Find`,它们的性能远好于全局查找。