zoukankan      html  css  js  c++  java
  • 脚本指令《游戏脚本的设计与开发》第一章 读取和解析一个脚本文件

    本文个人在北京吃饭的时候突然想到的...今天就有想写几篇关于脚本指令的文章,所以回家到以后就奋笔疾书的写出来发表了

        

     

        上一篇《游戏脚本的计划与开辟》-序中我介绍了游戏脚本的基本概念和准备工作,本篇来说说具体如何剖析一个脚本

        所谓剖析脚本,就是按照自己定义的语法,将每个脚本命令还原成不同的代码逻辑进行执行,比如,我规定绘制一个矩形的脚本

    draw rect

        和一个绘制圆的脚本

    draw arc

        那么,当我读取到了字符串“draw rect”的时候,就在屏幕上画一个矩形,读取到了字符串“draw arc”的时候,就在屏幕上画一个圆。

        如果你已经按照上一篇序中的说明安装了xampp,那么请找到xampp中的htdocs文件夹,在里面新建一个lsharp文件夹,然后再按照下面结构新建一些文件和文件夹

        lsharp

        |-script文件夹

        |-index.html

        |-Main.js

        |-lufylegend.lsharp.js

        |-lufylegend-1.7.5.js

        index.html文件代码如下

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>L#</title>
    </head>
    <body>
    <div id="mylegend">loading......</div>
    <script type="text/javascript" src="./lufylegend-1.7.5.js"></script> 
    <script type="text/javascript" src="./lufylegend.lsharp.js"></script> 
    <script type="text/javascript" src="./Main.js"></script> 
    </body>
    </html>

        注意:lufylegend-1.7.5.js你须要自己下载。

        剖析脚本,须要建立一个剖析脚本的函数analysis,每剖析完一个脚本,就返回调用一次analysis函数,让剖析一直的进行,直到脚本文件全体剖析结束。

        首先,在lufylegend.lsharp.js文件中新建一个LScript.js类,作为脚本剖析对象,用来控制脚本的剖析和执行。

    /** LScript.js
    **/
    function LScript(scriptLayer,value){
    	var self = this;
    	LGlobal.script = self;
    	self.scriptLayer = scriptLayer;
    	self.dataList = new Array();
    	var arr=[value];
    	self.dataList.unshift(arr);
    	self.toList(value);
    }

        代码剖析:

        LScript.js类接受两个参数,第一个参数scriptLayer是显示层,也是应用L#脚本制作游戏的最底层画板,以后的脚本命令的全部绘图都将绘制到这个显示层上,第二个参数是一个字符串脚本,也是LScript.js对象被创建后立即会被剖析的脚本。

    LGlobal.script = self;

        LGlobal.script将脚本剖析对象保存起来,便利回调脚本的剖析函数。

    self.scriptLayer = scriptLayer;

        将显示层保存起来,便利以后应用。

    self.dataList = new Array();
    var arr=[value];
    self.dataList.unshift(arr);

        保存脚本到缓存数组。

    self.toList(value);

        这一行是将整个字符串脚本进行分解,得到单个的脚本命令数组。

        看一下toList函数:

    toList:function(ltxt){
    	var self = this;
    	self.lineList = ltxt.split(";");
    	self.copyList = self.lineList.slice(0);
    	self.analysis();
    }

        代码剖析:

    self.lineList = ltxt.split(";");

        在L#中,我设定了各个的脚本指令之间是以分号来分割的,所以应用字符串的split函数对字符串进行分割,得到单个的脚本命令数组,并将其存入到脚本剖析对象的lineList。

    self.copyList = self.lineList.slice(0);

        copyList用来保存当前所执行的lineList,当有新的脚本命令lineList被添加进来的时候,当前的lineList就会被保存起来,当新的脚本命令lineList全体剖析完以后,就会对上一个未被剖析完的脚本命令继承进行剖析执行。

    self.analysis();

        开始剖析脚本命令。

        下面看一下症结的脚本剖析函数analysis。

    analysis:function(){
    	var self = this;
    	var lineValue = "";
    	if(self.lineList.length == 0){
    		self.dataList.shift();
    		if(self.dataList.length > 0){
    			arr=self.dataList[0];
    			self.lineList = arr[1];
    			self.copyList = arr[2];
    			self.analysis();
    		}
    		return;
    	}
    	while(self.lineList.length > 0){
    		lineValue = LMath.trim(self.lineList[0]);
    		self.lineList.shift();
    	}
    	if(lineValue.length == 0){
    		self.analysis();
    		return;
    	}
    	trace("analysis lineValue = " + lineValue);
    	var sarr = lineValue.split(".");
    	switch(sarr[0]){
    		default:
    			self.analysis();
    	}
    }

        代码剖析:

    if(self.lineList.length == 0){
    	self.dataList.shift();
    	if(self.dataList.length > 0){
    		arr=self.dataList[0];
    		self.lineList = arr[1];
    		self.copyList = arr[2];
    		self.analysis();
    	}
    	return;
    }

        上面代码判断lineList数组内的脚本指令是不是被剖析完,如果被剖析完了的话,检查一下dataList数组中是否有其他未被执行的脚本,有则继承执行。

    var lineValue = "";
    while(self.lineList.length > 0 && lineValue.length == 0){
    	lineValue = LMath.trim(self.lineList[0]);
    	self.lineList.shift();
    }

        上面代码用来获得一个lineList数组中的脚本指令

    if(lineValue.length == 0){
    	self.analysis();
    	return;
    }

        如果当前脚本指令为空,则执行下一条指令

    trace("analysis lineValue = " + lineValue);

        这行代码用来debug,发布的时候可以不要

    var sarr = lineValue.split(".");
    switch(sarr[0]){
    	default:
    		self.analysis();
    }

        在L#中,全部被执行的脚本指令,都是[类.命令]的格式,如果你在设定脚本的时候应用了其他格式,则请根据你的格式来做响应的处理。所以应用split函数,对每一条指令进行分割,获得须要的信息,进行剖析。

        接着,我们在Main.js中参加以下代码

    init(50,"mylegend",400,100,main);
    function main(){
    	LGlobal.setDebug(true);
    	var sc = "aaa;Load.script(script/Main.ls);bbb;";
    	var sp = new LSprite();
    	addChild(sp);
    	var script = new LScript(sp,sc);
    }

        那么脚本剖析类会对["aaa;Load.script(script/Main.ls);bbb;"]这个脚本进行剖析,里面的脚本指令是我随便写的,并非准确的指令。

        运行一下代码,

        你当地的执行URL为http://localhost/lsharp/index.html

        


        看看debug函数会输出的信息,如下

     脚本和指令

        图1

        可以看到,剖析类对脚本进行了剖析,按照分号将脚本分割为了三个指令,那么接下来就须要增加对每一条指令的剖析,当涌现了无法剖析的指令的时候,会自动跳过对下一个指令进行剖析。

        下面,先来进行第一个脚本指令的剖析,应用这个脚原来读取一个脚本文件。

        首先,我规定,在L#中读取一个脚本文件的语法如下

    Load.script(script/Main.ls);

        并且在script文件夹中新建一个Main.ls文件,用记事本打开Main.ls文件写入以下内容

    Text.label(-,txt,测试a,0,0,30,#000000);
    Text.label(-,txt,测试b,0,0,30,#000000);

        接着,修改剖析函数中的switch部份,如下

    switch(sarr[0]){
    	case "Load":
    		ScriptLoad.analysis(lineValue);
    		break;
    	default:
    		self.analysis();
    }

        所以,现在须要一个静态类ScriptLoad,来对Load指令进行剖析,新建一个ScriptLoad类,如下

        每日一道理
    人生是洁白的画纸,我们每个人就是手握各色笔的画师;人生也是一条看不到尽头的长路,我们每个人则是人生道路的远足者;人生还像是一块神奇的土地,我们每个人则是手握农具的耕耘者;但人生更像一本难懂的书,我们每个人则是孜孜不倦的读书郎。
    /*
    * ScriptLoad.js
    **/
    var ScriptLoad = function (){};
    ScriptLoad.data = "";
    ScriptLoad.urlloader = null;
    ScriptLoad.analysis = function (value){
    	var start = value.indexOf("(");
    	var end = value.indexOf(")");
    	ScriptLoad.data = value.substring(start+1,end).split(",");
    	switch(LMath.trim(value.substr(0,start))){
    		case "Load.script":
    			ScriptLoad.loadScript();
    			break;
    		default:
    			LGlobal.script.analysis();
    	}
    };

        ScriptLoad类的剖析函数analysis中,首先将脚本中括号外和括号内的内容[Load.script]和[script/Main.ls]分解出来,然后再利用switch函数进一步剖析。当遇到字符串“Load.script”的时候,调用loadScript函数来读取一个脚本文件。

        看下面的代码

    ScriptLoad.loadScript = function (){
    	ScriptLoad.urlloader = new LURLLoader();
    	ScriptLoad.urlloader.addEventListener(LEvent.COMPLETE,ScriptLoad.loadScriptOver);
    	ScriptLoad.urlloader.load(ScriptLoad.data[0],"text");
    };
    ScriptLoad.loadScriptOver = function (event){
    	var script = LGlobal.script;
    	var data = event.target.data;
    	ScriptLoad.urlloader.die();
    	ScriptLoad.urlloader = null;
    	script.saveList();
    	script.dataList.unshift([data]);
    	script.toList(data);
    };

        代码剖析

        loadScript函数比较简单,就是应用LURLLoader对象来读取一个文件,读取完以后调用loadScriptOver函数。

        loadScriptOver函数中利用下面三行代码,将读取进来的内容存入脚本剖析类的数组中,进行下一步剖析。

    script.saveList();
    script.dataList.unshift([data]);
    script.toList(data);

        其中的saveList函数如下

    saveList:function(){
    	var self = this;
    	var arr=self.dataList[0];
    	if(arr){
    		arr[1]=self.lineList;
    		arr[2]=self.copyList;
    	}
    }

        所做的处理就是前面所说的,将当前正在执行的脚本数组保存起来

        运行代码,debug输出以下信息

     脚本和指令

        图2

        可以看到,Main.ls脚本文件中的脚本指令都被剖析了出来,只是Text.label这个脚本我们还没有对其进行剖析,所以只是将其跳过了。

        其实,我们还可以在脚本文件中再读取脚本文件,比如将Main.ls中的内容换成下面:

    Text.label(-,txt,测试a,0,0,30,#000000);
    Load.script(script/test.ls);
    Text.label(-,txt,测试b,0,0,30,#000000);

        并且,再添加一个test.ls脚本文件,test.ls中的内容如下

    Text.label(-,txt,测试c,0,0,30,#000000);

        运行一下程序,看debug输出如下信息:

     脚本和指令

        图3

        可以看到,test.ls中的脚本指令也被读取出来了。

        测试连接

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

        

    关于源码

        

    现在代码比较少,我就直接贴出来了

        

    Main.js
    init(50,"mylegend",400,100,main);
    function main(){
    	LGlobal.setDebug(true);
    	var sc = "Load.script(script/Main.ls);";
    	var sp = new LSprite();
    	addChild(sp);
    	var script = new LScript(sp,sc);
    }
    lufylegend.lsharp.js
    /*
    * LScript.js
    **/
    function LScript(scriptLayer,value){
    	var self = this;
    	LGlobal.script = self;
    	self.scriptLayer = scriptLayer;
    	self.dataList = new Array();
    	var arr=[value];
    	self.dataList.unshift(arr);
    	self.toList(value);
    }
    LScript.prototype = {
    	toList:function(ltxt){
    		var self = this;
    		self.lineList = ltxt.split(";");
    		self.copyList = self.lineList.slice(0);
    		self.analysis();
    	},
    	saveList:function(){
    		var self = this;
    		var arr=self.dataList[0];
    		if(arr){
    			arr[1]=self.lineList;
    			arr[2]=self.copyList;
    		}
    	},
    	analysis:function(){
    		var self = this;
    		var arr;
    		if(self.lineList.length == 0){
    			self.dataList.shift();
    			if(self.dataList.length > 0){
    				arr=self.dataList[0];
    				self.lineList = arr[1];
    				self.copyList = arr[2];
    				self.analysis();
    			}
    			return;
    		}
    		var lineValue = "";
    		while(self.lineList.length > 0 && lineValue.length == 0){
    			lineValue = LMath.trim(self.lineList[0]);
    			self.lineList.shift();
    		}
    		if(lineValue.length == 0){
    			self.analysis();
    			return;
    		}
    		trace("analysis lineValue = " + lineValue);
    		var sarr = lineValue.split(".");
    		switch(sarr[0]){
    			case "Load":
    				ScriptLoad.analysis(lineValue);
    				break;
    			default:
    				self.analysis();
    		}
    	}
    };
    /*
    * ScriptLoad.js
    **/
    var ScriptLoad = function (){};
    ScriptLoad.data = "";
    ScriptLoad.urlloader = null;
    ScriptLoad.analysis = function (value){
    	var start = value.indexOf("(");
    	var end = value.indexOf(")");
    	ScriptLoad.data = value.substring(start+1,end).split(",");
    	switch(LMath.trim(value.substr(0,start))){
    		case "Load.script":
    			ScriptLoad.loadScript();
    			break;
    		default:
    			LGlobal.script.analysis();
    	}
    };
    ScriptLoad.loadScript = function (){
    	ScriptLoad.urlloader = new LURLLoader();
    	ScriptLoad.urlloader.addEventListener(LEvent.COMPLETE,ScriptLoad.loadScriptOver);
    	ScriptLoad.urlloader.load(ScriptLoad.data[0],"text");
    };
    ScriptLoad.loadScriptOver = function (event){
    	var script = LGlobal.script;
    	var data = event.target.data;
    	ScriptLoad.urlloader.die();
    	ScriptLoad.urlloader = null;
    	script.saveList();
    	script.dataList.unshift([data]);
    	script.toList(data);
    };




    本章就讲到这里,下一章我们真正的进入正题,一起来hello world!

        

        

    欢送大家介入

        

        


    文章结束给大家分享下程序员的一些笑话语录: 面试官:熟悉哪种语言
    应聘者:JAVA
    面试官:知道什么叫类么
    应聘者:我这人实在,工作努力,不知道什么叫累
    面试官:知道什么是包?
    应聘者:我这人实在 平常不带包 也不用公司准备了
    面试官:知道什么是接口吗?
    应聘者:我这个人工作认真。从来不找借口偷懒
    面试官:知道什么是继承么
    应聘者:我是孤儿没什么可以继承的
    面试官:知道什么叫对象么?
    应聘者:知道,不过我工作努力,上进心强,暂时还没有打算找对象。
    面试官:知道多态么?
    应聘者:知道,我很保守的。我认为让心爱的女人为了自已一时的快乐去堕胎是不道德的行为!请问这和C#有什么关系??

  • 相关阅读:
    下载安装ngnix
    微信小程序富文本中的图片大小超出屏幕
    微信小程序跳转(当我们不知道是普通页面还是tabbar)
    查看每年用量最多技术框架
    vue.js--遇到的一些错误
    vue-router(配置子路由--单页面多路由区域操作)
    webpack配置文件--(loader)
    webpack配置(入口出口)
    数组排序
    2021年12种高级UX/UI设计趋势
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3076725.html
Copyright © 2011-2022 走看看