::金点时空::

圣二脚本实现原理
tiamo


关于圣二的脚本部分

脚本部分就是要自己实现一个解释机,并且以恰当的方式加入到游戏循环里面去.

拿圣二的来说
脚本解释部分就是要识别特殊的字符
这些特殊的字符就是脚本指令
比如是say比如是talk等等

先打开一个脚本文件
读入全部的内容
从文件开头查找这些关键字
比如我们有一个脚本里面有一句话(暂时不考虑这个脚本的对错)
Say("大家好","lt");
那我们在把这个文件读入以后
就开始查找

圣二的整个过程是这样
先读入一行
然后在这一行中得到指令名字
根据这个指令名字找到指令相关的参数
在以一定的方式嵌入到游戏循环里面(这个在后面讲)

那好
我们一个一个的看
读入一行很简单
只要从当然的位置向下找表示指令结束的标志就可以了
圣二里面如果有用//的话
就表示这个后面是注释也是表示这个指令结束了
还可以用;和tab
结束以后我们把有用的指令放到一个字符串里面
用上面的例子就是
现在我们有一个字符串
里面放着
say("大家好","lt")

接下来是找到指令名字了
也简单
找指令里面的(
也有些指令是没有()的
那就是说整个字符串都是指令名字
上面的例子来说
我们就得到指令名字Say

得到了这个名字就好办了
我们用他和我们事先保持好的指令列表来对比
找到相应的项目
对这个指令的参数做合理的解释
这里说说指令列表

一个结构
//指令结构
struct stCommand{
int Id; //指令编号
char Name[32]; //指令名称
};

用一个id和一个名字表示
打开script.ini来看
是一个10=XXX的格式
那个10就是指令的id
而那个XXX是指令的名字

好了接着就好办了
在我们的指令列表里面找到Say这个指令(不分大小写)
得到id假如是10
我们就这样写
if(id==10) // 表示这个是一个say指令
{
// 然后对这个指令的产生进行分析
}

对于say这个指令
策划的时候就定了下来用三个参数,两个必须的一个确省的,而且是两个字符串型接一个整型的

接着我们就是得到这个三个参数了
对我们刚刚的指令字符串进行分析
先找到(
的位置跳过前面的指令名字
然后查找参数之间的分隔符
这样可以把一个个的参数分开
对于字符型的
我们可以直接使用
对于数字型的
由于我们得到的是字符串
要进行转换
也很容易
调用atoi就可以了
这个部分有点复杂
查看源代码,里面有比较详细的注释

指令解释部分就基本是这个样子
实际上是根据不同的功能写成了一个个的函数
那个指令配对部分也不是用的if
而是用的switch-case结构

然后说说脚本系统的嵌入
圣二用一个消息队列的方式和脚本系统配合嵌入到游戏循环中

对于几乎是所有的脚本指令
解释清楚了转换成一个个的消息放到消息队列(自己维护的消息队列不是windows的消息队列)里面
这个消息包括了
指令的名字(消息名)
指令的各个参数(支持到6个)
消息的结构如下
//消息传递数据
typedef struct{
enum MESSAGE msg; //消息类型
int Param1, Param2, Param3; //参数
char *String1, *String2, *String3, *String4; //字符指针参数
}stMessage;

然后在每次游戏循环的末尾根据当前的游戏状态
进行消息的执行---
根据消息的名字和参数实际的调用真实的函数

关于那个游戏状态
圣二有两种
1种是一次执行一个消息
1种是不停的执行消息直到有指令结束这种状态为止

基本就是这样


金点 tiamo
2002/8/19(第一稿)
http://www.gpgame.net