《游戏脚本的设计与开发》 第六章 按钮,脚本的暂停和标签

 按钮

按钮在任何程序中都是必不可少的,本次先来看看如何脚本来实现按钮的各种功能。文章中要实现的几个脚本如下。

/*

	游戏脚本的设计与开发 第六章

	*/

	//添加按钮

	Button.add(layer01,button01,null,50,50,ok_button_up,ok_button_over,null);

	function function_test01();

	    //移除按钮

	    Button.remove(button01);

	endfunction;

	//移除显示层

	Layer.remove(layer01);

	//给按钮添加点击事件

	Button.mousedown(button01,function_test01);


    下面是ScriptButton类的完整代码,用来实现上述脚本的解析

/*

	* ScriptButton.js

	**/

	var ScriptButton = function (){};

	ScriptButton.analysis = function (value){

	    var start = value.indexOf("(");

	    var end = value.indexOf(")");

	    switch(value.substr(0,start)){

	        case "Button.add"://添加按钮

	            ScriptButton.addButton(value,start,end);

	            break;

	        case "Button.remove"://删除按钮

	            ScriptButton.removeButton(value,start,end);

	            break;

	        case "Button.mousedown"://鼠标按下事件

	            ScriptButton.mouseevent(value,start,end,LMouseEvent.MOUSE_DOWN);

	            break;

	        case "Button.mouseup"://鼠标弹起事件

	            ScriptButton.mouseevent(value,start,end,LMouseEvent.MOUSE_UP);

	            break;

	        case "Button.mousemove"://鼠标移动事件

	            ScriptButton.mouseevent(value,start,end,LMouseEvent.MOUSE_MOVE);

	            break;

	        default:

	            LGlobal.script.analysis();

	            

	    }

	};

	/**

	添加按钮脚本解析

	Button.add(layer01,button01,null,50,50,ok_button_up,ok_button_over,null);

	*/

	ScriptButton.addButton = function (value,start,end){

	    var script = LGlobal.script;

	    var layer;

	    //获取参数

	    var lArr = value.substring(start+1,end).split(",");

	    var layerStr = lArr[0];//显示层名称

	    var nameStr = lArr[1];//按钮名称

	    var labelStr = lArr[2];//按钮上的文字,如果设置为null,则不显示文字

	    var x = parseInt(lArr[3]);//按钮坐标

	    var y = parseInt(lArr[4]);//按钮坐标

	    var dataUp = lArr[5];//按钮弹起样式的bitmapData对象名称

	    var dataOver = lArr[6];//按钮点击后样式的bitmapData对象名称

	    //获取按钮弹起和按下的样式的bitmapData对象

	    var upimg = script.scriptArray.bitmapdataList[dataUp];

	    var overimg = script.scriptArray.bitmapdataList[dataOver];

	    //按钮弹起状态LSprite

	    var upLayer = new LSprite();

	    upLayer.addChild(new LBitmap(upimg));

	    //按钮按下状态LSprite

	    var overLayer = new LSprite();

	    overLayer.addChild(new LBitmap(overimg));

	    //如果设置了按钮文字,则开始在按钮上添加一个LTextField对象来显示文字

	    if(labelStr && labelStr != "null"){

	        var upText = new LTextField();

	        upText.text = labelStr;

	        upText.size = upimg.height * 0.5;

	        upText.x = (upimg.width - upText.getWidth())*0.5;

	        upText.y = upimg.height * 0.2;

	        upLayer.addChild(upText);

	        var overText = new LTextField();

	        overText.text = labelStr;

	        overText.size = upimg.height * 0.5;

	        overText.x = (upimg.width - upText.getWidth())*0.5+2;

	        overText.y = upimg.height * 0.2+2;

	        overLayer.addChild(overText);

	        //按钮的文字颜色

	        if(lArr.length > 7){

	            upText.color = lArr[7];

	            overText.color = lArr[7];

	        }

	    }

	    //利用按钮的两个状态,新建一个LButton按钮对象

	    var btn = new LButton(upLayer,overLayer);

	    btn.x = x;

	    btn.y = y;

	    //得到显示层

	    layer = script.scriptArray.layerList[layerStr];

	    //保存按钮

	    script.scriptArray.btnList[nameStr] = btn;

	    btn.name = nameStr;

	    //将按钮添加到显示层

	    layer.addChild(btn);

	    script.analysis();

	};

	/**

	删除按钮脚本解析

	Button.remove(button01);

	*/

	ScriptButton.removeButton = function(value,start,end){

	    //获取参数

	    var lArr = value.substring(start+1,end).split(",");

	    var nameStr = lArr[0];//按钮名称

	    var script = LGlobal.script;

	    //获取按钮

	    var btn = script.scriptArray.btnList[nameStr];

	    //如果按钮不存在,则解析下一行脚本

	    if(btn == null){

	        script.scriptArray.btnList[nameStr] = null;

	        script.analysis();

	        return;

	    }

	    //移除按钮

	    btn.parent.removeChild(btn);

	    script.scriptArray.btnList[nameStr] = null;

	    script.analysis();

	};

	/**

	按钮事件脚本解析

	Button.mousedown(button01,function_test01);

	*/

	ScriptButton.mouseevent = function (value,start,end,e){

	    var script = LGlobal.script;

	    //获取参数

	    var lArr = value.substring(start+1,end).split(",");

	    var nameStr = lArr[0];//按钮名称

	    var funStr = lArr[1];//函数名称

	    //获取按钮

	    var btn = script.scriptArray.btnList[nameStr];

	    //添加匿名函数,然后匿名函数中利用Call脚本类来调用相应的函数

	    var fun = function(event){

	        ScriptFunction.analysis("Call." + funStr + "();");

	    };

	    //为按钮添加事件

	    btn.addEventListener(e,fun);

	    script.analysis();

	};


    我在上面的代码中添加了非常详细的代码,基本上不用我再多解释什么了,下面来看看这些脚本的使用,修改Main.ls如下。

