游戏对象的活动状态

Unity 4.0 改变了游戏对象活动状态的处理方式。游戏对象的活动状态现在由子游戏对象继承,因此,任何不活动的游戏对象也会使其子对象不活动。我们认为新行为比旧行为 来得更有意义,应该始终如此。此外,即将发布的新 GUI 系统严重依赖新 4.0 行为,没有的话不太可能实现。不幸的是,这就要求做一些工作来修复现有工程,从而让它与新的 Unity 4.0 行为共同作用,以下列出了更改内容:

旧行为:

  • 无论游戏对象是否活动,都以其 .active 属性进行定义。
  • 可对其进行查询并勾选 .active 属性进行设置。
  • 游戏对象的活动状态对子游戏对象的活动状态无影响。如果想激活或停用游戏对象及其所有子对象,须调用 GameObject.SetActiveRecursively。
  • 对游戏对象调用 SetActiveRecursively 时,任何子游戏对象的先前活动状态将会丢失。使用 SetActiveRecursively 停用然后激活游戏对象及其所有子对象时,调用 SetActiveRecursively 前任何不活动的子游戏对象会变为活动状态,如果想恢复到原有状态,须手动记录子游戏对象的活动状态。
  • 预设不包含任何活动状态,实例化后会始终保持活动状态。

新行为:

  • 游戏对象活动与否由自身及其所有父游戏对象的 .activeSelf 属性定义。如果游戏对象自身及其所有父对象的 .activeSelf 属性设为 true,即为活动状态。如果其一设为 false,则为不活动状态。
  • 可使用 .activeInHierarchy 属性进行查询。
  • 游戏对象的 .activeSelf 状态可通过调用 GameObject.SetActive 进行更改。对先前活动的游戏对象调用 SetActive (false) 可停用该游戏对象及其所有子对象。如果所有父对象为活动状态,对先前不活动的游戏对象调用 SetActive (true) 可激活该游戏对象。所有父对象为活动状态(如所有父对象的 .activeSelf 设为 true)时,其子对象将激活。
  • 这意味着不再需要 SetActiveRecursively,而是从父对象那里继承活动状态。还意味着调用 SetActive 停用和激活部分层级视图时,任何子游戏对象的先前活动状态将保留。* 预设可包含活动状态,并保留在预设实例化中。

示例:

有 A、B、C 三个游戏对象,那么 B 和 C 都是 A 的子对象。

  • 调用 C.SetActive(false) 停用 C。
  • 现在,A.activeInHierarchy == true,B.activeInHierarchy == true 且 C.activeInHierarchy == false。
  • 同样,A.activeSelf == true,B.activeSelf == true 且 C.activeSelf == false。
  • 现在我们调用 A.SetActive(false) 来停用父对象 A。
  • 现在,A.activeInHierarchy == false,B.activeInHierarchy == false 且 C.activeInHierarchy == false。
  • 同样,A.activeSelf == false,B.activeSelf == true 且 C.activeSelf == false。
  • 现在我们调用 A.SetActive(true) 再次激活父对象 A。
  • 现在,回到 A.activeInHierarchy == true,B.activeInHierarchy == true 且 C.activeInHierarchy == false。
  • 同样,A.activeSelf == true,B.activeSelf == true 且 C.activeSelf == false。

编辑器的新活动状态

要将这些更改可视化,在 Unity 4.0 编辑器中任何不活动的游戏对象(因自身或父对象的 .activeSelf 属性设置为 false)将在层级视图中显示为灰色,在检视器中的图标也为灰色。游戏对象自身的 .activeSelf 属性通过其活动复选框体现,可进行切换,与父对象的状态无关(但如果所有父对象都是活动状态,就会激活该游戏对象)。

