html5游戏开发-零基础开发RPG游戏-开源讲座(四)-游戏脚本化&地图跳转

原创 2012年01月22日 03:50:00

首先,本篇文章是零基础开发RPG游戏-开源讲座系列文章的第四篇,来实现游戏的脚本化,和利用游戏脚本实现地图场景的切换,离上次更新貌似很长时间了,你在看下面的文字之前,需要先了解前三篇在下啰嗦了些什么东东。

html5游戏开发-零基础开发RPG游戏-开源讲座(一)
http://blog.csdn.net/lufy_legend/article/details/7063316
html5游戏开发-零基础开发RPG游戏-开源讲座(二)-跑起来吧英雄
http://blog.csdn.net/lufy_legend/article/details/7076064
html5游戏开发-零基础开发RPG游戏-开源讲座(三)-卷轴&对话实现
http://blog.csdn.net/lufy_legend/article/details/7094567


一,什么是游戏脚本

简单说,游戏脚本就是依据一定的格式编写的可执行文件,游戏可以通过脚本中自定义的语句来执行相应的逻辑。

二,为什么要将游戏脚本化

游戏脚本,可以令我们的游戏动态化,比如当我们开发了一款rpg游戏,里面的剧情,事件以及地图等,我们如果将这些全部写进程序里,当然是可以的,但是一旦出现问题,哪怕几个错别字,我们需要先将这几个错别字改正,并且将整个程序重新编译发布一遍,这个过程是相当令人反感的,因为如果游戏的程序跟着游戏的内容不断进行修改的话,那只会使你的程序越来越复杂。但是如果我们将这些可重复的数据,都定义到游戏程序之外的文件里面,当游戏引擎开发完毕,我们的游戏通过读取这些外部文件,来执行相应的剧情和事件,那么,像上述当我们的游戏出现了问题,我们只需要改动这些外部文件就可以了,并不需要重新编译整个程序,这样便使得我们的游戏开发,变得便利简洁。

*当然,对于html5来说,不需要重新编译程序,但是对于rpg的游戏来说,脚本还是必不可少的,因为游戏的剧本不可能全都写到程序里...

三,如何来实现游戏的脚本化

好了,接下来,先来考虑以什么形式来制作游戏的脚本,我们有多种选择,可以选择xml,可以选择json,也可以选择纯自定义语法,

如鄙人开发的flash游戏脚本L#http://blog.csdn.net/lufy_legend/article/details/6889424

这次,我为了省事,选用比较方便处理的json,因为javascript可以很轻松的处理json数据。
目前游戏中实现的内容有,地图场景添加,游戏人物添加,以及人物对话的实现。那么,我在设计游戏脚本的时候,必须包含这些数据,然后才能将这三项功能用脚本来控制。
首先看下面的json

var script = {
	stage01:{
		map:[
		    [18,18,18,18,18,18,18,18,18,18,18,18,55,55,18,18,18],
			[18,18,18,17,17,17,17,17,17,17,17,17,55,55,17,17,18],
			[18,18,17,17,17,17,18,18,17,17,17,17,55,55,17,17,18],
			[18,17,17,17,18,18,18,18,18,17,17,55,55,17,17,17,18],
			[18,17,17,18,22,23,23,23,24,18,17,55,55,17,17,17,18],
			[18,17,17,18,25,28,26,79,27,18,55,55,17,17,17,17,18],
			[18,17,17,17,17,10,11,12,18,18,55,55,17,17,17,17,18],
			[18,18,17,17,10,16,16,16,11,55,55,17,17,17,17,17,18],
			[18,18,17,17,77,16,16,16,16,21,21,17,17,17,17,17,18],
			[18,18,17,17,77,16,16,16,16,55,55,17,17,17,17,17,18],
			[18,18,18,18,18,18,18,18,18,55,55,18,18,18,18,18,18]],
		mapdata:[
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1],
			[1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1],
			[1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1],
			[1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1],
			[1,0,0,1,1,1,0,1,1,1,1,1,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],
		add:[
		     {chara:"player",img:"mingren",x:5,y:6},
		     {chara:"npc",img:"npc1",x:7,y:6},
		     {chara:"npc",img:"npc1",x:3,y:3}],
		talk:{
			talk1:[
		    		  {img:"m",name:"鸣人",msg:"我是木叶村的鸣人,你是谁?"},
		    		  {img:"n",name:"黑衣忍者甲",msg:"你就是鸣人?九尾还在你身体里吗?"}
		    	  ],
		    talk2:[
		    	      {img:"n",name:"黑衣忍者乙",msg:"鸣人,听说忍者大战就要开始了。"},
		    		  {img:"m",name:"鸣人",msg:"真的吗?一定要想想办法啊。"}
		    	  ]
		}
	}


};


