Unity3D架构 – 令人头疼的“.”





5.00/5 (3投票s)
Unity 5 即将发布,带来了一大堆新特性,有些显而易见,有些则不那么明显。如果你还没有看过 Unity 5 公开展示的新特性,可以查看在 Unite 2014 上展示的功能预览。然而,有一些幕后变化…
“.” 到底意味着什么?
当你在 Unity3D 项目中使用组件和脚本,然后想在代码中访问它们时,很容易就开始编写
this.renderer.collider.attachedRigidbody.angularDrag = 0.2f;
(是的,这有点极端,但目的是为了说明问题。)
在这段简单的代码中,你实际上调用或访问了附加到你正在运行脚本的 GameObject
的 3 个单独的组件。
在后台,Unity3D 会将其转换为
var renderer = this.GetComponent<Renderer>();
var collider = renderer.GetComponent<Collider>();
var ridgedBody = collider.GetComponent<Rigidbody>();
ridgedBody.angularDrag = 0.2f;
现在看起来不那么简单了,不是吗?这个过程本质上是缓慢的,有时会涉及大量的反射(在内存中解构代码的过程,例如任何 Function(string)
方法都会这样做)。
将此乘以每一帧,你就可以开始理解为什么这是一个问题了。最初这只是编写更简单代码的一种方式,但随着它日益普及,Unity 已经表示“够了”,并正在进行破坏性更改。
据我所知,这种行为也会影响 JavaScript 和 Boo。
Unity3D 的最佳实践
使用 DOT 符号在代码中更改组件的行为确实有效,但就像很多事情一样,“仅仅因为你可以做某事并不意味着你应该这样做”,那么你可以做些什么来改进你的代码?
第一部分是理解你的代码并使其更好,这样你就会考虑
- 我真的需要在每一帧中都引用一个组件吗?
- 如果需要,则将该组件作为脚本中的引用来访问,而不是每次都调用
GetComponent
。 - 如果你愿意,仍然可以在每一帧中调用
GetComponent
(不建议),你现在可以控制它了。
因此,我会将上面的脚本转换为
Rigidbody myScriptBody;
void Awake()
{ var renderer = this.GetComponent<Renderer>();
var collider = renderer.GetComponent<Collider>();
myScriptBody = collider.GetComponent<Rigidbody>();
}
void Update()
{ myScriptBody.angularDrag = 0.2f * Time.deltaTime;
}
这样只在脚本第一次运行时使用 GetComponent
并存储运行时需要的引用(或引用),然后使用内存中的引用而不是尝试每一帧都发现它。
这些只是你使用和访问 Unity3D 系统中组件的简单更改。
最好的建议
你现在已经知道了新的知识,并做好了准备,使用这些知识来更改你当前的实践,如果你一直在代码中使用“.” 方法。
在观看每一个视频教程或从库或维基导入脚本时,请记住这一点,并提前进行调整。
如果你目前在你的代码中大量使用这种方法,并且认为这对于代码的模块化来说是一个很大的改变,那么请关注 Unity5,仍然有很多惊喜等待着你,包括一些帮助解决这种行为的问题。
未来是光明的,未来是 Unity5
Unity 5 即将发布,带来了一大堆新特性,有些显而易见,有些则不那么明显。
如果你还没有看过 Unity 5 公开展示的新特性,可以查看在 Unite 2014 上展示的功能预览。