实现一个简单的脚本系统

终于又有时间写文章了,这回我们要实现一个简单的脚本系统(很简单的)!

  说实话,原来《电脑报 2004年合订本》有个很好的直角90度游戏开发系列,里面的游戏脚本系统讲得还可以,如果你对本文还存在疑惑,可以看那一个游戏开发系列。

  和以前一样,我在脚本系统中没有掺合任何关于DirectX的内容,只讲理论!

  看看KGameV1.0(2005年5月初次在gameres中出现,就是13岁开发游戏的那个文章:))的脚本系统实现.

  首先是脚本类:
class CScript
{
char Name[64];
vector<stVariable> VARA;
bool ScrIsFill; //脚本运行时是否使用黑屏
string str; //一行完整的指令
string M_CMD; //M_CMD 命令,M_CAN 临时储存参数
string M_CANX[MAX_CANX]; //参数数组
string M_CAN,M_RIGHT;
string M_VAR; //变量
string M_value; //变量,如果为空,就为"="右边去掉";"的数据,否则为"="右边脚本的返回值
string M_IFO,M_IFT;
int CanB[MAX_CANX]; //参数是布尔的话在这里储存
public:
CScript();
~CScript();
bool LoadScript(char *FileName);
void ScriptXCanC();
void ShowERROR(string M_CMD); //显示错误
void FenJScript();
void RunScript();
void FenJVar();
bool BScriptBg(char *FileName);
bool AddVar(string Name,string value);
bool ClearVar();
};

  其实就只有这些东西,读取一个脚本,弄出一行的内容,分析一行的的内容(这时候边分析边执行相应的函数),添加一个变量,删除一个变量,等等.....

  读取脚本的实现(其实这个KGameV1.0写得并不好,我自己承认的,但起码做出来了,呵呵!)

bool CScript::LoadScript(char *FileName)
{
ifstream is;
int ZS;
int sta,end;
if (IsFile(FileName)==false) return false; //直接返回,因为不存在
IsNextLine=true;
strcpy(Name,FileName);
is.open(FileName);
if (IsNextLine==true) getline(is,str);
ZS=int(str.find("//"));
str=str.substr(0,ZS); //去掉注释语句
replace_all_distinct(str,"'",""); //自己写的替换函数
replace_all_distinct(str,syh,""); //自己写的替换函数,syh是双引号的ASCII码
if (stricmp(str.c_str(),"return;")==0||stricmp(str.c_str(),"return();")==0) break;
else RunScript();
//IF语句的实现
if (stricmp(M_CMD.c_str(),"If")==0)
{
int IfP=2;
//If(X(Y)) 肯定条件,相符运行语句
if (M_CANX[0].find("(")!=-1)
{
sta=int(M_CANX[0].find("(")); //比如IF(XX[(]XX))
end=int(M_CANX[0].find_last_of(")"));//比如IF(XX(XX[)])
M_IFO=M_CANX[0].substr(0,sta);//获取IF里的命令
M_IFT=M_CANX[0].substr(sta+1,end-sta-1);//获取if里的变量
//strcpy(SMessage,M_IFO.c_str());
if (M_IFO==M_IFT) IfP=0; //0为通过
else IfP=1; //1为不通过
}
//If(X[Y]) 否定条件,不符运行语句
if (M_CANX[0].find("[")!=-1)
{
sta=int(M_CANX[0].find("[")); //比如IF(XX[XX])
end=int(M_CANX[0].find_last_of("]"));//比如IF(XX[XX])
M_IFO=M_CANX[0].substr(0,sta);//获取IF里的命令
M_IFT=M_CANX[0].substr(sta+1,end-sta-1);//获取if里的变量
if (M_IFO!=M_IFT)IfP=0; //0为通过
else IfP=1; //1为不通过
}

if (IfP!=2)
{
if (IfP==0)
{
while(str!="}") //什么时候结束
{
if (IsNextLine==true) getline(is,str);
ZS=int(str.find("//"));
str=str.substr(0,ZS); //去掉注释语句
replace_all_distinct(str,"'","");
replace_all_distinct(str,syh,"");
if (str.find("return;")!=str.npos||str.find("return();")!=str.npos) {break;break;} //结束脚本
else RunScript();
//二级IF
//完成
}
}
else
{
while(str!="}") //什么时候结束
{
getline(is,str); //到"{"这一行
}
}
}
IfP=2;
M_IFO.clear();
M_IFT.clear();
} //IF结束
//结束
}
M_IFO.clear();
M_IFT.clear();
is.close();
return true;
}

  其实IF语句的实现占了代码比较多的比例,简单的方法就是ifstream这个东西有一个读取一行的函数substr,具体的自己研究一下吧,也可以用KGame V1.0的代码学习.

  运行了这段代码后,脚本就被切成一行一行的(此时"//"和这行后面的内容早已删去),下一个函数:

