【译】在UNITY 5.0中移除AddComponet(string)方法
发表于2016-03-06
原文地址:http://blogs.unity3d.com/2015/01/21/addcomponentstring-api-removal-in-unity-5-0/
原文作者未做版权声明,视为共享知识产权进入公共领域,自动获得授权
为了进一步提升Unity的性能,Unity开发组删除 GameObject::AddComponent(string) 和 GetComponent(string),在得到社区的反馈后,开发组重新评估并将 GetComponent(string)放回来。
但是不能对AddComponent(string)进行还原,(它会引入已经打算消除掉的依赖关系,像是从核心到附属系统),如果您的项目有使用这个方法,您有两个替代方案(取决于哪种类型符合编译命令的规则要求,以及如何确定类型名称)。下面会详细描述这两种选项(相关例子用C#语言编写,但是其概念也可用于UnityScript (js) 和 Boo)。
状况1:类型名称以常量/字符串编码进行传递,在构建过程中已经知晓该类型
这种状况非常直接而且易于辨认,AddComponent()用一个恒定的字符串访问,您能够定义被添加类型的局部变量(或是参数,字段)。这样您可以简单地使用通用的AddComponent()版本,如下面例子显示的情况:
当导入Unity 5.0版本时应该被转化为:
// C1 / C2 declared as before.
class MyObj : MonoBehaviour
{
public void Start()
{
AddComponent< N1.C1>();
AddComponent< C2>();
}
}
要注意的是在命名空间(C1)内宣告类之前必需先定义命名空间(第八行)。这与过去用一列字符表示的API版本不同,它仅仅显示类名称。
状况2:参数/字段/本地变量被作为參數传到AddComponent.
这个情况能简单地通过检查AddComponent()的调用来确定(它会用一个字段/本地变量/参数作为参数),不巧的是,针对这个情况的替代方法仅能在运行时调用Type.GetType(string)对特定类型进行参考检索,以及对 AddComponent(type) 的调用。这种方式会有如下缺点:
1、状况涉及AOT/stripping
对于平台产生的限制也会类似地发生在这里。例如,如果在编码中没有对于特定类型引用,可能会使AOT编译器不能以二进制的形式将某个类型并入(例如,只有类型名称)。也需要注意在IL2CPP后端中,stripping是默认开启的。
2、需要对类型进行全限定名配置
这不算个严重的问题,然而,配置限定名会产生极大的工作量,并容易产生语法错误.
3需要一个实际的.Net类型存在
一些Unity组件仅仅支持原生代码(非.Net接口,比如EllipsoidParticleEmitter)我们对相关组件(来自于UnityEngine的)添加了.Net的表示方法,但我们可能总是会忽视一种或多种类型。
4、性能开销会存在于类型查找或/和其他工作中
通常来说,除非Type.GetType(string)在一个紧凑的循环内被调用,否则这点不会成为问题,但是您仍需要注意。
自动API更新
因为想让项目的更新尽可能的简单,所以对API 更新器进行了设置。当发现对AddComponent(string)调用时,如果成功地进行了类型解析(不包括状况2解释的情况,即类型名称只有在运行期间才会知道),更新器会对参数的值进行分析。简单地将状况1中的处理方法运用到替换AddComponent(string)的调用上,即将调用变为:
AddComponent< T>() // for C#
AddComponent.< T>() // for UnityScript (js)
(“T”是被添加的组件类型)
当计划处理更新器无法通过的参数时(状况2和状况1的一些附属情况,比如类在命名空间中被宣告),我们试着去平衡实用性,可靠性和易用性。经过我们首轮的评估之后,得出了一下的选项:
1、千万不要去碰脚本(不好)
2、简单地将所有对AddComponent(string)的调用替换为它的通用类型(或是将System.Type当做它的参数时),假设/希望它能奏效;
3、将调用替换为更加复杂,效能较低的代码,去试着转化运行过程中多重配置的类型。
选项1很快就被否定,而选项2看起来对用户较不友善,对我们来说也不够可靠专业,所以我们只留下了选项3,虽然,那也不是一个很好的解决方式。最后我们只能考虑一个好的折衷办法:在这个条目下AddComponent(string)的调用(该类型不能在编译时被转化,因为它使用非恒定/非字面的形式通过的)被替换为:APIUpdaterRuntimeServices::AddComponent(…),并按照说明在编辑器中执行。选项3为开发者说明了如何替换所有的调用。因此,您会看到一个这样的记录截图:
当游戏开始进行时的记录
(注意在日志中的列/栏可能会因为其他更新正在实施而有轻微的中断;而且这个说明基于C#的语法,如果您的脚本在UnityScript/Boo下生成,需要进行相应的改变)
在上述的例子中,即使更新器无法解析类型,在运行时,比如使用Unity编辑模式按Play的时候,APIUpdaterRuntimeServices::AddComponent()发现组件可以被转化,并且可以用GameObject::AddComponent()替换调用。
因为平台限制(这个方法(method)使用的方法或类型没有获得全平台支持)和对于玩家的性能影响,这个方法是面临淘汰的方法,如果您试着用它开发游戏会遇到错误,这意味着您需要提前为开发做好代码。
Unity的开发组明白这不是一个完美的解决方式,但相信这是一个解决依赖关系的必要步骤,认为Unity5.0做出这个改变是绝佳时机。
如果您对此有任何反馈意见,请反馈进入社区。