Unity GameObject 与组件操作速查

这篇按“操作对象时想做什么”来查:找对象、拿组件、生成 Prefab、销毁、启用禁用、改父节点、换坐标。


快速索引

我想做什么 常用 API
拿自己身上的组件 GetComponent<T>()
安全判断组件是否存在 TryGetComponent<T>()
拿子节点组件 GetComponentInChildren<T>()
拿父节点组件 GetComponentInParent<T>()
查场景对象 FindObjectOfType<T>()GameObject.Find
按 Tag 查对象 GameObject.FindWithTag
生成 Prefab Instantiate
销毁对象 Destroy
禁用整个对象 gameObject.SetActive(false)
禁用脚本组件 enabled = false
禁用渲染 renderer.enabled = false
设置父节点 transform.SetParent
世界坐标转本地坐标 InverseTransformPoint
本地坐标转世界坐标 TransformPoint

0. GameObject 常用属性

1
2
3
4
5
6
7
8
9
10
gameObject.name                         // 对象名
gameObject.tag // Tag
gameObject.layer // Layer
gameObject.activeSelf // 自己是否被 SetActive(true)
gameObject.activeInHierarchy // 层级最终是否激活
transform.position // 世界坐标
transform.localPosition // 本地坐标
transform.rotation // 世界旋转
transform.localRotation // 本地旋转
transform.localScale // 本地缩放

1. 获取组件

1
2
3
4
5
6
private Rigidbody rb;

private void Awake()
{
rb = GetComponent<Rigidbody>(); // 获取自己身上的 Rigidbody
}

安全写法:

1
2
3
4
5
6
7
8
9
10
11
private void Awake()
{
if (!TryGetComponent(out Rigidbody rb)) // 没有组件时不抛异常
{
Debug.LogError("缺少 Rigidbody", this);
enabled = false;
return;
}

this.rb = rb;
}

查子节点或父节点:

1
2
Renderer childRenderer = GetComponentInChildren<Renderer>(); // 查自己和子节点
Canvas parentCanvas = GetComponentInParent<Canvas>(); // 查自己和父节点

包含未激活对象:

1
Renderer[] renderers = GetComponentsInChildren<Renderer>(true); // true 包含 inactive

2. Inspector 引用优先

1
2
[SerializeField] private Transform firePoint;    // 枪口位置直接拖引用
[SerializeField] private GameObject bulletPrefab; // 子弹 Prefab 直接拖引用

适合:

1
2
3
4
固定 UI 节点
固定 Prefab
固定出生点
固定音效源

好处:

1
2
3
不用运行时查找
引用关系一眼可见
性能稳定

3. 查找对象

低频可用:

1
2
3
Player player = FindObjectOfType<Player>();       // 场景里查 Player,低频使用
GameObject uiRoot = GameObject.Find("UIRoot"); // 按名字查,路径改名会失效
GameObject playerObj = GameObject.FindWithTag("Player"); // 按 Tag 查

少用:

1
2
3
4
private void Update()
{
GameObject player = GameObject.FindWithTag("Player"); // 每帧查找不推荐
}

替代写法:

1
[SerializeField] private Player player;           // 直接拖引用

或者用注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public sealed class PlayerRegistry : MonoBehaviour
{
public static Player Current { get; private set; }

private void Awake()
{
Current = GetComponent<Player>(); // 启动时注册
}

private void OnDestroy()
{
if (Current == GetComponent<Player>())
{
Current = null; // 销毁时清理
}
}
}

4. Instantiate 生成对象

1
GameObject bullet = Instantiate(bulletPrefab);     // 生成 Prefab

指定位置和旋转:

1
2
3
4
5
GameObject bullet = Instantiate(
bulletPrefab,
firePoint.position,
firePoint.rotation
); // 在枪口生成

指定父节点:

1
2
GameObject item = Instantiate(itemPrefab, contentRoot); // 作为 UI 列表子节点
item.transform.localScale = Vector3.one; // UI 常见重置

泛型写法:

1
2
Bullet bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
bullet.Init(damage, direction); // 生成后初始化

5. Destroy 销毁对象

1
2
3
Destroy(gameObject);                             // 销毁当前对象
Destroy(enemy.gameObject); // 销毁敌人对象
Destroy(effect, 2f); // 2 秒后销毁

注意:

1
2
3
4
Destroy 不是立刻从内存消失
当前帧后续代码仍可能继续执行
销毁后旧引用会变成 Unity 假 null
高频创建销毁用对象池

销毁后直接返回:

1
2
Destroy(gameObject);
return; // 避免后面继续访问自身

6. SetActive / enabled / renderer.enabled

禁用整个对象树:

1
gameObject.SetActive(false);                    // 当前对象和子对象都不再激活

只禁用脚本:

1
enabled = false;                                // 当前 MonoBehaviour 不再 Update

只隐藏渲染:

1
meshRenderer.enabled = false;                   // 不显示,但对象和逻辑仍在

只关闭碰撞:

1
collider.enabled = false;                       // 不再参与碰撞

区分:

1
2
activeSelf             # 自己是否被设置激活
activeInHierarchy # 父节点影响后的最终激活状态

7. Transform 坐标

1
2
3
4
transform.position = new Vector3(0, 1, 0);       // 世界坐标
transform.localPosition = Vector3.zero; // 相对父节点坐标
transform.rotation = Quaternion.identity; // 世界旋转
transform.localScale = Vector3.one; // 本地缩放

移动:

1
2
3
4
5
6
transform.Translate(Vector3.forward * speed * Time.deltaTime); // 按方向移动
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
); // 向目标靠近

朝向目标:

1
2
Vector3 dir = target.position - transform.position;
transform.rotation = Quaternion.LookRotation(dir); // 朝向目标

坐标转换:

1
2
Vector3 local = transform.InverseTransformPoint(worldPos); // 世界 -> 本地
Vector3 world = transform.TransformPoint(localPos); // 本地 -> 世界

8. 父子节点

1
2
3
4
5
transform.SetParent(parent);                    // 设置父节点,默认保持世界坐标
transform.SetParent(parent, false); // UI 常用:使用本地坐标
transform.SetAsFirstSibling(); // 放到同级第一个
transform.SetAsLastSibling(); // 放到同级最后一个
int index = transform.GetSiblingIndex(); // 当前同级索引

遍历子节点:

1
2
3
4
5
for (int i = 0; i < transform.childCount; i++)
{
Transform child = transform.GetChild(i); // 获取第 i 个子节点
child.gameObject.SetActive(false);
}

删除所有子节点:

1
2
3
4
for (int i = transform.childCount - 1; i >= 0; i--)
{
Destroy(transform.GetChild(i).gameObject); // 倒序删除子节点
}

9. Layer / Tag

1
2
3
4
if (other.CompareTag("Player"))                 // 比 other.tag == 更推荐
{
Debug.Log("碰到玩家");
}
1
2
int enemyLayer = LayerMask.NameToLayer("Enemy"); // Layer 名转编号
gameObject.layer = enemyLayer;
1
LayerMask mask = LayerMask.GetMask("Enemy", "Ground"); // 多个 Layer 组合

10. 常见坑速查

1
2
3
4
5
6
7
每帧 GetComponent / Find                 # 提前缓存或拖引用
GameObject.Find 依赖名字 # 改名后失效
Destroy 后继续访问对象 # 直接 return
SetParent 后 UI 坐标飞了 # UI 用 SetParent(parent, false)
Prefab 引用场景对象 # 实例化后容易丢引用
父节点 inactive,子节点 activeSelf true # 看 activeInHierarchy
用世界坐标改 UI # UI 优先查 RectTransform

系列导航