在日常的工作中,我偶尔能遇到这样的问题:“为何游戏脚本在现在的游戏开发中变得不可或缺?”。那么这周我就写篇文章从游戏脚本聊起,分析一下游戏脚本因何出现,而Mono又能提供怎样的脚本基础。最后会通过模拟Unity3D游戏引擎中的脚本功能,将Mono运行时嵌入到一个非托管(C/C++)程序中,实现脚本语言和“引擎”之间的分离。
Why?从为何需要游戏脚本说起首先聊聊为何现在的游戏开发需要使用游戏脚本这个话题。
为何需要有脚本系统呢?脚本系统又是因何而出现的呢?其实游戏脚本并非一个新的名词或者技术,早在暴雪的《魔兽世界》开始火爆的年代,人们便熟知了一个叫做Lua的脚本语言。而当时其实有很多网游都不约而同地使用了Lua作为脚本语言,比如网易的大话西游系列。但是在单机游戏流行的年代,我们却很少听说有什么单机游戏使用了脚本技术。这又是为什么呢?因为当时的硬件水平不高,所以需要使用C/C++这样的语言尽量压榨硬件的性能,同时,单机游戏的更新换代并不如网游那么迅速,所以开发时间、版本迭代速度并非其考虑的第一要素,因而可以使用C/C++这样开发效率不高的语言来开发游戏。
但是随着时间的推移,硬件水平逐年提升,压榨硬件性能的需求已经不再迫切。相反,此时网游的兴起却对开发速度、版本更迭提出了更高的要求。所以开发效率并不高效,且投资、巨大风险很高的C/C++便不再适应市场的需求了。更加现实的问题是,随着Java、.Net甚至是JavaScript等语言的流行,程序员可以选择的语言越来越多,这更加导致了优秀的C/C++程序员所占比例越来越小。而网游市场的不断扩大,对人才的需求也越来越大,这就造成了大量的人才空缺,也就反过来提高了使用C/C++开发游戏的成本。而由于C/C++是门入门容易进阶难的语言,其高级特性和高度灵活性带来的高风险也是每个项目使用C/C++进行开发时所不得不考虑的问题。
一个可以解决这种困境的举措便是在游戏中使用脚本。可以说游戏脚本的出现,不仅解决了由于C/C++难以精通而带来的开发效率问题,而且还降低了使用C/C++进行开发的项目风险和成本。从此,脚本与游戏开发相得益彰,互相促进,逐渐成为了游戏开发中不可或缺的一个部分。
而到了如今手游兴起的年代,市场的需求变得更加庞大且变化更加频繁。这就更加需要用脚本语言来提高项目的开发效率、降低项目的成本。
而作为游戏脚本,它具体的优势都包括哪些呢?
易于学习,代码方便维护。适合快速开发。
开发成本低。因为易于学习,所以可以启用新人,同时开发速度快,这些都是降低成本的方法。
因此,包括Unity3D在内的众多游戏引擎,都提供了脚本接口,让开发者在开发项目时能够摆脱C/C++(注:Unity3D本身是用C/C++写的)的束缚,这其实是变相降低了游戏开发的门槛,吸引了很多独立开发者和游戏制作爱好者。
What? Mono提供的脚本机制首先一个问题:Mono是什么?
Mono是一个由Xamarin公司赞助的开源项目。它基于通用语言架构(Common Language Infrastructure ,缩写为CLI)和C#的ECMA 标准(Ecma-335、Ecam-334),提供了微软的.Net框架的另一种实现。与微软的.Net框架不同的是,Mono具备了跨平台的能力,也就是说它不仅能运行在Windows系统上,而且还可以运行在Mac OSX、Linux甚至是一些游戏平台上。
所以把Mono作为跨平台的方案是一个不错的选择。但Mono又是如何提供这种脚本功能的呢?
如果需要利用Mono为应用开发提供脚本功能,那么其中一个前提就是需要将Mono的运行时嵌入到应用中,因为只有这样才有可能使托管代码和脚本能够在原生应用中使用。我们可以发现,将Mono运行时嵌入应用中是多么的重要。但在讨论如何将Mono运行时嵌入原生应用中去之前,我们首先要搞清楚Mono是如何提供脚本功能的,以及Mono提供的到底是怎样的脚本机制。
Mono和脚本本小节将会讨论如何利用Mono来提高我们的开发效率以及拓展性而无需将已经写好的C/C++代码重新用C#写一遍,也就是Mono是如何提供脚本功能的。
使用一种编程语言开发游戏是比较常见的一种情况。因而游戏开发者往往需要在高效率的低级语言和低效率的高级语言之间抉择。例如一个用C/C++开发的应用的结构如下图:
可以看到低级语言和硬件打交道的方式更加直接,所以其效率更高。
可以看到高级语言并没有和硬件直接打交道,所以效率较低。
如果以速度作为衡量语言的标准,那么语言从低级到高级的大体排名如下:
开发者在选择适合自己的开发语言时,的确面临着很多现实的问题。
高级语言对开发者而言效率更高,也更加容易掌握,但高级语言并不具备低级语言的那种运行速度,甚至对硬件的要求更高,这在某种程度上的确也决定了一个项目到底是成功还是失败。
因此,如何平衡两者,或者说如何融合两者的优点,便变得十分重要和迫切。脚本机制便在此时应运而生。游戏引擎由富有经验的开发人员使用C/C++开发,而一些具体项目中功能的实现,例如UI、交互等等则使用高级语言开发。
通过使用高级脚本语言,开发者便融合了低级语言和高级语言的优点。同时提高了开发效率,如同第一节中所讲的,引入脚本机制之后开发效率提升了,可以快速开发原型,而不必把大量的时间浪费在C/C++上。
脚本语言同时提供了安全的开发沙盒模式,也就是说开发者无需担心C/C++引擎中的具体实现细节,也无需关注例如资源管理和内存管理这些事情的细节,这在很大程度上简化了应用的开发流程。
而Mono则提供了这种脚本机制实现的可能性。即允许开发者使用JIT编译的代码作为脚本语言为他们的应用提供拓展。
目前很多脚本语言趋向于选择解释型语言,例如cocos2d-js使用的JavaScript,因此效率无法与原生代码相比。而Mono则提供了一种将脚本语言通过JIT编译为原生代码的方式,提高了脚本语言的效率。例如,Mono提供了一个原生代码生成器,可以提高应用的运行效率。它同时提供了很多方便的调用原生代码的接口。
在为一个应用提供脚本机制时,往往需要和低级语言交互。这便不得不提到将Mono的运行时嵌入到应用中的必要性了。那么接下来,我将会讨论一下如何将Mono运行时嵌入到应用中。