Layer.add(-,layer01,100,100);

	Layer.add(-,layer02,20,50);

	Text.label(layer02,txt01,点击下面按钮,被点击按钮就会消失,0,0,30,#000000);

	Load.img(ok_button_over,ok_button_over.png);

	Load.img(ok_button_up,ok_button_up.png);

	//添加按钮

	Button.add(layer01,button01,null,50,50,ok_button_up,ok_button_over);

	Button.add(layer01,button02,测试1,150,50,ok_button_up,ok_button_over,#880000);

	Button.add(layer01,button03,测试2,250,50,ok_button_up,ok_button_over,#008800);

	//声明函数,以备按钮事件使用

	function function_test01();

	    //移除按钮

	    Button.remove(button01);

	endfunction;

	function function_test02();

	    Button.remove(button02);

	endfunction;

	function function_test03();

	    Button.remove(button03);

	endfunction;

	//给按钮添加点击事件

	Button.mousedown(button01,function_test01);

	Button.mousedown(button02,function_test02);

	Button.mousedown(button03,function_test03);


    测试连接

http://lufylegend.com/demo/test/lsharp/06/index01.html



    上面的测试中,我利用脚本添加了三个按钮,并且给这三个按钮分别添加了点击事件,点击按钮后,被点击的按钮就会被移除。


    脚本暂停

    在游戏脚本运行过程中,如果脚本没有暂停功能,不间断的进行解析,那么就完全不受控制了,脚本什么时候运行结束了,整个程序也就结束了。这显然是不符合我们的意愿的,而且在游戏中,也尝尝会遇到一种情况,就是点击鼠标后才继续进行下面程序,这就要用到脚本暂停了,就是脚本执行到某一行后暂停解析,等待用户的命令,然后才进行下一行的脚本解析。

    下面尝试定义的脚本,如下

//暂停1秒

	Wait.time(1000);

	//等待点击

	Wait.click();

	//等待运行控制脚本的执行

	Wait.ctrl();

	//结束Wait.ctrl,继续进行解析

	Wait.play();

	


    下面是完整的ScriptWait.js类,用来解析暂停脚本相关的各种操作。

/*

	* ScriptWait.js

	**/

	var ScriptWait = function (){};

	ScriptWait.analysis = function (value){

	    var start = value.indexOf("(");

	    var end = value.indexOf(")");

	    switch(value.substr(0,start)){

	        case "Wait.click"://暂停,等待点击鼠标

	            ScriptWait.waitclick();

	            break;

	        case "Wait.ctrl"://暂停,等待运行脚本

	             if(int(value.substring(start + 1,end)) > 0)LGlobal.script.lineList.unshift("Wait.ctrl()");

	            break;

	        case "Wait.play"://脚本继续运行

	            LGlobal.script.analysis();

	            break;

	        case "Wait.time"://脚本暂停一段时间

	            ScriptWait.timeId = setTimeout(function(){

	                ScriptWait.timeId = null;

	                LGlobal.script.analysis();

	            }, 1000);

	            break;

	        case "Wait.clickOver"://结束等待点击脚本(Wait.click)

	            LGlobal.script.scriptLayer.removeEventListener(LMouseEvent.MOUSE_UP,ScriptWait.clickEvent);

	            LGlobal.script.analysis();

	            break;

	        case "Wait.timeOver"://结束时间暂停脚本(Wait.time)

	            ScriptWait.timeOver();

	            break;

	        case "Wait.Over"://结束所有暂停脚本

	            LGlobal.script.scriptLayer.removeEventListener(LMouseEvent.MOUSE_UP,ScriptWait.clickEvent);

	            ScriptWait.timeOver();

	            break;

	        default:

	            LGlobal.script.analysis();

	    }

	};

	/*

	* 结束时间暂停脚本(Wait.time)

	**/

	ScriptWait.timeOver = function (){

	    if(ScriptWait.timeId){

	        clearTimeout(ScriptWait.timeId);

	        ScriptWait.timeId = null;

	    }

	    LGlobal.script.analysis();

	};

	/*

	* 暂停,等待点击鼠标

	**/

	ScriptWait.waitclick = function (){

	    var layer = LGlobal.script.scriptLayer;

	    //添加一个鼠标点击事件,当鼠标点击屏幕的时候,调用clickEvent函数,开始运行脚本

	    layer.addEventListener(LMouseEvent.MOUSE_UP,ScriptWait.clickEvent);

	};

	/*

	* 鼠标点击运行脚本

	**/

	ScriptWait.clickEvent = function (event){

	    LGlobal.script.scriptLayer.removeEventListener(LMouseEvent.MOUSE_UP,ScriptWait.clickEvent);

	    LGlobal.script.analysis();

	};


    上面的代码同样加了详细的注释,下面来测试一下这几个脚本,修改脚本文件如下

Layer.add(-,layer01,20,20);

	Text.label(layer01,txt01,暂停测试,请等待一秒钟,0,0,20,#000000);

	Wait.time(1000);

	Text.label(layer01,txt01,一秒钟结束,请点击一下屏幕,0,30,20,#000000);

	Wait.click();

	Text.label(layer01,txt01,你点击了屏幕,脚本继续,0,60,20,#000000);

	Load.img(ok_button_over,ok_button_over.png);

	Load.img(ok_button_up,ok_button_up.png);

	Button.add(layer01,button01,null,50,200,ok_button_up,ok_button_over);

	function function_test01();

	    Wait.play();

	endfunction;

	Button.mousedown(button01,function_test01);

	Text.label(layer01,txt01,脚本暂停,你可以点击OK按钮来继续解析脚本,0,90,20,#000000);

	Wait.ctrl();

	Button.remove(button01);

	Text.label(layer01,txt01,脚本结束,0,120,20,#000000);


    测试连接如下

   http://lufylegend.com/demo/test/lsharp/06/index02.html
    可以看到,上述的各种脚本,都在程序中正常运行了。

    标签

    标签功能,类似于某些程序中的go语句,就是直接跳到某个代码的位置,然后开始继续执行,下面我依然在脚本中实现以下这个功能,先来定义两个脚本,如下。

//设置标签

	Mark.drawRoundRect;

	//跳到drawRoundRect标签位置

	Mark.goto(drawRoundRect);

	


    在脚本解析的时候,遇到不认识的脚本,会自动跳过,所以设置标签的时候,不需要任何处理,直接跳过即可,下面看一下ScriptMark.js类中如何来具体实现标签的寻找。

/*

	* ScriptMark.js

	**/

	var ScriptMark = function (){};

	ScriptMark.analysis = function (value){

	    var start = value.indexOf("(");

	    var end = value.indexOf(")");

	    switch(value.substr(0,start)){

	        case "Mark.goto"://跳至标签位置

	            ScriptMark.goto(value,start,end);

	            break;

	        default:

	            LGlobal.script.analysis();

	    }

	};

	ScriptMark.goto = function (value,start,end){

	    var mark = LMath.trim(value.substring(start+1,end));

	    //copyList是当前正在解析的脚本序列的副本,再复制一个脚本序列的副本

	    var copyArray = LGlobal.script.copyList.concat();

	    var foundStr;

	    while(copyArray.length){

	        //从复制的脚本序列中开始查找标签,没查找一行,则将其删除

	        foundStr = copyArray.shift();

	        if(foundStr.indexOf("Mark."+mark) >= 0){

	            //如果找到标签,则将当前正在解析的脚本序列替换为复制序列

	            LGlobal.script.lineList = copyArray;

	            LGlobal.script.analysis();

	            return;

	        }

	    }

	    //如果没有找到标签,则什么都不做,进行下一行脚本的解析

	    LGlobal.script.analysis();

	};


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

Layer.add(-,layer01,0,0);

	//跳到标签drawTriangle

	Mark.goto(drawTriangle);

	//绘制矩形

	Layer.drawRect(layer01,0,0,100,60,0xff0000);

	Layer.drawRectLine(layer01,0,100,100,60,0xff0000,5);

	//设置drawRoundRect标签

	Mark.drawRoundRect;

	//绘制圆角矩形

	Layer.drawRoundRect(layer01,150,0,100,60,10,0x880000);

	Layer.drawRoundRectLine(layer01,150,100,100,60,10,0x880000,5);

	//跳到标签over

	Mark.goto(over);

	//设置drawTriangle标签

	Mark.drawTriangle;

	//绘制三角形

	Layer.drawTriangle(layer01,350,0,300,60,400,60,0xff0000);

	Layer.drawTriangleLine(layer01,350,100,300,160,400,160,0xff0000,5);

	//跳到标签drawRoundRect

	Mark.goto(drawRoundRect);

	//设置over标签

	Mark.over;


    解释一下上面的脚本,如果没有这些标签操作的话,脚本按照顺序执行,会绘制两个矩形,两个圆角矩形和两个三角形,但是脚本一开始就遇到了跳到标签,跳转到了drawTriangle,开始绘制三角形,绘制完三角形,又跳转到了drawRoundRect标签,开始绘制圆角矩形,绘制完圆角矩形后,又直接跳转到了over标签,从而脚本结束,所以,最初的两个矩形最终没有绘制出来。

    测试连接如下

    http://lufylegend.com/demo/test/lsharp/06/index03.html

    这个是运行效果


以上是本章的素有内容,下一章来扩展一下文字脚本,实现打字机效果文字显示,然后脚本引擎的第一部分算是讲的差不多了,会试着用这些脚本做个小游戏给大家看看。


本章为止的lufylegend.lsharp.js源码如下
http://lufylegend.com/demo/test/lsharp/06/lufylegend.lsharp.js
   

《游戏脚本的设计与开发》系列文章目录
    http://blog.csdn.net/lufy_legend/article/details/8888787

standard
For more complete information about compiler optimizations, see our Optimization Notice.