How to Develop a Game
Object
PublishDate: 2025-06-01 | CreateDate: 2025-06-01 | LastModify: 2025-06-01 | Creator:ljf12825

Object是Unity中所有内建物体的基类,实现在UnityEngine.CoreModule中,不同于C#中的System.Object,它是托管层(C#)和原生引擎层(C++)之间的桥梁,背后绑定着Unity C++引擎层的资源句柄

Object的特点(Unity的特有行为)

引擎资源的绑定

每个UnityEngine.Object对象都对应一个C++层对象,它们通过一个instance 2D来关联,且资源的生命周期不由GC管理

比如:

GameObject go = new GameObject();
Object.Destroy(go);
Debug.Log(go == null);  // true

这就是Object的“鬼行为”,此处的go == null并非等价于object is null

Unity的“fake null”机制 fake null是Unity中一个特有的概念,通常用来描述已经销毁的对象或者已经不再有效的对象的引用。尽管对象被销毁了,但它仍然存在一个“假”引用,这个引用就像是一个假的null,它指向的对象实际上已经不再有效,但在代码层面看起来却任然是一个对象。具体来说,fake null让你能够获得一个对象引用,但该对象的属性和方法无法被正常访问,或者会返回默认值,或者不会产生期望的结果

Unity重写了==操作符

如果一个Object对象在引擎层已经被销毁(Destroy过),但C#还保有托管引用,这时候:

Debug.Log(go == null); // true
Debug.Log(go.Equals(null)); // false
Debug.Log(ReferenceEquals(go, null)); // false

为什么需要fake null

  1. 避免NullReferenceException 在传统的编程中,如果一个对象被销毁或设为null,而你还试图访问它的属性或方法,就会引发NullReferenceException错误。在Unity中,许多对象的销毁并不立即释放内存,尤其是当销毁了一个游戏对象或组件时。为了避免频繁的null检查和避免程序崩溃,Unity引入了fake null

  2. 内存管理的优化 Unity并不是立即销毁对象,而是将其“标记”为无效,保持它的引用存在,但无法访问。这使得Unity可以更高效地管理内存。内存的实际释放通常依赖于垃圾回收器,而不是对象销毁后立即释放内存,从而避免频繁的内存分配和释放造成的性能瓶颈

fake null行为总结

  1. 引用存在,但对象无效
  2. 不抛出异常
  3. 确保内存管理不会立即释放内存

底层原理

Unity的Object在C#层其实只是一个代理,它对应的C++引擎层对象通过C#层的IntPtr m_CachedPtr与C++对象通信(该字段可以在反编译时看到)

资源对象(比如一个贴图)在编译器导入时会被转换为native object,保存在场景或资源文件中,加载时通过Unity自己的反序列化系统生成C#代理对象,并挂接m_CachedPtr

Unity会使用C++引擎进行资源生命周期的管理,而不是C#的GC,所以Destroy调的是C++的释放接口

Sometimes an instance of Object can be in detached state, where there is no underlying native object. T
his can happen if the instance references an native object that has been destroyed, or a missing Asset or missing type. 
Detached objects retain their InstanceID, but the object cannot be used to call methods or access properties. 
An object in this state will appear to be null, because of special implementations of operator==, operator!= and Ojbect.bool.
Because the object is not truly null, a call to Object.ReferenceEquals(myobject, null) will return false.

The null-comditional operator(?.)and the null-coalescing operator(??)are not supported with Unity Object because they cannot be overridden to treat detached objects the same as null.
It is only safe to use those operators in your scripts if there is certainty that the objects being checked are never in a detached state.

Object API

Properties

属性类型描述
namestring对象名称(可读写)
hideFlagsHideFlags控制对象是否可隐藏/可编辑/保存

hideFlags
常见用途:

常用枚举值

枚举值含义
HideFlags.None默认行为,无隐藏
HideFlags.HideInHierarchy在 Hierarchy 视图中隐藏
HideFlags.HideInInspector在 Inspector 中隐藏
HideFlags.NotEditable不允许用户编辑(灰掉)
HideFlags.DontSave场景保存时不保存该对象
HideFlags.DontSaveInBuild打包时不保存该对象
HideFlags.DontSaveInEditor编辑器中不保存该对象
HideFlags.HideAndDontSave隐藏并不保存(临时对象)

Public Methods

MethodDescription
GetInstanceID获得object的实例ID
ToString返回object.name

Static Methods

方法描述示例/说明
Destroy(Object obj)销毁一个对象,在当前帧结束时生效Destroy(gameObject);
Destroy(Object obj, float t)延迟 t 秒销毁对象Destroy(gameObject, 2.0f);
DestroyImmediate(Object obj)立刻销毁对象,只推荐在编辑器中使用DestroyImmediate(gameObject);
DontDestroyOnLoad(Object target)场景切换时不销毁该对象常用于单例或管理器类
FindAnyObjectByType<T>()获取任何已加载的指定类型对象(不保证顺序)替代旧版 FindObjectOfType
FindFirstObjectByType<T>()获取第一个找到的指定类型对象(可能更快)常用于初始化查找
FindObjectsByType<T>()获取所有已加载的指定类型对象var allEnemies = FindObjectsByType<Enemy>();
Instantiate(Object original)克隆一个对象(创建副本)Instantiate(prefab);
Instantiate(Object original, Vector3 position, Quaternion rotation)在指定位置和旋转创建克隆Instantiate(prefab, pos, rot);
InstantiateAsync(Object original)异步克隆对象,返回 AsyncInstantiateOperation用于 Addressables 或大型对象,节省主线程开销

Operators

操作符描述
bool是否存在
operator!=比较两个object是否引用不同的物体
operator==是否引用相同

Object与资源的关系

几乎所有资源类型(包括预制体、贴图、材质、音频、动画等)都继承自Object

Texture tex = Resources.Load<Texture>("MyTexture");

Resources.Load<T>()返回的其实就是一个Object的子类(这里是Texture)

继承关系

Object
  ├── GameObject
  └── Component
        ├── MonoBehaviour
        └── Transform / Collider / Renderer / ...

所以可以有:

GameObject go = new GameObject();
Object obj = go; // legal
Component comp = go.GetComponent<Transform>();
Object o2 = comp; // legal

new出来的GameObject是合法的,但不能new TransformRenderer,必须用AddComponent等引擎API创建