HTML 5開發(fā)RPG游戲之四(游戲腳本化)
首先,本篇文章是零基礎開發(fā)RPG游戲-開源講座系列文章的第四篇,來實現(xiàn)游戲的腳本化,和利用游戲腳本實現(xiàn)地圖場景的切換,離上次更新貌似很長時間了,你在看下面的文字之前,需要先了解前三篇在下啰嗦了些什么東東。
一,什么是游戲腳本
簡單說,游戲腳本就是依據(jù)一定的格式編寫的可執(zhí)行文件,游戲可以通過腳本中自定義的語句來執(zhí)行相應的邏輯。
二,為什么要將游戲腳本化
游戲腳本,可以令我們的游戲動態(tài)化,比如當我們開發(fā)了一款rpg游戲,里面的劇情,事件以及地圖等,我們?nèi)绻麑⑦@些全部寫進程序里,當然是可以的,但是一旦出現(xiàn)問題,哪怕幾個錯別字,我們需要先將這幾個錯別字改正,并且將整個程序重新編譯發(fā)布一遍,這個過程是相當令人反感的,因為如果游戲的程序跟著游戲的內(nèi)容不斷進行修改的話,那只會使你的程序越來越復雜。但是如果我們將這些可重復的數(shù)據(jù),都定義到游戲程序之外的文件里面,當游戲引擎開發(fā)完畢,我們的游戲通過讀取這些外部文件,來執(zhí)行相應的劇情和事件,那么,像上述當我們的游戲出現(xiàn)了問題,我們只需要改動這些外部文件就可以了,并不需要重新編譯整個程序,這樣便使得我們的游戲開發(fā),變得便利簡潔。
當然,對于html5來說,不需要重新編譯程序,但是對于rpg的游戲來說,腳本還是必不可少的,因為游戲的劇本不可能全都寫到程序里...
三,如何來實現(xiàn)游戲的腳本化
好了,接下來,先來考慮以什么形式來制作游戲的腳本,我們有多種選擇,可以選擇xml,可以選擇json,也可以選擇純自定義語法,
這次,我為了省事,選用比較方便處理的json,因為javascript可以很輕松的處理json數(shù)據(jù)。
目前游戲中實現(xiàn)的內(nèi)容有,地圖場景添加,游戲人物添加,以及人物對話的實現(xiàn)。那么,我在設計游戲腳本的時候,必須包含這些數(shù)據(jù),然后才能將這三項功能用腳本來控制。
首先看下面的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:"鳴人,聽說忍者大戰(zhàn)就要開始了。"},
- {img:"m",name:"鳴人",msg:"真的嗎?一定要想想辦法啊。"}
- ]
- }
- }
- };
我將腳本定義成了變量,實際游戲制作的時候,腳本應該儲存到一個外部文檔當中,在這里我只是講解一下理論,如何完善那是后話了,哈。
可以看到,json中,包含了地圖相關的map數(shù)組和mapdata數(shù)組,添加人物的相關數(shù)據(jù),以及對話的數(shù)組。這樣,我在游戲顯示的時候,只需要讀入json數(shù)據(jù),然后根據(jù)這些內(nèi)容來顯示游戲畫面就可以了,定義一個initScript函數(shù)來進行這些操作。
- function initScript(){
- //地圖位置初始化
- mapLayer.x = 0;
- mapLayer.y = 0;
- //地圖層初始化
- mapLayer.removeAllChild();
- //人物層初始化
- charaLayer.removeAllChild();
- //效果層初始化
- effectLayer.removeAllChild();
- //對話層初始化
- talkLayer.removeAllChild();
- //地圖數(shù)據(jù)獲取
- map = stage.map;
- mapdata = stage.mapdata;
- //對話數(shù)據(jù)獲取
- talkScriptList = stage.talk;
- //添加地圖
- addMap(0,0);
- delMap();
- //添加人物
- addChara();
- }
removeAllChild方法是legendForHtml5Programming引擎獨有的方法,可以用來移出LScript顯示層上的所有子對象,從而實現(xiàn)本游戲中各個顯示層的初始化工作。
修改一下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);
- }
- }
即,根據(jù)json腳本中的add數(shù)組,來添加游戲中的人物。
好了,運行一下游戲,可以看到,游戲正常顯示了,和之前一模一樣,實現(xiàn)了同樣的功能.
#p#
四,利用游戲腳本實現(xiàn)地圖的切換
為了讓大家看到游戲腳本的便利性,現(xiàn)在利用腳本實現(xiàn)游戲中的場景切換。
將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:"鳴人,聽說忍者大戰(zhàn)就要開始了。"},
- {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節(jié)點來控制游戲場景的切換,其中jump中的at表示游戲主人公移動到達的坐標,to表示到達這個坐標后跳轉到的畫面名稱。這里的jump之所以是數(shù)組,是因為一個場景也可以跳轉到其他多個場景。
上面的腳本實現(xiàn)了stage01和stage02兩個場景的互相跳轉。
為了讀取這個jump,以及實現(xiàn)跳轉,我們需要在游戲主人公移動一個步長之后,判斷一下是否應該跳轉了,修改Character類的onmove方法
- /**
- * 開始移動
- **/
- Character.prototype.onmove = function (){
- var self = this;
- //設定一個移動步長中的移動次數(shù)
- var ml_cnt = 4;
- //計算一次移動的長度
- var ml = STEP/ml_cnt;
- //根據(jù)移動方向,開始移動
- 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++;
- //當移動次數(shù)等于設定的次數(shù),開始判斷是否繼續(xù)移動
- if(self.moveIndex >= ml_cnt){
- //一個地圖步長移動完成后,判斷地圖是否跳轉
- if(self.isHero && self.moveIndex > 0)checkJump();
- self.moveIndex = 0;
- //一個地圖步長移動完成后,如果地圖處于滾動狀態(tài),則移除多余地圖塊
- if(mapmove)delMap();
- //如果已經(jīng)松開移動鍵,或者前方為障礙物,則停止移動,否則繼續(xù)移動
- 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++){
- jumpjumpstage = jump[0];
- if(player.x == jumpstage.at.x * 32 && player.y == jumpstage.at.y * 32){
- //獲取該場景腳本數(shù)據(jù)
- stage = script[jumpstage.to];
- //開始跳轉
- initScript(stage);
- return;
- }
- }
- }
好了,一切都很簡單吧,運行游戲看看效果吧,小鳴人走到地圖的小房門的部分是,場景發(fā)生跳轉
游戲測試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
【編輯推薦】