HTML 5开发RPG游戏之四(游戏脚本化)

开发 前端
先来考虑以什么形式来制作游戏的脚本,我们有多种选择,可以选择xml,可以选择json,也可以选择纯自定义语法,这次,我为了省事,选用比较方便处理的json,因为javascript可以很轻松的处理json数据。

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

一,什么是游戏脚本

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

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

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

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

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

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

这次,我为了省事,选用比较方便处理的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:"真的吗?一定要想想办法啊。"}  
                  ]  
        }  
    }  
 
 
}; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.

我将脚本定义成了变量,实际游戏制作的时候,脚本应该储存到一个外部文档当中,在这里我只是讲解一下理论,如何完善那是后话了,哈。

可以看到,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();  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

removeAllChild方法是legendForHtml5Programming引擎独有的方法,可以用来移出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);  
    }  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

即,根据json脚本中的add数组,来添加游戏中的人物。

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



 

 

#p#

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

为了让大家看到游戏脚本的便利性,现在利用脚本实现游戏中的场景切换。

将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"}  
        ]  
    }  
 
 
}; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.

可以看到,我添加了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);  
    }  
}; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

我添加了一行

if(self.isHero && self.moveIndex > 0)checkJump(); 
  • 1.

表示,移动完后如果该人物是游戏主人公则进行跳转判断

所以,我们需要添加一个checkJump方法

//游戏场景跳转测试  
function checkJump(){  
    var jump = stage.jump;  
    var jumpstage;  
    for(var i=0;i<jump.length;i++){  
        jumpjumpstage = jump[0];  
        if(player.x == jumpstage.at.x * 32 && player.y == jumpstage.at.y * 32){  
            //获取该场景脚本数据  
            stage = script[jumpstage.to];  
            //开始跳转  
            initScript(stage);  
            return;  
        }  
    }  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

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

游戏测试URL:http://fsanguo.comoj.com/html5/rpg5/index.html

本次更新源代码下载:http://fsanguo.comoj.com/html5/rpg5/rpg5.rar

原文链接:http://www.cnblogs.com/html5cn/articles/2337054.html

【编辑推荐】

  1. HTML 5开发RPG游戏之一(地图人物实现)
  2. HTML 5开发RPG游戏之二(跑起来吧英雄)
  3. HTML 5开发RPG游戏之三(卷轴和对话)
  4. 开发HTML5跨平台游戏相关经验
  5. HTML 5开发的优秀网页游戏
责任编辑:张伟 来源: HTML5中国的博客
相关推荐

2012-05-15 13:44:00

HTML5中国

2012-05-15 13:10:57

HTML5

2012-05-15 13:29:20

HTML5

2015-07-08 16:38:10

Cocos游戏引擎

2012-01-06 14:10:13

HTML 5

2012-05-15 10:35:35

HTML5

2012-03-06 10:56:32

HTML 5

2012-05-09 09:41:58

HTML5

2013-06-21 13:33:46

HTML 5游戏

2012-05-10 09:45:14

HTML5

2014-11-12 16:00:12

火舞游戏

2012-01-06 09:45:23

HTML5游戏开发货币化

2011-12-21 09:38:31

HTML 5

2013-06-26 10:14:40

2012-06-06 14:46:52

HTML5

2013-10-21 15:24:49

html5游戏

2011-07-18 11:39:58

iPhone 游戏 引擎

2015-07-10 10:27:21

Cocos游戏开发引擎

2014-12-30 17:13:51

HTML5

2015-10-23 13:44:14

巴巴猎
点赞
收藏

51CTO技术栈公众号