|
做了两年手机游戏,终于晓得了脚本是个啥东西,为什么做游戏要用到脚本呢,看了无数资料总结如下:
优点:
1,脚本可以实现游戏逻辑,在不修改主游戏引擎并且花费时间去编译的前提下,改变了脚本也就改变游戏的玩法和趣味性
2,硬编码似乎编程人员都不太提倡,所以为了避免硬编码带来的危害,人们乐意将数据放到外部文件,实现数据和引擎的分离,最终发展为
带有逻辑判断的外部数据文件,即脚本。
3,游戏中用到太多的功能函数,一旦需要修改则必须重新编译,如果将功能函数放到脚本里,由游戏引擎来调用将会是一件灵活而又优雅的
做法。
4,将程序员从逻辑处理中解放出来,他们只负责搭建完美表现的游戏主引擎,而为数据逻辑及人物物品的行为编写代码的工作丢给策划
最大限度提高游戏生产力。比如halo里的NPC行为全部都用脚本控制,并且更为神奇的是脚本之间可以相互通信,使得NPC可以
有组织有计划有策略的向玩家发起进攻,真实性不言而喻。
5,安全性,如果脚本的执行出了一点BUG绝不会引起整个游戏的崩溃,大不了卸载脚本再重新加载执行,玩家在游戏中还是正常的打怪和
聊天,一点也没觉得有什么异常。
缺点:
1,运行速度比游戏主引擎慢,即使优化到极限都没有任何速度优势,基于解释型的脚本引擎做游戏压根都不太考虑。
2,设计简单的脚本,编写代码都需要有一定的编程基础,所以策划要想编写出优雅的脚本代码也是需要学习的。
基于脚本的速度问题,我考虑过并经过测试,发现用脚本来实现精灵的逻辑运算一点问题都没有,因为是脚本虚拟机是读字节码,并且全部面向过程,就连与主游戏引擎通信的关键部分,也没有用到javaRTTI机制,最大限度的优化了运行速度,所以用主游戏引擎处理运算量大的图形渲染,脚本去做逻辑运算,我个人倾向于这种完美的搭配。
Snake脚本引擎简介:
一、高级代码编写:
1,语法类似于C。
2,支持函数定义,函数调用,数组,表达式,循环,分支。
3,弱类型(lua也是),内建类型有string,int,float,boolean
如定义变量 var x;可以给x赋的值有 x="你好Snake"; x=32; x=32.23; x=true;
4,内建35个运算符,适用于所有的表达式,如位运算>> 逻辑运算&& 赋值运算 |= 等等,运算符优先级简化为4级,
由高到低为 单目运算>算数运算>关系运算>逻辑运算,如果你写代码是不确定运算符的优先级保险起见加上括号就不会有错
5,支持转义字符输入。
6,支持注释,如行注释符// 及块注释符 /* */
二、低级代码编写:
1,语法类似于8086汇编,但要比它简单的多,有33种虚拟指令可供选择,并且可以定义方法
演示一个完整的加法函数及函数调用(分号是行注释符):
myAdd()
{
param y ;函数参数y
param x ;函数参数x
Add x, y ;将y的值与x相加并赋给x
Mov _RetVal, x ;将x值赋给寄存器(只有一个寄存器即_RetVal)
Ret ; 方法返回符(可以省略)
}
_Main()
{
var x ;定义局部变量x
var y ;定义局部变量y
var z ;定义局部变量
Mov x, 2 ;将2赋给x
Mov y, 3 ;将3赋给y
Push x ;将x压栈,调用方法需要将参数压栈
Push y ;将y压栈
Call myAdd ;调用方法
Mov z, _RetVal ;将寄存器的值赋给z
}
判断和分支的低级代码我就不给出了,想了解的话可以先写高代码,再用编译器编译成低级代码(在编译器中输入参数-A)
再参照低级代码来研究
话说回来,为什么要设计低级代码呢,干脆直接写高级代码多方便,之所以这样设计是由于编译器编译跳转分支那部分都非常的
精简,运行速度非常的快,但是编译表达式就比较繁琐,虽然在3个星期前我压根不知道什么叫编译原理,但是通过写脚本的词法分析,
语法分析,汇编等程序我才发现它的难度和复杂度超出想象好几倍,当前最流行的编译器如C++编译器是用状态机进行语法分析,在表
达式的编译上做足了优化,可是我才是个初学者,为了加快研发速度我使用了半状态机半递归下降的方式进行编译,所以在效率上没有做
太多优化,所以如果您想写复杂表达式求值并需要快速运行的代码,还是建议用低级代码编写,最后可以和高级代码进行合并,用汇编器
汇编成二进制。
三、脚本虚拟机(SVM)
1,虚拟机的执行是基于字节码的,只有一个寄存器_RetVal 用来存放返回值,运行时堆栈是用来进行函数调用的
大小默认是512K,可以自己更改 比如在低级代码上头部加入关键字 SetStackSize 1024 虚拟机会根据设置来修改堆栈大小
2,和主游戏引擎通信是基于方法调用,需要自己写方法库类,这个类需要继承Lib.class, 在自己的方法库中实现方法,考虑到效率,
没有通信是没有用到对象,并且也不是基于RTTI机制,所以使用时务必要注意2点,这两点写在测试包里,可以去看一下
3,错误处理也是考虑到效率没有基于java的异常,而是只打印错印并且虚拟机会正常运行,可是一旦打印出错误,需要做的就是停
下运行的程序 检查脚本有没有,或者是虚拟机的核心执行单元有没有BUG如果不这样做,那么后面的脚本数据已经成脏数据,
会对游戏逻辑造成潜在的危险。
4,多线程:脚本引擎能加载多个脚本并发执行,并且每个线程有个优先级,优先级高的脚本能分到更多的时间片,SVM来管理这些线程
的运行,并且主游戏引擎能方便的操作脚本虚拟机加载,暂停,停止,恢复这些脚本线程。(0.8版提供多线程功能)
5,运行方式:主游戏引擎在while循环中,每次调用虚拟机的runScript(int time)方法,通过传入时间片来决定虚拟机在这个循环
周期运行多长时间,所以脚本里就可以写这样的循环while(true)也就是脚本有自己的逻辑死循环,但是它不会干扰主引擎的逻辑死
循环,因为在传入的时间片运行完时,脚本引擎会自动跳出来让主引擎继续运行下一个循环,而这些对编程人员都是透明的。
四、最后
希望对此有兴趣的人能来共同维护这个脚本引擎,说真的,要不是自己的那点热情,做这么具有挑战的东西我想都不敢想,还好东西
总算完成了,并且经行了一些测试,并将这个引擎用到了公司的游戏中,bug还有没有我不太敢保证,毕竟是最近才做出来,所以希望
大家一起来维护它的版本,并且有好的改进策略一定要告诉我,我期待你们将优秀的编程思想注入其中,让它永远充满活力。
如果在使用的时候有什么困难或bug就欢迎联系我,我们一起探讨一下。
五、感谢
CoCoMo 看了他的脚本引擎才真正了解其内涵。
《游戏脚本高级编程》这本书写的非常好,它里面思想我全部吸纳,并且亲手实现了。
<脚本控制的人工智能AI> 这篇文章让我极度的热衷于人工智能AI脚本的编写,脚本引擎只是个工具,能够编写出智能的NPC那才是本事
《深入java虚拟机》 可以了解虚拟机的一些实现策略和最底层的数据处理。
《人工智能游戏编程真言》 里面有些写对脚本的负面看法,很客观。
六、下载地址:
虚拟机及测试程序
http://www.j2megame.cn/attachment.php?aid=1218
编译器及汇编器
http://www.j2megame.cn/attachment.php?aid=1219
|
|