《游戏脚本的设计与开发》-(RPG部分)3.3 加入多个人物以及对话实现

上一节中 给地图加入了遮挡功能,尝试着加入了一个可以控制的测试人物,并且实现了人物行走时的各个动作变换的控制。本节中接下来要做的事情就是把之前的工作全部脚本化,并且使用游戏脚本加入多个人物角色,最后通过点击地图上的人物,来实现游戏中的对话功能。文章中贴出的只是部分主要的代码,你在看的时候,有些代码可能会不理解,这个不要紧,最后我会放出完整源码的下载。

首先,使用之前已经开发好的脚本来给游戏添加一个logo页面。

Main.ls

//添加显示层back
Layer.add(-,back,0,0);
Layer.drawRectLine(back,0,0,800,480,#000000);
//显示文字,读取中
Text.label(-,loading,图片读取中...,300,200,15,#000000);
//读取图片
Load.img(logobtnover,./images/logo/logobtnover.png);
Load.img(logobtnup,./images/logo/logobtnup.png);
Load.img(logo,./images/logo/logo.jpg);
//删除文字,读取中
Text.remove(loading);
Img.add(back,logo01,logo,0,0,800,480,1);
//显示游戏名称
Text.label(back,logo,RPG脚本测试,470,50,40,#000000);
//在back层上添加一个按钮,作为选项
Button.add(back,btn01,游戏开始,500,150,logobtnup,logobtnover,logobtnover,#ffffff);
function btn01click();
	Button.remove(btn01);
	Text.label(-,loading,脚本读取中...,300,200,20,#ffffff);
	Load.script(script/R01.ls);
endfunction;
//为按钮添加点击事件
Button.mousedown(btn01,btn01click);
使用脚本添加图片,按钮,函数等功能,在 第一章 基本功能里都已经详细介绍过了,不了解的朋友可以看一下第一章的内容,上面的脚本效果如下图。

点击[游戏开始]按钮后,进入脚本R01.ls,先来预设一下本地要实现的所有功能所需要的脚本内容,一会儿我来一点点儿的实现它。

R01.ls

//清除画面
Layer.clear(-);
//RPG地图设定开始
RPGMap.start();
//RPG地图初始化开始
initialization.start;
//地图数据设定,包括地形和图片等
addMap(r01.rmap);
//加入人物角色,参数以此为 人物index,动作action,方向direction,坐标x,坐标y,是否可控ishero
RPGCharacter.add(1,stand,right,20,9,true);
RPGCharacter.add(2,stand,down,22,13,false);
RPGCharacter.add(3,stand,down,55,15,false);
RPGCharacter.add(4,stand,up,35,40,false);
RPGCharacter.add(5,stand,left,35,7,false);
//RPG地图初始化结束
initialization.end;
//RPG地图中各函数初始化开始
function.start;
//函数名称为“characterclick”+人物序号的函数,功能是当点击到某人物的时候,会调用相应的函数
function characterclick2();
	RPGTalk.set(2,0,你知道lufy吗,听说那家伙除了做游戏,啥都不会。);
	RPGTalk.set(1,0,怪不得啊,哈哈哈。);
endfunction;
function characterclick3();
	RPGTalk.set(3,0,。。。。。。);
	RPGTalk.set(1,0,少年,你能帮我捡肥皂吗?);
endfunction;
function characterclick4();
	RPGTalk.set(4,0,请不要跟我说话,我只是过来打酱油的。);
	RPGTalk.set(1,0,不跟我说话是因为看不起我吗?);
endfunction;
function characterclick5();
	RPGTalk.set(5,0,你现在进入的是由lufylegend.js制作的一个虚幻的游戏脚本世界。目前正在执行是对话脚本。);
endfunction;
//RPG地图中各函数初始化结束
function.end;
//RPG地图设定结束
RPGMap.end();

以上的脚本,已经足够满足接下来要完成的工作了,实现的效果为


下面一个一个的来看,这些脚本如何来实现。

1,进入地图脚本

//RPG地图设定开始
RPGMap.start();
//RPG地图设定结束
RPGMap.end();
包括第二章的战旗部分,前面已经介绍了多种脚本,RPG脚本当然要与其他脚本区分开,所以RPG部分的脚本我会全部以RPG开头,上面这两个脚本,分别会进入和退出RPG部分的地图脚本。

RPG脚本部分有区别于其他部分脚本,当然有自己的一个脚本解析函数,如下

/*
* LScriptRPG.js
**/
var LScriptRPG = function (){};
LScriptRPG.analysis = function (childType, lineValue){
	var start,end,params;
	start = lineValue.indexOf("(");
	end = lineValue.indexOf(")");
	switch(childType){
		case "RPGMap":
			LGlobal.script.scriptLayer.controller.mapLoad();
			break;
		case "RPGTalk":
			LRPGTalkScript.analysis(lineValue);
			break;
		default:
			LGlobal.script.analysis();
	}
};

修改LScript.analysis脚本解析函数中的switch部分,可以很容易的进入到上面RPG脚本解析函数里,稍后大家可以看一下源码,上面的RPG脚本解析函数里,遇到RPGMap脚本,会调用LGlobal.script.scriptLayer.controller.mapLoad(),我已经提前在IndexController中把LGlobal.script.scriptLayer设定成了程序中的IndexView,所以这里其实是调用了IndexController的mapLoad函数,

IndexController.prototype.mapLoad=function(){
	var self = this;
	self.loadMvc("Map",self.mapComplete);
};

当Map的相关的文件读取完成之后,会自动调用LRPGMapScript.analysis();进行下一个脚本的解析。

2,地图的初始化

//RPG地图初始化开始
initialization.start;
//RPG地图初始化结束
initialization.end;
地图的初始化,包括地图图片和地形的设定,人物角色的添加等等,看一下RPG地图脚本的解析函数

/*
* LRPGMapScript.js
**/
LRPGMapScript = function(){};
LRPGMapScript.analysis=function(){
	var script = LGlobal.script;
	if(script.lineList.length == 0)return;
	var lineValue = LMath.trim(script.lineList.shift());
	if(lineValue.length == 0){
		LRPGMapScript.analysis();
		return;
	}
	trace("LRPGMapScript analysis lineValue = " + lineValue);
	switch(lineValue){
		case "RPGMap.end()":
			setTimeout(function(){
				LRPGObject.RPGMap.initOver=true;
				LGlobal.script.analysis();
			},100);
			return;
		case "initialization.start":
			LRPGMapScript.initialization();
			break;
		case "function.start":
			LRPGMapScript.addFunction();
			break;
		default:
			LRPGMapScript.analysis();
	}
};
当遇到脚本initialization.start的时候,会调用LRPGMapScript.initialization();函数来进行地图初始化。
LRPGMapScript.initialization=function(){
	var script = LGlobal.script;
	var lineValue = LMath.trim(script.lineList.shift());
	trace("LRPGMapScript initialization lineList = " + lineValue);
	if(lineValue.length == 0){
		LRPGMapScript.initialization();
		return;
	}
	if(lineValue == "initialization.end"){
		LRPGMapScript.analysis();
		return;
	}
	var params,i;
	var start = lineValue.indexOf("(");
	var end = lineValue.indexOf(")");
	switch(lineValue.substr(0,start)){
		case "addMap":
			params = lineValue.substring(start+1,end).split(",");
			LRPGObject.RPGMap.addMap.apply(LRPGObject.RPGMap,params);
			break;
		case "RPGCharacter.add":
			params = lineValue.substring(start+1,end).split(",");
			LRPGObject.RPGMap.addCharacter.apply(LRPGObject.RPGMap,params);
			break;
		default:
			LRPGMapScript.initialization();
	}
};
可以看到,LRPGMapScript.initialization();函数进行地图的初始化工作,目前里面包括addMap地图数据添加,RPGCharacter.add人物角色添加等功能。
3,地图数据添加

//地图数据设定,包括地形和图片等
addMap(r01.rmap);
r01.rmap文件中的内容就是前面所介绍过的地图数据,如下

{
"width":1280
,"height":960
,"data":[
			[1,1,1,......]
			,[0,0,0,......]
			......
		]
		,"pieceWidth":1280
		,"pieceHeight":960
		,"imgs":[
			[{"img":"map-1","rect":[0,0],"path":"map-1.png"}]
		]
		,"builds":[
			[{"img":"build-1","rect":[0,0],"path":"build-1.png"}]
		]
	}
解析函数遇到addMap脚本之后,读取相应的地图数据文件,然后进行地图的相关的设定。
4,人物角色的添加
//加入人物角色,参数以此为 人物index,动作action,方向direction,坐标x,坐标y,是否可控ishero
RPGCharacter.add(1,stand,right,20,9,true);
RPGCharacter.add(2,stand,down,22,13,false);

上一节中我为了测试,临时加入了一个可以控制的人物,上面脚本RPGCharacter.add用来添加一个人物角色,我只需要解析这个脚本,然后把相应的参数分离出来,和上一节用同样的方法,就可以加入一个人物了,当然地图上可以控制行走的人物通常只有一个(或者说是一组,因为有些游戏中是控制一个队伍的行走,如fc版《吞食天地》),所以在加入人物角色的时候,要设定这些人物哪些是可以控制的,哪些是不可以控制的。

5,函数的添加

//RPG地图中各函数初始化开始
function.start;
//函数名称为“characterclick”+人物序号的函数,功能是当点击到某人物的时候,会调用相应的函数
function characterclick2();
	RPGTalk.set(2,0,你知道lufy吗,听说那家伙除了做游戏,啥都不会。);
	RPGTalk.set(1,0,怪不得啊,哈哈哈。);
endfunction;
//RPG地图中各函数初始化结束
function.end;
之前也已经介绍了,如何用脚本来实现一个函数的添加和调用,但是函数的解析需要在LScript.analysis脚本解析函数中进行,而现在脚本解析已经进入到了RPG部分的解析,所以这里我加入了function.start;和function.end;来做一下特殊的处理,调用原来的ScriptFunction脚本,来解析里面的函数脚本。
6,对话脚本

RPGTalk.set(1,0,少年,你能帮我捡肥皂吗?);
对话的显示,要分两部分,一个是人物头像的显示,一个是对话内容的显示。

头像的显示,我用下面的类来实现。

function Face(index,subindex){
	var self = this;
	base(self,LSprite,[]);
	loader = new LLoader();
	loader.parent = self;
	loader.addEventListener(LEvent.COMPLETE,self.loadOver);
	loader.load(LMvc.IMG_PATH+"face/"+index+"-"+subindex+".png","bitmapData");
}
Face.prototype.loadOver = function(event){
	var self = event.target.parent;
	var bitmapData = new LBitmapData(event.currentTarget);
	var bitmap = new LBitmap(bitmapData);
	self.addChild(bitmap);
};
index是人物的头像序号,subindex是人物的表情,因为在游戏里一个人物,通常有多种表情,所以,我们要为每个人物准备多个头像,并且能分别调用它们。
接着,先准备一张背景图,


然后,将人物的名字和对话的名称显示到相应的位置上就可以了,下面是Talk的所有代码。

function Talk(){
	if(arguments.length == 6){
		TalkRun.apply(this,arguments);
	}else if(arguments.length == 4){
		TalkRun.call(this,LMvc.layer,150,arguments[0],arguments[1],arguments[2],arguments[3]);
	}else{
		TalkRun.call(this,arguments[0],150,arguments[1],arguments[2],arguments[3],arguments[4]);
	}
}
function TalkRun(layer,y,index,faceindex,msg,callback){
	if(LGlobal.talkLayer && LGlobal.talkLayer.parent){
		LGlobal.talkLayer.parent.removeChild(LGlobal.talkLayer);
	}
	var talkLayer = new LSprite();
	talkLayer.y = y;
	talkLayer.x = 50;
	var charaLayer = new Face(LMvc.datalist["chara"]["peo"+index]["Face"],faceindex);
	charaLayer.x = 200;
	talkLayer.addChild(charaLayer);
	
	var back = new LBitmap(new LBitmapData(LMvc.datalist["talkbox"]));
	back.y = 130;
	back.alpha = 0.7;
	talkLayer.addChild(back);
	var nameText = new LTextField();
	nameText.size = 18;
	nameText.color = "#FFFFFF";
	nameText.text = LMvc.datalist["chara"]["peo"+index]["Name"];
	nameText.x = 30+(90 - nameText.getWidth())*0.5;
	nameText.y = back.y + 22;
	talkLayer.addChild(nameText);
	
	var msgText = new LTextField();
	msgText.x = 25;
	msgText.y = 225;
	msgText.text = msg;
	msgText.size = 12;
	msgText.color = "#FFFFFF";
	msgText.width = 430;
	msgText.setWordWrap(true,23);
	msgText.wind(callback);
	talkLayer.addChild(msgText);
	layer.addChild(talkLayer);
	LRPGObject.talkOver = false;
	LRPGObject.talkLayer = talkLayer;
}
function TalkRemove(){
	LRPGObject.talkLayer.remove();
	LRPGObject.talkOver = false;
	LRPGObject.talkLayer = null;
	LGlobal.script.analysis();
}


OK,是不是已经迫不及待的想要看到效果了?测试连接如下:

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

预览效果:

最后,给出本次的代码下载:

https://github.com/lufylegend/lsharp/archive/3.3.zip

※源码运行说明:

1,需要服务器支持,详细请看本系列文章《序》和《第一章》

2,源码中不含lufylegend.js引擎代码,请自己到官方下载引擎


预告:

现在地图上的NPC人物都是静止不动的,在实际的游戏中有些NPC会随即的走动,使得游戏效果更为生动,

另外大家都知道,RPG游戏中有一个重要的功能,就是任务系统,玩家完成某一项人物会得到什么奖励,然后接着出现一个新的任务等等,

后面我接着来给大家介绍地图的切换效果,NPC人物的随即走动,以及地图脚本中的任务系统,请期待下次更新。

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

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

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

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

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值