我将脚本定义成了变量,实际游戏制作的时候,脚本应该储存到一个外部文档当中,在这里我只是讲解一下理论,如何完善那是后话了,哈。
可以看到,json中,包含了地图相关的map数组和mapdata数组,添加人物的相关数据,以及对话的数组。这样,我在游戏显示的时候,只需要读入json数据,然后根据这些内容来显示游戏画面就可以了,定义一个initScript函数来进行这些操作。
function initScript(){
	//地图位置初始化
	mapLayer.x = 0;
	mapLayer.y = 0;


	//地图层初始化
	mapLayer.removeAllChild();
	//人物层初始化
	charaLayer.removeAllChild();
	//效果层初始化
	effectLayer.removeAllChild();
	//对话层初始化
	talkLayer.removeAllChild();
	
	//地图数据获取
	map = stage.map;
	mapdata = stage.mapdata;
	//对话数据获取
	talkScriptList = stage.talk;
	
	//添加地图
	addMap(0,0);
	delMap();
	//添加人物
	addChara();
}
removeAllChild方法是lufylegend引擎独有的方法,可以用来移出LScript显示层上的所有子对象,从而实现本游戏中各个显示层的初始化工作。
修改一下addChara方法,如下
//添加人物
function addChara(){
	var charaList = stage.add;
	var chara,charaObj;
	for(var i=0;i<charaList.length;i++){
		charaObj = charaList[i];
		if(charaObj.chara == "player"){
			//加入英雄
			bitmapdata = new LBitmapData(imglist[charaObj.img]);
			chara = new Character(true,i,bitmapdata,4,4);
			player = chara;
		}else{
			//加入npc
			bitmapdata = new LBitmapData(imglist[charaObj.img]);
			chara = new Character(false,i,bitmapdata,4,4);
		}
		chara.x = charaObj.x * 32;
		chara.y = charaObj.y * 32;
		charaLayer.addChild(chara);
	}
}
即,根据json脚本中的add数组,来添加游戏中的人物。


好了,运行一下游戏,可以看到,游戏正常显示了,和之前一模一样,实现了同样的功能。


四,利用游戏脚本实现地图的切换

