Unity3D技术之Unity 3.5 至 4.0 升级指南

2015年03月25日 14:40 0 点赞 0 评论 更新于 2025-11-21 18:32

游戏对象的活动状态

Unity 4.0 改变了游戏对象活动状态的处理方式。游戏对象的活动状态现在由子游戏对象继承,即任何不活动的游戏对象会使其子对象也变为不活动状态。我们认为这种新行为比旧行为更具逻辑性,并且即将发布的新 GUI 系统严重依赖此 4.0 新行为,没有该行为则难以实现。不过,这就需要对现有工程进行一些调整,以使其与 Unity 4.0 的新行为兼容。以下是具体的更改内容:

旧行为

  1. 活动状态定义:无论游戏对象是否活动,都由其 .active 属性进行定义。
  2. 查询与设置:可对 .active 属性进行查询和勾选设置。
  3. 对子对象的影响:游戏对象的活动状态对子游戏对象的活动状态无影响。若要激活或停用游戏对象及其所有子对象,须调用 GameObject.SetActiveRecursively
  4. 状态丢失问题:对游戏对象调用 SetActiveRecursively 时,任何子游戏对象的先前活动状态将会丢失。使用 SetActiveRecursively 停用然后激活游戏对象及其所有子对象时,调用 SetActiveRecursively 前任何不活动的子游戏对象会变为活动状态,若想恢复到原有状态,须手动记录子游戏对象的活动状态。
  5. 预设情况:预设不包含任何活动状态,实例化后会始终保持活动状态。

新行为

  1. 活动状态定义:游戏对象活动与否由自身及其所有父游戏对象的 .activeSelf 属性定义。只有当游戏对象自身及其所有父对象的 .activeSelf 属性都设为 true 时,该游戏对象才处于活动状态;若其中有一个设为 false,则为不活动状态。
  2. 查询方式:可使用 .activeInHierarchy 属性进行查询。
  3. 状态更改:游戏对象的 .activeSelf 状态可通过调用 GameObject.SetActive 进行更改。对先前活动的游戏对象调用 SetActive (false) 可停用该游戏对象及其所有子对象;当所有父对象为活动状态(即所有父对象的 .activeSelf 设为 true)时,对先前不活动的游戏对象调用 SetActive (true) 可激活该游戏对象,并且其子对象也将激活。
  4. 优势:这意味着不再需要 SetActiveRecursively,活动状态会从父对象继承。调用 SetActive 停用和激活部分层级视图时,任何子游戏对象的先前活动状态将保留。预设可包含活动状态,并在预设实例化时保留该状态。

示例

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

  1. 调用 C.SetActive(false) 停用 C。此时,A.activeInHierarchy == trueB.activeInHierarchy == trueC.activeInHierarchy == false;同样,A.activeSelf == trueB.activeSelf == trueC.activeSelf == false
  2. 调用 A.SetActive(false) 停用父对象 A。此时,A.activeInHierarchy == falseB.activeInHierarchy == falseC.activeInHierarchy == falseA.activeSelf == falseB.activeSelf == trueC.activeSelf == false
  3. 调用 A.SetActive(true) 再次激活父对象 A。此时,A.activeInHierarchy == trueB.activeInHierarchy == trueC.activeInHierarchy == falseA.activeSelf == trueB.activeSelf == trueC.activeSelf == false

编辑器的新活动状态

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

对现有工程的影响

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

改为资源处理管道

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

这包含两方面的影响:一是在后置处理过程中用户无法获得资源中对象的正确引用;二是如果使用先前导入版本的资源引用,后置处理过程中如果进行存储修改,那么这些修改会丢失。

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

以下是一个小示例:

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 仍可获得旧行为。

作者信息

feifeila

feifeila

共发布了 3994 篇文章