对现有工程的影响:

  • 为了让用户了解代码中可能会受到影响的地方,GameObject.active 属性和 GameObject.SetActiveRecursively() 函数已被弃用。
  • 但是它们依然起作用。GameObject.active 值的读取与 GameObject.activeInHierarchy 的读取相同,设置 GameObject.active 与调用 GameObject.SetActive() 相同。调用 GameObject.SetActiveRecursively() 与对游戏对象及其所有子对象调用 GameObject.SetActive() 相同。
  • 3.5 版本中的现有场景通过将场景中任何游戏对象的 selfActive 属性设置为先前的 active 属性进行导入。
  • 因此,只要不依赖拥有不活动游戏对象的活动子对象(在 Unity 4.0 中不再可行),从 Unity 旧版本中导入的任何工程应能如期工作(虽然会出现编译器警告)。
  • 如果工程依赖于拥有不活动游戏对象的活动子对象,就必须更改 Unity 4.0 中可用的模型逻辑。

改为资源处理管道

开发 4.0 版本时,我们的资源导入管道在内部做了一些重要更改,以提高性能、内存使用率和确定性。在大多数情况下,这些更改对用户并无影响,但一种情况除外:资源中的对象不持续到导入管道的最终端,任何先前导入的资源版本将被完全替代。

第一部分的意思是,在后置处理过程中用户无法获得资源中对象的正确引用,第二部分的意思是如果使用先前导入版本的资源引用,后置处理过程中如果进行存储修改,那么这些修改会丢失。

因为不持续而丢失的引用示例

思考下面这个小示例:

[JavaScript]
?
1
2
3
4
5
6
7
public class ModelPostprocessor : AssetPostprocessor
{
    public void OnPostprocessModel(GameObject go)
    {
        PrefabUtility.CreatePrefab(\"Prefabs/\" + go.name, go);
    }
}

这在 Unity 3.5 中是可以的,但在 Unity 4.0 中,已导入的模型会被完全替代,因而更改先前导入的网格的名称将没有影响。这里给出的解决方案是通过其他方式找到网格并更改其名称。最重要的是,在 Unity 4.0 中应只更改对后置处理程序的给定输入,不依赖先前导入的相同资源版本。

网格读取/写入 (Read/Write) 选项

Unity 4.0 在网格 (Mesh) 导入设置中增添了“读取/写入已启用 (Read/Write Enabled)” 选项。关闭该选项能节省内存,因为 Unity 可在游戏中卸载网格数据的副本。

可是,如果在运行时以非统一缩放对网格进行缩放或实例化,则必须在其导入设置中启用“读取/写入已启用 (Read/Write Enabled)”。这是因为非统一缩放要求将网格数据保存在内存中。一般来说构建时会检测到这点,但运行时如果网格被缩放或实例化,就必须手动设置该选 项。否则将不会在游戏构建中正确呈现。

网格优化

Unity 4.0 中的模型导入器 (Model Importer) 在网格优化方面做得越来越好。Unity 4.0 中模型导入器 (Model Importer) 内的“网格优化 (Mesh Optimization)”复选框现已默认启用,将在网格 (Mesh) 中对顶点重新排序,以获得最佳性能。工程中可能有一些后置处理代码或效果依赖网格的顶点顺序,更改之后可能会破坏这些代码和效果。如果出现这种情况,请关 闭网格 (Mesh) 导入器中的“网格优化 (Mesh Optimization)” 选项。特别是使用 SkinnedCloth 组件时,网格优化会导致顶点权重贴图变化。因而,如果在从 3.5 版本中导入的工程中使用 SkinnedCloth,就需要关闭“网格优化 (Mesh Optimization)” 来影响网格或重新配置顶点权重,来匹配新的顶点顺序。

移动输入

对于 Unity 4.0 移动传感器,在平台之间输入,对齐更佳,也就是说只需写入较少代码就可以在移动平台上处理典型输入。现在,加速和陀螺输入将按照屏幕方向进行,iOS 和安卓 (Android) 平台的方法都相同。为了利用该更改,应在处理加速和陀螺输入时重构输入代码并移除平台和屏幕方向特定代码。在 iOS 中,将 Input.compensateSensors 设置为 false 仍可获得旧行为。