目录
(3)FindGameObjectWithTag("Tag")
(4)FindGameObjectsWithTag("Tag")
一、GameObject是什么
GameObject是Unity场景中所有实体的基础容器,代表场景中的一个独立对象。就像下面一样,我创建了一个空对象,最右侧的Insoector面板上面显示的就是这个对象的基本内容,它包含了一些最基本的识别编号,他是作为其他组件的挂载池,是最最基本的组件。本质来说他也是组件,是组件,就会有自己的属性,成员变量,以及成员方法,所以我们来看看它有哪些内容。
其核心特性包括:
- 组件容器:本身无功能,需挂载组件(如Transform、脚本、Collider等)实现具体行为。
- 层级结构:通过Transform组件形成父子层级,实现对象间的相对坐标和批量控制。
- 生命周期:由引擎管理创建、激活、销毁等状态,与场景加载/卸载紧密相关。
- 唯一标识:每个GameObject具有唯一实例ID,可通过名称(name)或标签(tag)访问。
二、GameObject中的成员属性及变量
属性/变量 | 作用 | 注意事项 | 代码示例 |
---|---|---|---|
name | 对象名称标识(可重复) | 修改后会影响Find 方法的结果 | gameObject.name = "Player"; |
activeSelf | 自身激活状态(不受父对象影响) | 直接控制对象显隐,但父对象失活时仍不可见 | bool isActive = gameObject.activeSelf; |
activeInHierarchy | 实际激活状态(受父对象链影响) | 只读属性,反映对象在场景中的真实可见性 | if (gameObject.activeInHierarchy) { } |
isStatic | 标记为静态对象(参与光照烘焙等优化) | 运行时修改可能导致性能开销 | gameObject.isStatic = true; |
layer | 所属层级(0-31) | 需配合LayerMask 使用,常用于射线检测或摄像机过滤 | gameObject.layer = 8; |
tag | 标签分类 | 优先用CompareTag 替代字符串比较 | if (gameObject.tag == "Enemy") { } |
transform | 控制位置、旋转、父子关系 | 修改时会触发物理引擎更新 | Vector3 pos = gameObject.transform.position; |
关于上面的属性的演示说明:
(1)修改名字
// 1. 修改本对象名称
this.gameObject.name = "ModifiedObject";
Debug.Log("当前对象名称: " + gameObject.name);
可见成功修改
(2)打印里面包含的激活状态
// 2. 打印激活状态
Debug.Log("--- 激活状态 ---");
Debug.Log("activeSelf: " + gameObject.activeSelf);
Debug.Log("activeInHierarchy: " + gameObject.activeInHierarchy);
(3)静态属性的修改 ,注意看这里打上了√
// 3. 打印静态标记状态
gameObject.isStatic = true; // 设置静态标记(实际项目慎用)
Debug.Log("--- 静态状态 ---");
Debug.Log("isStatic: " + gameObject.isStatic);
(4) 打印层级和标签信息
// 4. 打印层级信息
gameObject.layer = LayerMask.NameToLayer("UI"); // 设置层级
Debug.Log("--- 层级信息 ---");
Debug.Log("Layer数值: " + gameObject.layer);
Debug.Log("Layer名称: " + LayerMask.LayerToName(gameObject.layer));
// 5. 打印标签信息
Debug.Log("--- 标签信息 ---");
Debug.Log("当前标签: " + gameObject.tag);
Debug.Log("是否Player标签: " + gameObject.CompareTag("Player"));
(5) 打印transform中的信息
// 6. 打印变换组件信息
Debug.Log("--- 变换信息 ---");
Debug.Log("位置: " + transform.position);
Debug.Log("旋转: " + transform.rotation.eulerAngles);
Debug.Log("缩放: " + transform.localScale);
(6) 父对象失活对子对象的影响
// 7. 父对象激活状态影响演示
GameObject parentObj = new GameObject("ParentObject");
transform.SetParent(parentObj.transform);
Debug.Log("--- 父子关系测试 ---");
Debug.Log("父对象激活前 activeInHierarchy: " + gameObject.activeInHierarchy);
parentObj.SetActive(false);
Debug.Log("父对象激活后 activeInHierarchy: " + gameObject.activeInHierarchy);
这就像小时候,你家长要睡觉了,非要让你也睡觉
三、GameObject中的静态方法
方法 | 作用 | 注意事项 | 代码示例 |
---|---|---|---|
CreatePrimitive | 创建基本几何体 | 默认无碰撞体(如不需要可手动移除) | GameObject.CreatePrimitive(PrimitiveType.Sphere); |
Find("Name") | 按名称查找单个激活对象 | 效率低,避免在Update 中频繁调用 | GameObject obj = GameObject.Find("Cube"); |
FindGameObjectWithTag("Tag") | 按标签查找单个激活对象 | 需预先在标签管理器中定义标签 | GameObject player = GameObject.FindGameObjectWithTag("Player"); |
FindGameObjectsWithTag("Tag") | 按标签查找所有激活对象 | 返回数组,需判空处理 | GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy"); |
FindObjectOfType<T>() | 查找挂载某类型脚本的激活对象 | 无法查找禁用脚本 | Camera cam = GameObject.FindObjectOfType<Camera>(); |
Instantiate(original) | 克隆对象或预制体 | 高频调用需优化(如对象池) | GameObject clone = GameObject.Instantiate(prefab); |
Destroy(obj) | 销毁对象或组件 | 延迟到帧末尾执行,DestroyImmediate 慎用 | GameObject.Destroy(enemy, 3.0f); //3秒后销毁 |
DontDestroyOnLoad(obj) | 跨场景保留对象 | 需手动管理生命周期 | GameObject.DontDestroyOnLoad(gameObject); |
逐个解释:
(1)CreatePrimitive
作用:创建自带基础几何体的GameObject
注意事项:默认自带碰撞体,无刚体,需手动添加Rigidbody组件
支持几何体类型(PrimitiveType
枚举):
几何体类型 | 描述 |
---|---|
Cube | 立方体 |
Sphere | 球体 |
Capsule | 胶囊体 |
Cylinder | 圆柱体(旧版) |
Plane | 平面(大尺寸地面) |
Quad | 四边形(小尺寸面片) |
看,作为造世主的你创建了一个球。值得注意的是,你的脚本必选先挂载到场景上的某一个对象上才能执行
// 创建球体并设置位置
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
(2) Find("Name")
作用:通过名称查找单个激活对象
注意事项:全局遍历效率低,避免高频调用
代码示例:
// 查找名为 "Player" 的对象
GameObject player = GameObject.Find("Player");
if (player != null) {
Debug.Log("找到玩家对象: " + player.name);
player.transform.position = Vector3.zero; // 重置位置
} else {
Debug.LogWarning("未找到玩家对象");
}
(3)FindGameObjectWithTag("Tag")
作用:通过标签查找单个激活对象
注意事项:需在标签管理器预定义标签
代码示例:
// 查找标签为 "Enemy" 的单个对象
GameObject enemy = GameObject.FindGameObjectWithTag("Enemy");
if (enemy != null) {
Debug.Log("发现敌人: " + enemy.name);
}
(4)FindGameObjectsWithTag("Tag")
作用:通过标签查找所有激活对象们,这个就是上面的多个情况
注意事项:返回数组需判空或检查长度。如果场景中 存在多个满足条件的对象,我们无法准确确定知道的是谁
代码示例:
// 查找所有标签为 "Item" 的对象
GameObject[] items = GameObject.FindGameObjectsWithTag("Item");
if (items.Length > 0)
{
Debug.Log("找到 " + items.Length + " 个可拾取物品");
foreach (GameObject item in items)
{
item.SetActive(false); // 隐藏所有物品
}
}
(5) FindObjectOfType()
作用:查找场景中挂载某类型脚本的激活对象
注意事项:无法查找禁用脚本
代码示例:
// 查找场景中第一个激活的摄像机
Camera mainCamera = GameObject.FindObjectOfType<Camera>();
if (mainCamera != null) {
mainCamera.backgroundColor = Color.blue; // 修改背景颜色
}
(6)Instantiate
作用:克隆预制体或场景对象 实例化对象 它的作用是根据GameObject对象 创建出一个和他一模一样的GameObject对象
注意事项:高频调用需用对象池优化
代码示例:
GameObject objClone = GameObject.Instantiate(myObj);
(7)Destroy
作用:延迟销毁对象或组件
注意事项:
删除对象有两种作用
1.是删除指定的一个游戏对象
2.是删除一个指定的脚本对象
注意:这个Destroy的方法 不会马上移除对象 只是给这个对象加了一个移除标识
一般情况下 他会在下一帧时把这个对象移除并从内存中移除
下面这个方法就是立即把对象从内存中移除了
GameObject.DestroyImmediate(objClone);
没有特殊需求 就是一定要马上移除一个对象的话
建议使用上面的Destroy方法 因为是异步的 降低卡顿的几率
如果是继承MonoBehavior的类 不用再写GameObject
直接调用函数
代码示例:
// 3秒后销毁本对象
Destroy(gameObject, 3.0f);
// 仅销毁脚本组件(保留GameObject)
// Destroy(this);
(8)DontDestroyOnLoad
作用:跨场景保留对象
注意事项:需手动管理生命周期
默认情况 在切换场景时 场景中对象都会被自动删除掉
如果你希望某个对象再过场景的时候不被移除 就使用下面这个方法
下面这句代码的意思就是 自己依附的GameObject对象在过场景的时候不被移除
一般都是传依附的GameObject对象
代码示例:
GameObject.DontDestroyOnLoad(this.gameObject);
小结:
①基础几何体创建与组件操作
通过 GameObject.CreatePrimitive
方法可快速生成基础几何体(立方体、球体等),生成的对象默认包含网格渲染器和碰撞体组件。创建后需注意:
可手动移除不需要的碰撞体组件以优化性能
通过
GetComponent
获取对象上的任意脚本或组件进行后续操作动态添加新组件使用
AddComponent
,例如为对象添加刚体实现物理效果
②对象查找方法与限制
Unity 提供多种对象查找方式,核心方法包括:
按名称查找:
GameObject.Find
全局遍历场景对象,效率较低按标签查找:
FindGameObjectWithTag
(单个)和FindGameObjectsWithTag
(多个),需预定义标签
- 按脚本查找:
FindObjectOfType
遍历场景中激活的脚本实例
共同限制:无法查找失活对象,存在多个匹配对象时返回结果不确定,高频调用需用缓存优化
③ 对象克隆与销毁机制
使用 Instantiate
克隆对象时会完整复制原对象的所有组件和子对象:
适合生成敌人、子弹等动态对象
高频克隆需配合对象池技术避免性能问题
销毁操作通过Destroy
实现:默认延迟到帧末尾异步执行,避免卡顿
DestroyImmediate
立即移除对象,但易导致空引用问题可指定销毁延迟时间,例如
Destroy(obj, 5.0f)
④ 跨场景对象生命周期控制
通过 DontDestroyOnLoad
方法保留对象跨场景:
常用于全局管理对象如音效控制器、游戏存档
需配合单例模式防止重复创建
手动管理保留对象的销毁时机,避免内存泄漏
⑤Unity 与 C# 对象系统差异
UnityEngine.Object
继承自 C# 的System.Object
,包含 Unity 特有的资源管理逻辑Unity 对象销毁为标记移除,实际内存回收由引擎管理
静态方法如
Destroy
可直接调用,无需通过GameObject
类名Unity里面的Object 不是指的万物之父object
Unity里的Object 命名空间在UnityEngine.Object类 也是继承万物之父的一个自定义类
C#中的Object 命名空间是System中的
四、GameObject中的成员方法
方法 | 作用 | 注意事项 | 代码示例 |
---|---|---|---|
AddComponent<T>() | 动态添加组件或脚本 | 不可添加重复组件 | Rigidbody rb = gameObject.AddComponent<Rigidbody>(); |
SetActive(bool) | 激活/禁用对象 | 禁用后停止所有组件更新(如Update ) | gameObject.SetActive(false); //隐藏对象 |
CompareTag("Tag") | 安全比较标签 | 避免拼写错误,性能优于字符串比较 | if (gameObject.CompareTag("Player")) { } |
SendMessage("MethodName") | 调用对象所有脚本的指定方法 | 反射调用性能较差,优先用组件直接访问 | gameObject.SendMessage("TakeDamage", 10); |
BroadcastMessage("MethodName") | 向自身及子对象发送消息 | 可能引发意外副作用 | gameObject.BroadcastMessage("Respawn"); |
SendMessageUpwards("MethodName") | 向自身及父对象发送消息 | 慎用,易导致循环调用 | gameObject.SendMessageUpwards("ApplyGravity"); |
123都不用讲了,这个方法很容易就理解了,我们来看看后面三个方法 ,一般来说,用处不大,除非你有什么特殊需求。
//通过广播或者发送消息的形式 让别人或者自己 执行某些行为的方法
//通知自己 执行什么行为
//命令自己 去执行这个TestFun这个函数 会在自己身上挂载的所有脚本中去找这个名字的函数
this.gameObject.SendMessage("TestFun");
//会把自己身上的所有脚本中的TestFun函数都执行一遍 别的脚本也会执行 所有脚本中有这个名字的函数去执行
//名字加参数可以直接放在括号里面 this.gameObject.SendMessage("TestFun",154);//广播行为 让自己和自己的子物体都执行这个函数
this.gameObject.BroadcastMessage("TestFun");//向父对象和自己发送信息 并执行
this.gameObject.SendMessageUpwards("函数名");
没啦,就这样,下期见!