为了让大家看到游戏脚本的便利性,现在利用脚本实现游戏中的场景切换。
将json脚本修改如下
var script = {
	stage01:{
		map:[
		    [18,18,18,18,18,18,18,18,18,18,18,18,55,55,18,18,18],
			[18,18,18,17,17,17,17,17,17,17,17,17,55,55,17,17,18],
			[18,18,17,17,17,17,18,18,17,17,17,17,55,55,17,17,18],
			[18,17,17,17,18,18,18,18,18,17,17,55,55,17,17,17,18],
			[18,17,17,18,22,23,23,23,24,18,17,55,55,17,17,17,18],
			[18,17,17,18,25,28,26,79,27,18,55,55,17,17,17,17,18],
			[18,17,17,17,17,10,11,12,18,18,55,55,17,17,17,17,18],
			[18,18,17,17,10,16,16,16,11,55,55,17,17,17,17,17,18],
			[18,18,17,17,77,16,16,16,16,21,21,17,17,17,17,17,18],
			[18,18,17,17,77,16,16,16,16,55,55,17,17,17,17,17,18],
			[18,18,18,18,18,18,18,18,18,55,55,18,18,18,18,18,18]],
		mapdata:[
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1],
			[1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1],
			[1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1],
			[1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1],
			[1,0,0,1,1,1,0,1,1,1,1,1,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],
		add:[
		     {chara:"player",img:"mingren",x:5,y:6},
		     {chara:"npc",img:"npc1",x:7,y:6},
		     {chara:"npc",img:"npc1",x:3,y:3}],
		talk:{
			talk1:[
		    		  {img:"m",name:"鸣人",msg:"我是木叶村的鸣人,你是谁?"},
		    		  {img:"n",name:"黑衣忍者甲",msg:"你就是鸣人?九尾还在你身体里吗?"}
		    	  ],
		    talk2:[
		    	      {img:"n",name:"黑衣忍者乙",msg:"鸣人,听说忍者大战就要开始了。"},
		    		  {img:"m",name:"鸣人",msg:"真的吗?一定要想想办法啊。"}
		    	  ]
		},
		jump:[
		      {at:{x:6,y:5},to:"stage02"}
		]
	},
	stage02:{
		map:[
		    [0,0,1,2,2,2,2,2,2,2,2,1,0,0,0],
		    [0,0,1,3,5,5,1,5,5,5,5,1,0,0,0],
		    [0,0,1,80,4,4,1,80,4,4,4,1,0,0,0],
		    [0,0,1,80,4,4,1,80,8,7,8,1,0,0,0],
			[0,0,1,80,4,4,5,81,4,4,4,1,0,0,0],
			[0,0,1,2,2,2,6,4,4,4,4,1,0,0,0],
			[0,0,1,3,5,5,81,4,4,4,4,1,0,0,0],
			[0,0,1,80,4,4,4,4,4,4,9,1,0,0,0],
			[0,0,1,2,2,2,2,6,2,2,2,1,0,0,0]],
		mapdata:[
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,1,0,0,0,1,0,0,0,0,1,1,1,1],
			[1,1,1,0,0,0,1,0,0,0,0,1,1,1,1],
			[1,1,1,0,0,0,1,0,0,1,0,1,1,1,1],
			[1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
			[1,1,1,1,1,1,0,0,0,0,0,1,1,1,1],
			[1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
			[1,1,1,0,0,0,0,0,0,0,1,1,1,1,1],
			[1,1,1,1,1,1,1,0,1,1,1,1,1,1,1]],
		add:[
		     {chara:"player",img:"mingren",x:7,y:8},
		     {chara:"npc",img:"npc1",x:8,y:3},
		     {chara:"npc",img:"npc1",x:10,y:3}],
		talk:{
		      talk1:[
		    	        {img:"m",name:"鸣人",msg:"你们在干什么啊?"},
			    		{img:"n",name:"黑衣忍者甲",msg:"我们在喝茶。"}
		    	  ],
		      talk2:[
			    	    {img:"n",name:"黑衣忍者乙",msg:"我们在喝茶,你不要打扰我们。"},
			    		{img:"m",name:"鸣人",msg:"....."}
		    	  ]
		},
		jump:[
		      {at:{x:7,y:8},to:"stage01"}
		]
	}


};


可以看到,我添加了stage02,即第二个场景,并且在脚本里引入了jump节点来控制游戏场景的切换,其中jump中的at表示游戏主人公移动到达的坐标,to表示到达这个坐标后跳转到的画面名称。这里的jump之所以是数组,是因为一个场景也可以跳转到其他多个场景。
上面的脚本实现了stage01和stage02两个场景的互相跳转。
为了读取这个jump,以及实现跳转,我们需要在游戏主人公移动一个步长之后,判断一下是否应该跳转了,修改Character类的onmove方法
/**
 * 开始移动 
 **/
Character.prototype.onmove = function (){
	var self = this;
	//设定一个移动步长中的移动次数
	var ml_cnt = 4;
	//计算一次移动的长度
	var ml = STEP/ml_cnt;
	//根据移动方向,开始移动
	switch (self.direction){
		case UP:
			if(mapmove){
				mapLayer.y += ml;
				charaLayer.y += ml;
			}
			self.y -= ml;
			break;
		case LEFT:
			if(mapmove){
				mapLayer.x += ml;
				charaLayer.x += ml;
			}
			self.x -= ml;
			break;
		case RIGHT:
			if(mapmove){
				mapLayer.x -= ml;
				charaLayer.x -= ml;
			}
			self.x += ml;
			break;
		case DOWN:
			if(mapmove){
				mapLayer.y -= ml;
				charaLayer.y -= ml;
			}
			self.y += ml;
			break;
	}
	self.moveIndex++;
	//当移动次数等于设定的次数,开始判断是否继续移动
	if(self.moveIndex >= ml_cnt){
		//一个地图步长移动完成后,判断地图是否跳转
		if(self.isHero && self.moveIndex > 0)checkJump();
		self.moveIndex = 0;
		//一个地图步长移动完成后,如果地图处于滚动状态,则移除多余地图块
		if(mapmove)delMap();
		//如果已经松开移动键,或者前方为障碍物,则停止移动,否则继续移动
		if(!isKeyDown || !self.checkRoad()){
			self.move = false;
			return;
		}else if(self.direction != self.direction_next){
			self.direction = self.direction_next;
			self.anime.setAction(self.direction);
		}
		//地图是否滚动
		self.checkMap(self.direction);
	}
};
我添加了一行
if(self.isHero && self.moveIndex > 0)checkJump();
表示,移动完后如果该人物是游戏主人公则进行跳转判断
所以,我们需要添加一个checkJump方法
//游戏场景跳转测试
function checkJump(){
	var jump = stage.jump;
	var jumpstage;
	for(var i=0;i<jump.length;i++){
		jumpstage = jump[0];
		if(player.x == jumpstage.at.x * 32 && player.y == jumpstage.at.y * 32){
			//获取该场景脚本数据
			stage = script[jumpstage.to];
			//开始跳转
			initScript(stage);
			return;
		}
	}
}


好了,一切都很简单吧,运行游戏看看效果吧,小鸣人走到地图的小房门的部分是,场景发生跳转


游戏测试URL:

http://lufylegend.com/demo/rpg/index.html


lufylegend.js引擎包内包含这个demo,请直接下载lufylegend.js引擎,查看引擎包内源码

lufylegend.js引擎下载地址

http://lufylegend.com/lufylegend



零基础开发RPG游戏-开源讲座系列文章,结贴了,如有问题欢迎大家指正,也欢迎大家留言一起探讨游戏制作以及改进的方法。

人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[5]——一树双花

继续,考虑到日后扩充的需要,开始将代码模块化重构,将原有MyPanel分解成Common,GameMap,GameHandle及MyPanel等4个子模块,逐步实现Sprite操作。0-5讲源码下载地...
  • cping1982
  • cping1982
  • 2007年08月17日 11:30
  • 8115

人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[0]——月晕础润

开场诗:不儒不道又不仙,非神非圣也非贤。轻吐心头寻常语,开辟文武一片天。 自表诗:北冥沉渊有鲲鹏,吞噬金乌戮真龙。一日扶摇凌天起,三千世界可横行。       小子“...
  • w00w12l
  • w00w12l
  • 2013年06月20日 21:00
  • 1613

人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[0]——月晕础润

开场诗:不儒不道又不仙,非神非圣也非贤。轻吐心头寻常语,开辟文武一片天。 自表诗:北冥沉渊有鲲鹏,吞噬金乌戮真龙。一日扶摇凌天起,三千世界可横行。      小子“鹏凌三千”,欲将心...
  • cping1982
  • cping1982
  • 2007年06月20日 16:46
  • 14477

html5游戏开发-零基础开发RPG游戏-开源讲座(一)

因为上一篇雷电的开发中,有朋友反应不太理解,本篇将以零基础的视点,来讲解如何开发一款RPG游戏。在游戏的世界里,我们可以看到各种地图,各种游戏人物,看到人物在地图上行走,对话等,无论是地图还是人物,其...
  • lufy_Legend
  • lufy_Legend
  • 2011年12月13日 13:49
  • 41178

如何制作一款HTML5 RPG游戏引擎——第一篇,地图类的实现

一,话说天下大事 前不久看到lufy的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做。由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于luf...
  • yorhomwang
  • yorhomwang
  • 2013年05月06日 21:49
  • 22043

人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[4]——一步莲华

         从星期一开始一直郁闷……最近的状况……用迷信的说法就是犯小人,以社会学的观点是由于出现人际交往困难造成社会评价降低……无比郁闷中,继续写这个……上一回我们写到关于如何改变角色的移动样...
  • cping1982
  • cping1982
  • 2007年08月17日 09:29
  • 9161

《游戏脚本的设计与开发》-(RPG部分)3.8 通过脚本来自由控制游戏(一)

一个RPG游戏中会触发各种各样的剧情,让某个人物的动作改变,或者让某个人移动到另一处,或者让某个人物从战场上消失,或者会播放一段动画,或者会切换游戏场景,等等吧,这些都要通过脚本来动态的控制。 我在序...
  • lufy_Legend
  • lufy_Legend
  • 2014年09月02日 21:31
  • 10955

RPG游戏地图设计与实现

先占个坑,有空写文章,时间长了,忘了写什么了,国庆快到了,我是多想立即给zhugu...
  • tyxkzzf
  • tyxkzzf
  • 2014年09月28日 20:42
  • 926

《游戏脚本的设计与开发》-(RPG部分)3.1 RPG地图到底怎么做?

我之前也写过一个短篇系列《零基础开发RPG游戏开源讲座》,介绍的也比较简单,这次我会更深入也更具体的介绍一下RPG游戏的开发过程。 话说好久没有更新博客了,其实这段时间主要是工作忙,没时间。那又是什么...
  • lufy_Legend
  • lufy_Legend
  • 2013年12月19日 16:30
  • 15274

RPG游戏(一)——环境搭建、地图显示

RPG游戏是rogue类似,例如经典RPG的游戏“口袋妖怪”,我们组选择用Qt开发一个类似的游戏,作为“嵌入式linux开发”这门课的大作业。环境搭建:安装Qt、安装Tiledmap(一款地图编辑器)...
  • jupeizhong
  • jupeizhong
  • 2015年11月17日 16:55
  • 686
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:html5游戏开发-零基础开发RPG游戏-开源讲座(四)-游戏脚本化&地图跳转
举报原因:
原因补充:

(最多只允许输入30个字)