GameObject 基础
GameObject 是 Unity 中最核心的概念,场景中的所有对象都是 GameObject。本章将深入讲解 GameObject 的工作原理和使用方法。
什么是 GameObject
GameObject 是 Unity 场景中所有实体的基类。它可以代表角色、道具、特效、灯光、摄像机等任何存在于场景中的事物。
GameObject 的本质
一个 GameObject 本质上是一个容器,它本身没有任何功能,而是通过附加**组件(Component)**来实现各种功能:
GameObject (空容器)
└── Components (功能组件)
├── Transform (必需) - 定义位置、旋转、缩放
├── MeshRenderer - 渲染 3D 模型
├── Rigidbody - 物理模拟
└── 自定义脚本 - 游戏逻辑
核心原则
GameObject = 容器 + 组件集合
Unity 采用组件化架构(Component-Based Architecture),这种设计的优势在于:
- 灵活性:自由组合不同功能
- 复用性:组件可在不同对象间复用
- 解耦:功能独立,便于维护
创建 GameObject
通过编辑器创建
Hierarchy 窗口右键菜单:
右键点击 Hierarchy 窗口空白处
├── 3D Object # 3D 对象
│ ├── Cube # 立方体
│ ├── Sphere # 球体
│ ├── Capsule # 胶囊体
│ ├── Cylinder # 圆柱体
│ ├── Plane # 平面
│ └── Quad # 四边形
├── 2D Object # 2D 对象
│ ├── Sprite # 精灵
│ ├── Square # 正方形
│ ├── Circle # 圆形
│ └── Tilemap # 瓦片地图
├── Effects # 特效
│ ├── Particle System # 粒子系统
│ └── Trail # 轨迹
├── Light # 灯光
├── Audio # 音频
├── Video # 视频
├── UI # 用户界面
└── Create Empty # 创建空对象
通过代码创建
using UnityEngine;
public class CreateObjectExample : MonoBehaviour
{
void Start()
{
// 方法1:创建空 GameObject
GameObject emptyObject = new GameObject("MyEmptyObject");
// 方法2:创建基本 3D 对象
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = "MyCube";
// 方法3:实例化预制体(Prefab)
// GameObject instance = Instantiate(prefabReference);
// 设置父对象
cube.transform.SetParent(emptyObject.transform);
}
}
创建基本图元
Unity 提供了几种内置的基本几何体:
// 创建立方体
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
// 创建球体
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
// 创建胶囊体
GameObject capsule = GameObject.CreatePrimitive(PrimitiveType.Capsule);
// 创建圆柱体
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
// 创建平面
GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
关于 Quad 和 Plane
- Quad:1x1 单位大小的单面四边形,适合 UI 和 2D 效果
- Plane:10x10 单位大小的单面平面,适合作为地面
组件系统详解
Transform 组件
每个 GameObject 都必须有 Transform 组件,它是唯一不能移除的组件。
// 获取 Transform 组件
Transform trans = gameObject.transform;
// 常用属性
Vector3 position = trans.position; // 世界坐标位置
Vector3 localPosition = trans.localPosition; // 本地坐标位置
Quaternion rotation = trans.rotation; // 世界坐标旋转
Vector3 eulerAngles = trans.eulerAngles; // 欧拉角(度)
Vector3 localScale = trans.localScale; // 本地缩放
// 常用方法
trans.Translate(Vector3.forward); // 平移
trans.Rotate(Vector3.up, 90f); // 旋转
trans.LookAt(target); // 看向目标
添加和移除组件
通过编辑器:
- 选中 GameObject
- Inspector 窗口点击 Add Component
- 搜索并选择需要的组件
通过代码:
// 添加组件
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
BoxCollider collider = gameObject.AddComponent<BoxCollider>();
// 获取组件
Rigidbody existingRb = gameObject.GetComponent<Rigidbody>();
// 获取子对象中的组件
Rigidbody childRb = gameObject.GetComponentInChildren<Rigidbody>();
// 获取父对象中的组件
Rigidbody parentRb = gameObject.GetComponentInParent<Rigidbody>();
// 获取所有组件
Component[] allComponents = gameObject.GetComponents<Component>();
// 移除组件
Destroy(rb); // 销毁组件
Destroy(collider);
常用内置组件
| 组件类型 | 用途 | 典型场景 |
|---|---|---|
| Transform | 位置、旋转、缩放 | 所有对象 |
| MeshRenderer | 渲染 3D 模型 | 可见物体 |
| SpriteRenderer | 渲染 2D 精灵 | 2D 游戏 |
| Rigidbody | 物理模拟 | 需要物理效果的对象 |
| Collider | 碰撞检测 | 所有可碰撞对象 |
| Camera | 渲染场景 | 主摄像机 |
| Light | 照明 | 光源 |
| AudioSource | 播放音频 | 音效来源 |
| Animator | 播放动画 | 角色动画 |
| ParticleSystem | 粒子特效 | 特效对象 |
对象激活状态
GameObject 可以被激活或禁用,禁用的对象不会渲染、不执行脚本、不参与物理。
通过编辑器控制
Inspector 窗口顶部的复选框控制对象激活状态:
☑ MyGameObject ← 勾选为激活,取消为禁用
通过代码控制
// 检查激活状态
bool isActive = gameObject.activeSelf; // 自身激活状态
bool isActiveInHierarchy = gameObject.activeInHierarchy; // 在层级中是否有效
// 设置激活状态
gameObject.SetActive(true); // 激活
gameObject.SetActive(false); // 禁用
// 激活子对象(不影响父对象)
transform.GetChild(0).gameObject.SetActive(true);
注意区别
activeSelf:对象自身的激活设置activeInHierarchy:考虑父对象后的实际激活状态
如果父对象被禁用,子对象的 activeInHierarchy 会是 false,即使 activeSelf 是 true。
对象标签和层
标签(Tag)
标签用于标识和分类 GameObject,便于查找和区分。
Unity 内置标签:
Untagged:默认无标签Respawn:重生点Finish:终点EditorOnly:仅在编辑器中显示MainCamera:主摄像机Player:玩家GameController:游戏控制器
自定义标签:
- 选中对象,Inspector 中点击 Tag 下拉菜单
- 选择 Add Tag...
- 在 Tags & Layers 窗口添加新标签
代码中使用标签:
// 设置标签
gameObject.tag = "Enemy";
// 比较标签(推荐方式)
if (gameObject.CompareTag("Player"))
{
// 这是玩家对象
}
// 不推荐:字符串比较
// if (gameObject.tag == "Player") { }
// 通过标签查找对象
GameObject player = GameObject.FindWithTag("Player");
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
层(Layer)
层用于控制渲染、物理碰撞、射线检测等行为。
内置层:
Default(0):默认层TransparentFX(1):透明特效Ignore Raycast(2):忽略射线检测Water(4):水UI(5):用户界面
常用自定义层:
Player:玩家层Enemy:敌人层Ground:地面层Obstacle:障碍物层Item:物品层
代码中使用层:
// 设置层(使用层索引)
gameObject.layer = 8; // 第8层
// 设置层(使用层名称)
gameObject.layer = LayerMask.NameToLayer("Enemy");
// 获取层名称
string layerName = LayerMask.LayerToName(gameObject.layer);
// 层遮罩(用于射线检测等)
LayerMask enemyMask = LayerMask.GetMask("Enemy");
LayerMask groundMask = LayerMask.GetMask("Ground", "Obstacle");
对象查找方法
查找单个对象
// 通过名称查找(全局搜索,效率低)
GameObject obj = GameObject.Find("Player");
// 通过标签查找(推荐)
GameObject player = GameObject.FindWithTag("Player");
GameObject player = GameObject.FindGameObjectWithTag("Player");
// 通过类型查找(查找带有特定组件的对象)
PlayerController pc = FindObjectOfType<PlayerController>();
Camera mainCam = FindObjectOfType<Camera>();
查找多个对象
// 查找所有带特定标签的对象
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
// 查找所有带特定组件的对象
PlayerController[] players = FindObjectsOfType<PlayerController>();
// 现代推荐方式(避免 GC)
List<PlayerController> players = new List<PlayerController>();
FindObjectsOfType(players);
Transform 层级查找
// 获取父对象
Transform parent = transform.parent;
// 获取根对象
Transform root = transform.root;
// 获取子对象
Transform child = transform.GetChild(0); // 获取第1个子对象
int childCount = transform.childCount; // 子对象数量
// 通过名称查找子对象
Transform foundChild = transform.Find("ChildName");
Transform deepChild = transform.Find("Parent/Child/GrandChild"); // 支持路径
// 遍历所有子对象
foreach (Transform child in transform)
{
Debug.Log(child.name);
}
性能警告
GameObject.Find和FindObjectOfType开销较大,避免在Update中调用- 建议在
Start或Awake中缓存查找结果 - 对于频繁访问的对象,使用 public 字段或 SerializeField 在 Inspector 中引用
对象销毁
// 销毁对象(延迟到本帧结束)
Destroy(gameObject);
// 延迟销毁(2秒后)
Destroy(gameObject, 2f);
// 立即销毁(谨慎使用,可能引发问题)
DestroyImmediate(gameObject);
// 销毁组件
Destroy(GetComponent<Rigidbody>());
// 销毁子对象
Destroy(transform.GetChild(0).gameObject);
父子关系管理
设置父对象
// 方法1:直接设置 parent(已过时,不推荐使用)
// transform.parent = parentTransform;
// 方法2:使用 SetParent(推荐)
transform.SetParent(parentTransform);
// 保持世界坐标不变
transform.SetParent(parentTransform, true);
// 保持本地坐标不变
transform.SetParent(parentTransform, false);
// 解除父子关系
transform.SetParent(null);
父子关系的作用
// 父对象移动,子对象跟随
parent.position = new Vector3(10, 0, 0);
// child.position 也会相应变化
// 子对象的 Transform 是相对于父对象的
child.localPosition = Vector3.zero; // 子对象位于父对象中心
// 应用场景:角色装备系统
// 武器作为手的子对象,跟随手部移动
weapon.transform.SetParent(handTransform);
实践示例
示例1:创建简单的敌人
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
public Material enemyMaterial;
void Start()
{
CreateEnemy("Enemy1", new Vector3(0, 1, 0), Color.red);
CreateEnemy("Enemy2", new Vector3(5, 1, 0), Color.blue);
CreateEnemy("Enemy3", new Vector3(-5, 1, 0), Color.green);
}
GameObject CreateEnemy(string name, Vector3 position, Color color)
{
// 创建立方体
GameObject enemy = GameObject.CreatePrimitive(PrimitiveType.Cube);
enemy.name = name;
enemy.tag = "Enemy";
enemy.layer = LayerMask.NameToLayer("Enemy");
// 设置位置
enemy.transform.position = position;
// 设置材质颜色
Renderer renderer = enemy.GetComponent<Renderer>();
renderer.material = new Material(enemyMaterial);
renderer.material.color = color;
// 添加刚体
Rigidbody rb = enemy.AddComponent<Rigidbody>();
rb.mass = 2f;
// 添加自定义脚本
enemy.AddComponent<EnemyController>();
return enemy;
}
}
示例2:对象池管理
using UnityEngine;
using System.Collections.Generic;
public class ObjectPool : MonoBehaviour
{
public GameObject prefab;
public int poolSize = 20;
private Queue<GameObject> pool = new Queue<GameObject>();
void Start()
{
// 预创建对象
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
pool.Enqueue(obj);
}
}
public GameObject GetFromPool()
{
if (pool.Count > 0)
{
GameObject obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
// 池耗尽时创建新对象
return Instantiate(prefab);
}
public void ReturnToPool(GameObject obj)
{
obj.SetActive(false);
pool.Enqueue(obj);
}
}
最佳实践
- 使用预制体(Prefab):对于重复使用的对象,创建预制体而非代码生成
- 缓存组件引用:在
Awake或Start中缓存常用组件 - 避免频繁查找:不要在
Update中使用Find方法 - 合理使用层级:通过父子关系组织场景,保持 Hierarchy 整洁
- 命名规范:使用有意义的名称,便于识别和管理
下一步
理解 GameObject 后,你可以:
- 深入学习 Transform 变换 控制对象位置和旋转
- 编写 C# 脚本 添加交互逻辑
- 了解 物理系统 实现碰撞和物理效果