100steps/Blogs

浅谈游戏脚本系统

PieroCoding opened this issue · 2 comments

最近在看《游戏脚本高级编程》,所以想向大家分享一下书里的内容。不过书已经暂时还回广图,所以我不能翻书,只能全凭记忆写这篇分享,因此如有错误敬请提出。

游戏的组成部分

一个游戏主要包括游戏引擎,游戏脚本,美术和音乐等游戏材料。

游戏引擎,是一个很复杂的系统,包括图形渲染系统、物理碰撞系统等等。而像游戏引擎里的物理碰撞系统,简单来说就是计算两个物体是否碰撞在一起,例如枪战游戏里人物是否中弹啦、哪个部位中弹啦。所以游戏引擎,就是负责一个游戏的计算和渲染的大型程序。

游戏脚本,就是控制剧情和每一个游戏角色行为的背后程序。例如一个NPC,他的行为就是不断行走,然后遇到人就说:“你好。“这就是背后一个程序脚本来控制他的行为。又例如,你已经把小boss打败,下面该打大boss了,剧情脚本就会控制切换画面、更换音乐、导入大boos的脚本。所以游戏脚本,就是控制剧情和控制人物的行为的多个程序。

为什么需要脚本系统

现在多数游戏引擎都由C++写出,当你把一个人物的所有属性都写进游戏引擎时,你编译整个游戏程序将耗费大量时间,所以解决办法就是把各个部分都分离,把一个游戏变成一个个互不相同的模块。于是细分下去,就把剧情任务、人物行为这一部分和游戏引擎那一部分分离了开来。

而且,因为已经有了游戏引擎,若想增加新的剧情,你就可以只写游戏脚本,这样游戏公司就降低了很多成本。就例如有些游戏发布一些新的副本。

虚拟机实现与动态链接程序实现

对于脚本系统,最流行的实现方法有两种,一是像python一样的运行在虚拟机上的动态语言,二是利用游戏引擎提供的接口控制游戏的二进制dll动态链接程序。

对于第一种实现方法,例子有《梦幻西游》。《梦幻西游》的游戏脚本语言是云风修改lua源码后得到的一种lua方言,所以它和正版lua不兼容,又因为lua是一种小众语言,所以使得开发外挂变得困难,这在当时是很成功的。这种实现方法,所有游戏脚本程序都是运行在虚拟机上面的,并不是运行在本地电脑上的二进制程序。

对于第二种实现方法,例子有经典游戏CS。CS是由外国玩家写的mod,他利用《半条命》提供的接口构造了另一种玩法,而这个mod本身是运行在本地电脑上的二进制程序,所以就是相当于插件一样。还有一个著名例子就是Dota啦。

对于虚拟机的实现方法,在运行速度上肯定比不过动态链接程序。但是在编写上更容易,因为虚拟机上运行的是解释型的语言,所以修改后不用编译就马上可以看到改动效果,而动态链接程序还需要编译时间。

在安全性上,动态链接程序因为运行在本地电脑上,所以这个程序的作者可以写一些恶意的代码,例如去扫描你的所有文件,也可以去攻击服务器。同时如果代码质量差,动态链接程序还会容易奔溃,影响到本地电脑。所以动态链接程序安全性应该说是比较差的。

而对于虚拟机的实现方法,因为脚本都运行在虚拟机里,是比较安全的。因为虚拟机可以禁止脚本去访问那些不能访问的地方,而且如果脚本奔溃了还可以没有负担地重启脚本。

举个栗子

例如现有一个类似C++的动态语言,写了一个箱子类
class box
{
function move(event);
function explode(event);
var x;
var y;
};
当人物行走时,游戏引擎会计算人物与箱子的距离,如果人物当前位置和箱子的位置重合了,游戏引擎就会调用箱子的move方法,向move方法发送event。event是一个结构体,是游戏引擎调用脚本方法时发送给脚本的,里面的变量告诉箱子脚本很多信息,包括碰撞力的方向与大小、发出力的物体等等。然后move方法就会根据event结构体来改变box的位置,同时调用游戏引擎的物理系统来计算轨迹,调用渲染系统来显示箱子移动的效果。而控制爆炸的方法explode也是同样的道理,只是调用渲染系统来显示的是爆炸效果,爆炸效果结束后调用渲染系统使自己不再显示,最后脚本退出。

你觉得游戏脚本高级编程这本书怎么样?(正好有朋友要去广图,或许可以借回来看看(^__^))

这本书其实是关于编译原理的一本书,所以我并不推荐用其来学习游戏编程。这本书前两章说了些关于游戏的一些知识(也就是我上面说的),但是后面的章节就很少涉及游戏方面的知识。这本书的组织形式是由游戏脚本编程引出编译原理,例如它后面教如何写汇编器,如何设计一门脚本语言,如何实现运行这个语言的虚拟机等等。