Unity 的背景
Unity引擎是一个跨平台的游戏引擎,最早发布于Apple的WWDC2005。开发的主要语言是C#,这归功于Mono,一个.Net Framework的非官方实现(Xamarin公司开发并使用这个框架实现了用C#来开发跨平台的应用,后来被微软收购。)。有了Mono,就解决了C#跨平台的问题。(为什么选择C#而不选择Java,可能是条款的问题,也可能是当时的环境。)一个游戏引擎,为了实现跨平台,不仅仅是一个编程语言统一了就足矣。如果说计算机的计算速度快的不行,或者人们对游戏的需求只是局限于玩玩2D游戏,那么的确可以这样,在Flash游戏(Action Script 3.0)最火的时候,就是这样的情况。但是现实的情况是,计算机的实际处理速度不够快,台式机的性能虽然很好了,现在移动设备更受欢迎。同时,3D游戏似乎更炫酷,更能让人沉浸其中。对于不需要事先跨平台的游戏引擎来说,解决问题的方案还简单一点,CPU先天是并发效率比较弱,所以就用GPU来做辅助的图形计算。GPU在上世纪九十年代还是不可编程只能配置,所以现在还是习惯称之为硬件加速器。随着时代发展,GPU也能够编程了,但是还是有很多限制,还没办法像CPU上的语言那样,发展出Java/C#等与硬件无关的解决方案。现在的GPU编程语言还是比较贴近硬件的,虽然有了一些高级的语言Cg、GLSL、HLSL(统称之为Shader语言,编译出来的程序称之为Shader Program,简称Shader,Shader受限于Shader Model,在渲染流水线上,相应的位置有相应的Shader),但这些高级语言还是比较贴近硬件,类似于C/C++,在不同的GPU硬件上都需要(重新)编译一次。Shader语言编译的工作不需要游戏引擎实现,而是由GPU的生产商来实现。而生产商又会遵循主流的标准,例如做一个HLSL的版本给DirectX,做一个GLSL的版本给OpenGL等等。像主机的开发商任天堂、Sony,有他们自己的硬件,他们自研的引擎一般不需要考虑跨平台了。Unity要开发一个跨平台的游戏引擎,当然就需要考虑怎么解决Shader的跨平台了(CPU端的问题,mono已经替他们解决了)。目前的情况,没有一种GPU的API是真正的跨平台。像DirectX,毫无疑问,只能在Windows上用,Windows虽然在PC端有占大多数的份额,但在移动端的市场几乎为0,而现在移动端的用量比PC还要多。OpenGL在PC上能用,在Mac上也能用。在移动端占主流的那个,虽然叫OpenGL ES,并且Shader语言也是GLSL,但是同样名字的语言,其实也是有很多版本的。现在真正实现跨平台最多的,可能就是OpenGL ES了,PC上的WebGL就是OpenGL ES。如果用OpenGL ES,Unity会比较被动的,因为ES不能发挥出硬件的所有性能。Unity的解决方案是Shader Lab,这个语言是类似HLSL,或者Cg的。Shader Lab的实现方案是,将这个语言编译到目标平台能够使用的语言,例如某个版本的GLSL。虽然Unity号称是跨平台的,但是并没有达到运行时跨平台,而只能做到编译时的跨平台。如何实现运行时跨平台?就是开发出一个Unity Player,系统平台装了这个Player后,就能运行开发者开发出来的游戏文件。曾经Flash完成了一半这项工作,但后来移动端的兴起,GPU在游戏中的重要性与日俱增,又毁掉了Flash的前程。现在最接近这个任务的是Unity了。得益于移动端的发展,但Unity的今天,已经不再是他的跨平台的feature了,而是一套成熟的工具链,这个工具链还实现了一个生态,Asset Store。
Hello Unity
Unity游戏的开发,依赖于Unity开发工具。很多游戏引擎,只是作为一个库的存在,基于这些引擎的开发,更像是一项编程的工作——打开一个text editor,便可开始敲代码,一运行,就能看到自己的编程成果。游戏的开发,有不少的工作量是界面上的布局,这样的工作,非常需要有一个GUI编辑器来实现。Unity实现了这样的功能,称之为Scene。Scene本身其实也是游戏引擎的一个运行的结果,当然,在PC上,Scene是基于PC的,而PC开发的游戏,不一定发布到PC平台,因此效果并不能划等号。Scene支持镜头的拖动,或者选择toolbar上的其他选择,可以实现对Scene中的对象进行编辑。Scene中的对象是什么?是可渲染的对象。搭配着Scene一起使用的还有Hierarchy,Hierarchy列表是由GameObject对象组成的,Scene的渲染是基于Hierarchy中的GameObject,但是GameObject不一定是可渲染对象,GameObject本身可以认为是一个容器,可以添加各种Component,而Scene中可见的对象来自带有Renderer Component的Game Object对象。虽然有点绕,但是这里强调一点,Scene中的对象并不能与Game Object划等号,它只是Game Object的一部分,它是一个具有Renderer + Mesh Filter的GameObject的呈现。那些不具备这些特性的Game Object,不会在Scene中出现,但是是Hierarchy的一部分。Scene和Game(窗口)的区别,是Game的Camera在Hierarchy中配置,而Scene的Camera是不在Hierarchy中的,Scene本身也可以认为是一个具有交互性质的已发布的Game,其Camera就是编辑器的渲染视角。
那种在text editor上编辑并启动的游戏,可以认为是code driven的,需要用户自己创建一个scene,然后要么代码式的生成出场景效果。而Unity则是scene driven的,不需要用户在代码中创建scene,而是由引擎的runtime自动创建scene。用户可以在Build Setting界面,将添加需要的scene,而列表中第一个scene便是Unity runtime在启动时会去加载的scene。这个scene可以认为是Scene对象的一个序列化文件。用户在Scene上编辑的后,按保存,就可以认为是序列化的过程。启动时加载scene,则是反序列化的过程。
作为程序员,Unity最简单的Hello World,不是创建一个Text对象,而是创建一个空的Game Object,给这个Game Object添加一个Component,这个Component是一个可编程的组件,而不是可编辑的组件(其他的Component),这个Component可命名为HelloWorld(.cs),然后在代码编辑器中,删除掉Class中两个Override方法,而是Override Awake方法。在方法中写上“Debug.Log("Hello World");”。这便是最简单的Hello Unity了。