void CScript::RunScript() //运行一行脚本
{
int VarVa=int(str.find_first_of("="));
int sta=int(str.find_first_of("("));
int end=int(str.find_last_of(")"));
M_VAR=str.substr(0,VarVa);//获取变量
M_CMD=str.substr(VarVa+1,sta-VarVa-1);//获取命令
M_CAN=str.substr(sta+1,end-sta-1);//获取全部参数
M_RIGHT=str.substr(VarVa+1,strlen(str.c_str()));
for (int i=0;i<int(VARA.size());i++)
{
replace_all_distinct(M_CAN,"["+VARA[i].Name+"]",VARA[i].value);
replace_all_distinct(M_CAN,VARA[i].Name,VARA[i].value);
}
for (int i=0;i<MAX_CANX;i++)
{
sta=int(M_CAN.find(","));
M_CANX[i]=M_CAN.substr(0,sta);
M_CAN.replace(0,sta+1,"");
if (stricmp(M_CANX[i].c_str(),"False")==0) CanB[i]=0;
else if (stricmp(M_CANX[i].c_str(),"True")==0) CanB[i]=1; //布尔变量读取
}
if (M_CMD.length()!=0)FenJScript(); //执行脚本
if (M_VAR.length()!=0)FenJVar(); //分析变量,因为脚本有的有返回值
}

  我的代码风格不是很好,凑合看看吧!

  这段就是把这一行给拆开,M_CMD就是gggg(1fs,fs)的gggg,M_CAN是1fs,fs的字符串,M_CANX就是一个数组,里面存贮着一个个参数,比如这里M_CANX[0]="1fs",M_CANX[1]="fs",注意我使用的是STL的string,具体的资料可以上网查.

  把命令和参数分开了,下一步就是执行了.

if (stricmp(M_CMD.c_str(),"Close")==0) RunMessage(MS_Close,0,NULL,0,0,0,0,NULL,0); //命令2,关闭引擎

else if (stricmp(M_CMD.c_str(),"NewMap")==0) //创建地图
{
strcpy(Tempc,M_CANX[0].c_str());t5=atoi(Tempc);

strcpy(Tempc,M_CANX[2].c_str());t1=atoi(Tempc);
strcpy(Tempc,M_CANX[3].c_str());t2=atoi(Tempc);
strcpy(Tempc,M_CANX[4].c_str());t3=atoi(Tempc);
strcpy(Tempc,M_CANX[5].c_str());t4=atoi(Tempc);
strcpy(Tempc,M_CANX[6].c_str());t6=atoi(Tempc);
strcpy(Tempc,M_CANX[1].c_str());
strcpy(tmpc,M_CANX[7].c_str());
RunMessage(MS_NWMAP,t5,Tempc,t1,t2,t3,t4,tmpc,t6);
}

else if (stricmp(M_CMD.c_str(),"ReadATile")==0) //读取一个TILE资源到表面
{
strcpy(Tempc,M_CANX[0].c_str());t1=atoi(Tempc);
strcpy(Tempc,M_CANX[1].c_str());
RunMessage(MS_RAT,t1,Tempc,0,0,0,0,NULL,0);
}
else if (stricmp(M_CMD.c_str(),"NewVar")==0) AddVar(M_CANX[0],M_CANX[1]);//创建变量
else if (stricmp(M_CMD.c_str(),"ClearVar")==0) ClearVar();//清除所有的变量
..... //后面的大同小异

  再声明一次,这个脚本系统只是我学习C++之作,现在绝对不会这样写了,使用KGameV1.0这个源代码也是迫不得已,因为目前我只对这个源代码熟(虽然圣剑得更好,但他的实现太麻烦)

  可以看出这里基本都重复了,就是把这些参数给消息系统(当然现在我的实现方法不会说的 :))

  剩下的就是变量的处理了,看到这部分代码上面不明白的代码基本就明白了!

void CScript::FenJVar()
{
if (M_value.length()==0)
{
M_value=M_RIGHT;
replace_all_distinct(M_value,";","");
}
for (int i=0;i<int(VARA.size());i++)
if (VARA[i].Name==M_VAR) VARA[i].value=M_value;
M_value.clear();//返回清空
}

bool CScript::AddVar(string Name,string value)
{
stVariable TVar;
TVar.Name=Name;
TVar.value=value;
VARA.push_back(TVar); //压这个变量
return true;
}

bool CScript::ClearVar()
{
//清空变量
VARA.clear();
return true;
}

  再补充stVariable结构:

//变量结构
struct stVariable{
string Name; //名称
string value; //当前值
};

  这段代码是后期写的,因为前期的不好构架,所以后期也不能大改了 :( 详细地看注释吧!

  再一次草草完成一篇文章,其实这篇文章是给自己看的,免得以后忘了这段游戏开发的经历!

[全文完]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值