`
252190908
  • 浏览: 228292 次
文章分类
社区版块
存档分类
最新评论

《游戏脚本的设计与开发》-1.3 基础语法(注释,变量,函数,条件语句)

 
阅读更多

本章来解析一些无论在任何语言中都必不可少的脚本语法,分别是注释,变量,函数,条件语句,脚本格式如下。

/*
游戏脚本的设计与开发 第三章
*/
//设定变量num的值为5
Var.set(num,5);
//条件语句脚本测试
if(@num>10);
	Var.set(name,lufy);
elseif(@num>4);
	if(@num==5);
		Var.set(name,你好);
	else;
		Var.set(name,hellow);
	endif;
else;
	Var.set(name,legend);
endif;
Text.label(-,txt01,变量测试:Hello @name,0,0,30,#000000);
//声明test函数
function test(value);
	Text.label(-,txt02,函数测试:@value,0,50,30,#000000);
endfunction;
Call.test(参数测试);
下面我们就来一个一个的实现这些脚本的解析。

1,注释

在脚本中难免会用到注释,而一般的注释方式有以下两种。

//Text.label(-,txt01,Hello World,0,0,30,#000000);
/*Text.label(-,txt01,Hello World,0,0,30,#000000);*/
将这些注释移除的方法,就是找到两种注释的开始和结束的位置,然后将其移除。

removeComment:function(str){
	var self = this;
	var sIndex;
	var eIndex;
	var sStr;
	var eStr;
	sIndex = str.indexOf("/*");
	while(sIndex >=0){
		eIndex = str.indexOf("*/",sIndex + 2);
		sStr = str.substr(0,sIndex);
		eStr = str.substr(eIndex + 2);
		str = sStr + eStr;
		sIndex = str.indexOf("/*");
	}
	sIndex = str.indexOf("//");
	while(sIndex >=0){
		eIndex = str.indexOf("\n",sIndex);
		if(eIndex >= 0){
			sStr = str.substr(0,sIndex);
			eStr = str.substr(eIndex);
			str = sStr + eStr;
			sIndex = str.indexOf("//");
		}else{
			sStr = str.substr(0,sIndex);
			str = sStr;
			sIndex = -1;
		}
	}
	return str;
}
然后在每次读取脚本文件的时候,用上面这个函数过滤一下,就可以将里面的注释删除了。

2,变量

对于任何一种语言来说,变量都是不可缺少的,脚本中也是一样,比如游戏中有很多分支选择,游戏要根据玩家做出的不同的选择,来进行不同的剧情发展,这些选择我们必须使用大量的变量来保存。

先来扩展一下LScriptArray类,如下

function LScriptArray(){
	var self = this;
	self.textList = new Array();
	self.layerList = new Array();
	self.varList = new Array();
	self.funList = new Array();
}
varList用来保存变量,funList用来保存函数,这个讲完变量后接着就会讲。

先来规定一下变量的语法

//设定变量
Var.set(name,lufy);
//使用变量 @+变量名
Text.label(-,txt01,变量测试:Hello @name,0,0,30,#000000);

先来实现一下变量的设定,修改一下解析函数的switch部分。

switch(sarr[0]){
	case "Load":
		ScriptLoad.analysis(lineValue);
		break;
	case "Text":
		ScriptText.analysis(lineValue);
		break;
	case "Var":
		ScriptVarlable.analysis(lineValue);
		break;
	default:
		self.analysis();
}
ScriptVarlable类代码如下

/*
* ScriptVarlable.js
**/
var ScriptVarlable = function (){};
ScriptVarlable.analysis = function (value){
	var start = value.indexOf("(");
	var end = value.indexOf(")");
	switch(value.substr(0,start)){
		case "Var.set":
			ScriptVarlable.setVarlable(value,start,end);
			break;
		default:
			LGlobal.script.analysis();
	}
};
ScriptVarlable.setVarlable = function (value,start,end){
	var script = LGlobal.script;
	var lArr = value.substring(start+1,end).split(",");
	script.scriptArray.varList[lArr[0]] = lArr[1];
	script.analysis();
};
这个不难看懂,在setVarlable函数中,将Var.set(name,lufy);括号中的内容以分号隔开,作为变量的名字和值存到了varList数组中。

变量在使用的时候,我定义的规则是@+变量名,在解析每一行脚本的时候,找到@符号看看它后面的变量名是否存在即可,实现方法如下。

ScriptVarlable.getVarlable = function (str){
	var script = LGlobal.script;
	var iIndex = 0;
	var sIndex;
	var eIndex;
	var sStr;
	var eStr;
	var vStr;
	var result = "";
	var r=/^([a-z]|[A-Z]|_)+$/;
	sIndex = str.indexOf("@");
	while(sIndex >=0){
		eIndex = str.indexOf("@",sIndex+1);
		if(sIndex + 1 == eIndex){
			sStr = str.substr(iIndex,sIndex);
			vStr = "@";
			eStr = str.substr(eIndex + 1);
			iIndex = eIndex + 1;
		}else{
			sStr = str.substring(iIndex,sIndex);
			vStr = "";
			sIndex++;
			while(r.exec(str.charAt(sIndex))){
				vStr += str.charAt(sIndex);
				sIndex++;
			}
			vStr = script.scriptArray.varList[vStr];
			eStr = str.substr(sIndex);
			iIndex = sIndex;
		};
		result += (sStr + vStr);
		sIndex = str.indexOf("@",iIndex);
	}
	result += str.substr(iIndex);
	return result;
};
只要在解析每一行的脚本之前,调用此函数的话,就会将此行脚本中的变量部分替换成变量的值,达到使用变量的目的。
将Main.ls的内容修改如下

Var.set(name,lufy);
Text.label(-,txt01,变量测试:Hello @name,0,0,30,#000000);
测试一下,得到效果如下

图1
可以看到,第二行中显示文字的时候,“@name”已经被替换成了“lufy”。

3,函数

首先规定好定义函数的脚本如下

function test(value);
	Text.label(-,txt02,函数测试:@value,0,50,30,#000000);
endfunction;
解析上面的脚本的话,可以通过查找关键字function和endfunction来实现,

首先找到包含function关键字的一行脚本,表示声明函数开始,然后再从这一行中找到空格,左括号和右括号,将函数名和参数分离出来。

然后从下一行脚本开始寻找endfunction关键字,如果没有,则表示该行脚本属于函数体内部,如果有,则表示声明函数结束,然后按照函数名,将函数体和参数都保存起来。

具体实现方法如下。

/*
* ScriptFunction.js
**/
var ScriptFunction = function (){};
ScriptFunction.setFunction = function (value){
	var script = LGlobal.script;
	var startNameIndex = value.indexOf(" ");
	var child;
	var funArr = new Array();
	var start = value.indexOf("(");
	var end = value.indexOf(")");
	var strParam = value.substring(start + 1,end);
	var param = strParam.split(",");
	funArr["param"] = new Array();
	var i;
	for(i=0;i<param.length;i++){
		param[i] = LMath.trim(param[i]);
		if(param[i].length > 0)	{
			funArr["param"].push("param_" + param[i]);
		}
	}
	funArr["name"] = LMath.trim(value.substring(startNameIndex + 1,start));
	
	var funLineArr = new Array();
	while(script.lineList[0].indexOf("endfunction") < 0){
		child = script.lineList.shift();
		for(i=0;i<param.length;i++){
			if(param[i].length > 0)	child = child.replace("@"+param[i],"@param_"+param[i]);
		}
		funLineArr.push(child);
	}
	script.lineList.shift();
	funArr["function"] = funLineArr;
	script.scriptArray.funList[funArr["name"]] = funArr;
	script.analysis();
};
既然已经可以声明函数了,那接下来就是如何调用这个函数了,调用函数的脚本语法如下

Call.test(参数测试);
这行脚本表示调用函数test,并传入“参数测试”这个字符串作为函数的参数。

如何找到test这个函数并运行这个函数呢,如下。

ScriptFunction.analysis = function (value){
	var script = LGlobal.script;
	var point = value.indexOf(".");
	var start = value.indexOf("(");
	var end = value.indexOf(")");
	var name = value.substring(point + 1,start);
	var funArr = script.scriptArray.funList[name];
	if(funArr == null){
		script.analysis();
		return;
	}
	_data = value.substring(start+1,end).split(",");
	var param = funArr["param"];
	var i;
	for(i=0;i<param.length;i++){
		script.scriptArray.varList[param[i]] = _data[i];
	}
	var funLineArr = funArr["function"];
	for(i=funLineArr.length-1;i>=0;i--)script.lineList.unshift(funLineArr[i]);
	script.analysis();
	
};
其实就是通过“test”这个函数名,从funList数组中找到相应的函数,然后将保存在函数体内的脚本添加到脚本解析队列lineList里,这样解析函数就会自动解析这些脚本,从而达到调用函数的目的。

最后修改解析函数的switch部分,如下

switch(sarr[0]){
	case "Load":
		ScriptLoad.analysis(lineValue);
		break;
	case "Text":
		ScriptText.analysis(lineValue);
		break;
	case "Var":
		ScriptVarlable.analysis(lineValue);
		break;
	case "Call":
		ScriptFunction.analysis(lineValue);
		break;
	default:
		if(lineValue.indexOf("function") >= 0){
			ScriptFunction.setFunction(lineValue);
		}else{
			self.analysis();
		}
}
接着类测试一下函数的脚本吧,修改Main.ls文件如下
function test(value);
	Text.label(-,txt02,函数测试:@value,0,50,30,#000000);
endfunction;
Call.test(参数测试);
运行程序,得到效果如图

图2

函数“test”已经成功被调用了,并且参数也成功的传了进去。

4,条件语句

条件语句就是if...else...了,这个相对复杂一些,因为涉及到多层嵌套,if里面还有if。

条件语句的定义如下

if(条件);
	脚本
else if(条件);
	脚本
else;
	脚本
endif;
和函数一样,解析这些脚本关键在于“if”,“else if”,“else”,“endif”这些关键字,只要正确查找到这些关键字,就能解析这些脚本。
if条件语句的解析函数如下

/*
* ScriptIF.js
**/
var ScriptIF = function (){};
ScriptIF.getIF = function (value){
	var script = LGlobal.script;
	var startifIndex = 0;
	var endifIndex = 0;
	var ifArr;
	var childArray = new Array();
	var start = value.indexOf("(");
	var end = value.indexOf(")");
	var str = value.substring(start + 1,end);
	ifArr = str.split("&&");
	var ifvalue = ScriptIF.checkCondition(ifArr);
	var ifvalueend = false;
	var sCount = 0;
	var eCount = 0;
	
	while(startifIndex<script.lineList.length){
		sCount = 0;
		
		if(script.lineList[startifIndex].indexOf("elseif") >= 0){
			if(ifvalue){
				ifvalueend = true;
				startifIndex++;
				continue;
			}
			start = script.lineList[startifIndex].indexOf("(");
			end = script.lineList[startifIndex].indexOf(")");
			str = script.lineList[startifIndex].substring(start + 1,end);
			str = ScriptVarlable.getVarlable(str);
			ifArr = str.split("&&");
			ifvalue = ScriptIF.checkCondition(ifArr);
			startifIndex++;
			continue;
		}else if(script.lineList[startifIndex].indexOf("else") >= 0){
			if(ifvalue){
				ifvalueend = true;
				startifIndex++;
				continue;
			}
			ifvalue = true;
			endifIndex = startifIndex;
			startifIndex++;
			continue;
		}else if(script.lineList[startifIndex].indexOf("endif") >= 0){
			startifIndex++;
			break;
		}else if(script.lineList[startifIndex].indexOf("if") >= 0){
			if(ifvalue && !ifvalueend){
				childArray.push(script.lineList[startifIndex]);
			}
			startifIndex++;
			sCount = 1;
			eCount = 0;
			while(sCount > eCount){
				if(script.lineList[startifIndex].indexOf("if") >= 0 && 
					script.lineList[startifIndex].indexOf("else") < 0 && 
					script.lineList[startifIndex].indexOf("end") < 0){
					sCount++;
				}else if(script.lineList[startifIndex].indexOf("endif") >= 0){
					eCount++;
				}
				if(ifvalue && !ifvalueend){
					childArray.push(script.lineList[startifIndex]);
				}
				startifIndex++;
			}
		}
		if(sCount==0){
			if(ifvalue && !ifvalueend){
				childArray.push(script.lineList[startifIndex]);
			}
			startifIndex++;
		}
	}
	script.lineList.splice(0,startifIndex);
	
	for(var i=childArray.length - 1;i>=0;i--){
		script.lineList.unshift(childArray[i]);
	}
	
	script.analysis();
};
ScriptIF.checkCondition = function (arr){
	for(var i = 0;i<arr.length;i++){
		if(!ScriptIF.condition(arr[i])){
			return false;
		}	
	}
	return true;
};
ScriptIF.condition = function (value){
	var arr;
	if(value.indexOf("===") >= 0){
		//===
		arr=ScriptIF.getCheckStr(value,"===");
		return arr[0] == arr[1];
	}else if(value.indexOf("!==") >= 0){
		//!==
		arr=ScriptIF.getCheckStr(value,"!==");
		return arr[0] != arr[1];
	}else if(value.indexOf("==") >= 0){
		//==
		arr=ScriptIF.getCheckInt(value,"==");
		return arr[0] == arr[1];
	}else if(value.indexOf("!=") >= 0){
		//!=
		arr=ScriptIF.getCheckInt(value,"!=");
		return arr[0] != arr[1];
	}else if(value.indexOf(">=") >= 0){
		//>=
		arr=ScriptIF.getCheckInt(value,">=");
		return arr[0] >= arr[1];
	}else if(value.indexOf("<=") >= 0){
		//<=
		arr=ScriptIF.getCheckInt(value,"<=");
		return arr[0] <= arr[1];
	}else if(value.indexOf(">") >= 0){
		//>
		arr=ScriptIF.getCheckInt(value,">");
		return arr[0] > arr[1];
	}else if(value.indexOf("<") >= 0){
		//<
		arr=ScriptIF.getCheckInt(value,"<");
		return arr[0] < arr[1];
	}
	return false;
};
ScriptIF.getCheckInt = function (value,s){
	var arr;
	arr = value.split(s);
	arr[0] = parseInt(arr[0]);
	arr[1] = parseInt(arr[1]);
	
	return arr;
};
ScriptIF.getCheckStr = function (value,s){
	var arr;
	arr = value.split(s);
	arr[0] = LMath.trim(arr[0].replace('"',''));
	arr[1] = LMath.trim(arr[1].replace('"',''));
	
	
	return arr;
};

最后修改解析函数的switch部分,如下

switch(sarr[0]){
	case "Load":
		ScriptLoad.analysis(lineValue);
		break;
	case "Text":
		ScriptText.analysis(lineValue);
		break;
	case "Var":
		ScriptVarlable.analysis(lineValue);
		break;
	case "Call":
		ScriptFunction.analysis(lineValue);
		break;
	default:
		if(lineValue.indexOf("if") >= 0){
			ScriptIF.getIF(lineValue);
		}else if(lineValue.indexOf("function") >= 0){
			ScriptFunction.setFunction(lineValue);
		}else{
			self.analysis();
		}
}

最后,来测试一下,修改Main.ls脚本文件如下

Var.set(num,1);
if(@num==0);
	Var.set(name,lufy);
else;
	Var.set(name,legend);
endif;
运行程序得到效果

图3

再来个稍微复杂点的例子,继续修改Main.ls脚本文件如下

Var.set(num,5);
if(@num>10);
	Var.set(name,lufy);
elseif(@num>4);
	if(@num==5);
		Var.set(name,你好);
	else;
		Var.set(name,hellow);
	endif;
else;
	Var.set(name,legend);
endif;
运行程序得到效果

图4

基本语法讲完了,本来想实现下循环的,不过暂时用不到,等以后用到的时候再详细说说吧,

目前为止讲解的脚本只有文字,大家是不是觉得很无聊?下一章开始进入图形和图片等脚本的解析,要开始有图像了。


测试连接如下

http://lufylegend.com/demo/test/lsharp/03/index.html

本章为止的lufylegend.lsharp.js源码如下

http://lufylegend.com/demo/test/lsharp/03/lufylegend.lsharp.js

《游戏脚本的设计与开发》系列文章目录

http://blog.csdn.net/lufy_legend/article/details/8888787



本章就讲到这里,欢迎继续关注我的博客

转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend

分享到:
评论

相关推荐

    matlab常用函数大全

    3.3 脚本文件、函数及变量 3.4 参数处理 3.5 信息显示 3.6 交互式输入 4、基本矩阵函数和操作 4.1 基本矩阵 4.2 矩阵基本信息 4.3 矩阵操作 4.4 特殊变量和常量 4.5 特殊矩阵 5、基本数学函数 ...

    python基础教程课后答案-Python基础教程(第2版).pdf

    6 1.3 算法是什么 7 1.4 数字和表达式 8 1.4.1 长整型数 9 1.4.2 ⼗六进制和⼋进制 10 1.5 变量 10 1.6 语句 11 1.7 获取⽤户输⼊ 12 1.8 函数 13 1.9 模块 14 1.9.1 cmath和复数 14 1.9.2 回到__future__ 15 1.10 ...

    python基础教程 第三版 中文 高清 pdf

    第1 章 快速上手:基础知识 1.1 交互式解释器 1.2 算法是什么 1.3 数和表达式 1.4 变量 1.5 语句 1.6 获取用户输入 1.7 函数 1.8 模块 1.8.1 cmath和复数 1.8.2 回到未来 1.9 保存并执行程序 1.9.1 从...

    VBSCRIPT中文手册

    Option Explicit 语句 强制显式声明脚本中的所有变量。 Or 运算符 执行两个表达式的逻辑“或”运算。 Pattern 属性 设置或返回正被搜索的正则表达式的模式。 Private 语句 声明私有变量并分配存储空间。 ...

    Perl 实例精解(第三版).pdf

    附录含有完整的函数和定义、命令行开关、特殊变量、常见模块和Perl调试器的列表,全功能的、面向对象的CGI程序,一些有用的脚本,以及很有帮助的HTM教程。 本书非常适合于Perl语言初学者阅读,对于Perl程序员,也有...

    VBSCRIP5 -ASP用法详解

    Option Explicit 语句 强制显式声明脚本中的所有变量。 Or 运算符 执行两个表达式的逻辑“或”运算。 Pattern 属性 设置或返回正被搜索的正则表达式的模式。 Private 语句 声明私有变量并分配存储空间。 ...

    SQLServer2000高级编程技术-已添加书签,想学存储过程、SQL编程务必要看,分析非常透彻

    4.6.2 与光标有关的语句和函数 4.6.3 使用光标带来的问题 4.6.4 合理使用光标 4.7 小结 4.8 练习 第5章 函数 5.1 使用函数 5.1.1 用于选择和赋值中 5.1.2 用于过滤规则中 5.1.3 用于表达式中 5.1.4 作为检查和默认的...

    SQLServer2000高级编程技术(part02)-想学存储过程 SQL编程 务必要看

    4.6.2 与光标有关的语句和函数 4.6.3 使用光标带来的问题 4.6.4 合理使用光标 4.7 小结 4.8 练习 第5章 函数 5.1 使用函数 5.1.1 用于选择和赋值中 5.1.2 用于过滤规则中 5.1.3 用于表达式中 5.1.4 作为检查和默认的...

    php网络开发完全手册

    4.2.7 变量检测函数isset与变量释放 4.2.7 函数unset 66 4.2.8 随机函数rand与srand 66 4.3 关于引用的解释 67 4.3.1 对变量的引用 67 4.3.2 对函数的引用 68 4.3.3 引用的释放 68 4.4 小结 69 第5章 PHP中类的应用 ...

    Shell脚本专家指南

    全书分为3个部分:脚本技术基础、系统交互和高级技术、有用的脚本实例。主要内容包括如何使小到中型的系统管理任务自动化,分析系统数据并编辑配置文件,使用bash和ksh等编写IAnux、Unix和OSX应用程序的脚本文件等。...

    VBScript 语言参考

    Option Explicit 语句 强制显式声明脚本中的所有变量。 Or 运算符 执行两个表达式的逻辑“或”运算。 Pattern 属性 设置或返回正被搜索的正则表达式的模式。 Private 语句 声明私有变量并分配存储空间。 ...

    VBScript 语言参考中文手册CHM

    Option Explicit 语句 强制显式声明脚本中的所有变量。 Or 运算符 执行两个表达式的逻辑“或”运算。 Pattern 属性 设置或返回正被搜索的正则表达式的模式。 Private 语句 声明私有变量并分配存储空间。 ...

    ebo-script:vscode扩展,用于ebostruxure构建操作脚本编程

    EBO脚本扩展 此“ ebo-script”扩展的预览版增加了对施耐德电气ecostruxureure建筑操作脚本语言的支持。 扩展名 .ebosf-脚本功能 .ebosp-脚本程序 能力 语法高亮 支架匹配 代码段 悬停定义 有限的提示,警告和错误 ...

    vb Script参考文档

    Option Explicit 语句 强制显式声明脚本中的所有变量。 Or 运算符 执行两个表达式的逻辑“或”运算。 Pattern 属性 设置或返回正被搜索的正则表达式的模式。 Private 语句 声明私有变量并分配存储空间。 ...

    python基础教程第三版-Magnus Lie Hetland 著

    新人学习必备书籍: 第 1 章 快速上手:基础知识 1.1 交互式解释器 1.2 算法是什么 1.3 数和表达式 十六进制、八进制和二进制 1.4 变量 1.5 语句 1.6 获取用户输入 1.7 函数 1.8 模块 ...

    javascript函数的解释

    javascript函数的解释,解释了具体函数的功能,一、函数JavaScript函数集合 1.document.write(""); 输出语句 2.JS中的注释为// 3.传统的HTML文档顺序是:document-&gt;html-&gt;(head,body) 4.一个浏览器窗口中的DOM顺序是:...

    Python核心编程(第二版).pdf (压缩包分2部分,第二部分)

     5.6 内建函数与工厂函数   5.6.1 标准类型函数   5.6.2 数字类型函数   5.6.3 仅用于整型的函数   5.7 其他数字类型   5.7.1 布尔“数”   5.7.2 十进制浮点型   5.8 相关模块   5.9 ...

    Python核心编程(第二版).pdf (压缩包分2部分,第一部分)

     5.6 内建函数与工厂函数   5.6.1 标准类型函数   5.6.2 数字类型函数   5.6.3 仅用于整型的函数   5.7 其他数字类型   5.7.1 布尔“数”   5.7.2 十进制浮点型   5.8 相关模块   5.9 ...

Global site tag (gtag.js) - Google Analytics