《遊戲指令碼的設計與開發》-(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,是不是已經迫不及待的想要看到效果了?測試連線如下:
預覽效果:
最後,給出本次的程式碼下載:
※原始碼執行說明:
1,需要伺服器支援,詳細請看本系列文章《序》和《第一章》
2,原始碼中不含lufylegend.js引擎程式碼,請自己到官方下載引擎
預告:
現在地圖上的NPC人物都是靜止不動的,在實際的遊戲中有些NPC會隨即的走動,使得遊戲效果更為生動,
另外大家都知道,RPG遊戲中有一個重要的功能,就是任務系統,玩家完成某一項人物會得到什麼獎勵,然後接著出現一個新的任務等等,
後面我接著來給大家介紹地圖的切換效果,NPC人物的隨即走動,以及地圖指令碼中的任務系統,請期待下次更新。
《遊戲指令碼的設計與開發》系列文章目錄