纳金网

标题: 解构Unity的Script物件模型 [打印本页]

作者: 会飞的鱼    时间: 2011-12-7 15:15
标题: 解构Unity的Script物件模型


Unity 是一个以 Mono 为基础的游戏开发环境,能同时支持三种脚本语言,包括 C#、Javascript 和Boo (类似 Python)。
由于Unity 的开发工具暂时只有 Mac 的版本,所以暂时未能测试。但是它有很详细的文档,看上来很易用,所以就从文字上学习它的Script 使用方式。
跟据一些Tutorial 及参考手册,我用 Graphviz 画了一个 (我认为) 最核心的 UML 类别图:
从这个类别图我们可以理解它的结构,及如何把一些常用功能映射至这系统里,以下分节讨论。
GameObject 和 Component
Unity 的执行环境里,会有一个场境 (Scene)。这个场境包含一个 GameObject 物件的层阶
(Hierarchy)。这个 GameObject 类别只是一个包容器,本身没有其他功能。使用者需要为 GameObject 加入各种Component 物件来定义它的行为,而不是透过继承 (inherit) GameObject 来加入 行为。
一个物件可拥有多个Component 物件,但有一些Component 类别只可以在一个 GameObject 中有一个实体 (instance)。
MonoBehavior
我最感兴趣的,是使用者如何自行定义行为来做出不同的 Gameplay。在Unity 中,程式员编写的Script,其实也是Component 的一种,所有的Script 都会继承自 MonoBehavior 类别。以下是一个简单例子:
var speed = 5.0;
function Update () {
var x = Input.GetAxis("Horizontal") * Time.deltaTime * speed;
var z = Input.GetAxis("Vertical") * Time.deltaTime * speed;
transform.Translate(x, 0, z);
}
把这个Script 加进一个 GameObject 的话 (成为该 GameObject 的一个Component),Runtime 会在每帧呼叫 Update(),玩家就可以用上下左右键控制那个 GameObject 在水平方向移动。。
Transform
每个能在三维空间里的 GameObject 都会有 Transform Component (未有详细看是否有一些
GameObject 可以省郄 Transform,例如一个用来定义一个游戏任务的 GameObject)。Transform 包括位置、旋转及缩放。之前的例子已用了 transform component,不过它其实是 Object 类别的一个 shortcut,这 shortcut其实等同:
GetComponent(Transform).Translate(x, 0, z)
Component 的连结
在Script Tutorial 里的例子是写一个 Follow 的行为,拥有这个Component 的 GameObject 会自动追踪 (面对着) 一个目标物件:
var target : Transform;
function Update () {
transform.LookAt(target);
}
这个Script 暴露了一个 target 变数 (应当作成员变数吧),使用者可以把其他物件的变数 assign 至这个变数。这 assignment 有两种方法实现,其一是利用Unity 的 GUI 工具把一个Component 实体的变数 (如Transform) drag-and-drop 至这个Component 实体的 target 变数,而另一个方法是写代码:
var newTarget = GameObject.Find("Cube").transform;
GetComponent(Follow).target = newTarget;


用代码就可以这样动态改变这些Component 之间的联结方式。或者另一个说法是,GUI 工具是可以设定起始的联结,而Script 可以在执行期改变这些联结。
渲染
一个可被渲染的 GameObject 需要有以几个 Components,以 Mesh 为例:
1. MeshFilter: 用来找出现时的 Mesh 物件
2. MeshRenderer: 用来渲染 Mesh 的 Component,会参考一个 material 物件
要注要 Mesh 和 Material 物件并非 Component,它们是继承自 Object 的。但是你仍然可以去动态改变它们。但由于它们不是Component ,所以可以被分享,例如多个 GameObject 的 MeshRenderer都参考到同一个 Material。一个Component 实体只属于一个 GameObject (所以在 UML 中我用黑色钻石表示 Composition)。而 Light 和 Camera 则是 Component,这意未着可以简单的设定联结。
分析
Unity 的Script 物件模型是以Component 为基础的。透过把Component 实体加入 GameObject 实体来组合不同功能的物件,而Component 实体之间可以建立联结。这种方式不需要透过继承 (inheritance),而是透过聚合 (aggregation)加入物件的功能和行为。使用聚
合的好处是不会产生复杂的继承层阶,亦可以动态改变聚合的结构 (例如在执行期加入或移除Component)。
有一些细节我暂时未清楚,例如多个Component 在一个 GameObject 中的执行次序如何设定;联结会否有 cylic 的问题等等。可能要拿到软件再试用才可以知道。
结语
Unity 的脚本系统给我的感觉是使用非常简单。透过很少的代码就能写一些行为,甚至把行为组合到物件中。但是,通常容易的东西都会有相对的缺点,例如在效能上或是 Scalability 上。后者可能是一个很大的问题,当游戏规模扩大,Component 和联结就会变成一个很复杂的 graph,由于连结是发生于执行期(而非静态),可能要作改动会变得困难。换句话说,就是改几十个类别容易,改它们的几千个实体就会很困难。
软件设计世界里当然没有银子弹,每个方案都适合不同的情况。我认为Unity 的一个设计目标是容易使用,就是像 Virtools 之流,可以给没有程式底子的人做游戏,相对来说做比较复杂的项目可能会遇到许多问题。但参考一下总可以给予对事物新的观点,或分析另一个科案的强劲之处。我在周末就会再研究其他游戏工业上最强的引擎的脚本,例如 CryEngine2/Sandbox2 和 Unreal。


由 u8  发表
作者:Milo
作者: C.R.CAN    时间: 2012-1-19 22:59
每年短信都很卡,今年提前一点发,就算网络再怎么忙,保准我是第一个,祝福提前到:运气顺顺顺,一切旺旺旺,一年更比一年强!收到有福啦!

作者: 晃晃    时间: 2012-1-24 23:19
祝你新年很灿烂,牛气哄哄冲霄汉,祝你明年业务多,好运连连一火车,祝你工作小轻松,玩玩闹闹很成功,祝你身体特别好,吃嘛嘛香没烦恼。

作者: 菜刀吻电线    时间: 2012-1-31 23:20
空调冷却不了青春的火焰,彩电演绎不了年轻的色彩,MP3播放不了岁月的音色,电影远比不上生命的出色,短信却能寄托我真诚的祝福:春节快乐!

作者: 菜刀吻电线    时间: 2012-2-5 23:27
頂。。。

作者: 晃晃    时间: 2012-2-14 23:23
不错 非常经典  实用

作者: tc    时间: 2012-2-14 23:24
谢谢楼主,真是太实用了

作者: 晃晃    时间: 2012-2-22 23:27
人过留名!

作者: 菜刀吻电线    时间: 2012-4-5 23:23
好`我顶``顶顶

作者: 浩劫    时间: 2012-4-6 19:33

作者: 奇    时间: 2012-6-13 23:18
凡系斑竹滴话要听;凡系朋友滴帖要顶

作者: C.R.CAN    时间: 2012-10-31 23:30
已阵亡的 蝶 随 风 舞 说过  偶尔按一下 CTRL A 会发现 世界还有另一面

作者: 菜刀吻电线    时间: 2012-11-8 23:18
好可爱的字,学习了

作者: tc    时间: 2013-2-15 23:36
我是老实人,我来也!





欢迎光临 纳金网 (http://go.narkii.com/club/) Powered by Discuz! X2.5