html5遊戲開發-零基礎開發RPG遊戲-開源講座(三)-卷軸&對話實現

lufy發表於2013-05-27

本文章首發自我的部落格 http://blog.csdn.net/lufy_legend/article/details/7094567

前兩篇,RPG的開發已經實現了新增地圖和新增遊戲人物,本篇來實現地圖的卷軸滾動和人物對話的實現,效果如下 enter image description here

地圖的滾動

關於地圖的滾動原理,可以參照下圖 enter image description here 按照上圖說明,實現地圖滾動,只需要先把即將出現的地圖(圖中黃色部分)畫上,然後滾動地圖,待地圖滾動完畢之後,將螢幕之外的部分(圖中綠色部分)移除

首先要新增一個變數來控制地圖是否滾動

//地圖滾動
var mapmove = false;

然後,在人物移動的時候,判斷地圖是否需要滾動

/**
 * 地圖是否滾動
 **/
Character.prototype.checkMap = function (dir){
    var self = this;
    mapmove = false;
    //如果不是英雄,則地圖不需要滾動
    if(!self.isHero)return;

    switch (dir){
        case UP:
            if(self.y + charaLayer.y> STEP)break;
            if(mapLayer.y >= 0)break;
            addMap(0,-1);
            mapmove = true;
            break;
        case LEFT:
            if(self.x + charaLayer.x > STEP)break;
            if(mapLayer.x >= 0)break;
            addMap(-1,0);
            mapmove = true;
            break;
        case RIGHT:
            if(self.x < 480 - 2*STEP)break;
            if(480 - mapLayer.x >= map[0].length*STEP)break;
            addMap(1,0);
            mapmove = true;
            break;
        case DOWN:
            if(self.y < 288 - 2*STEP)break;
            if(288 - mapLayer.y >= map.length*STEP)break;
            addMap(0,1);
            mapmove = true;
            break;
    }
};

在移動過程中,判斷地圖是否處於滾動狀態,如果地圖處於滾動,則滾動地圖,否則移動人物

/**
 * 開始移動 
 **/
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(mapmove)delMap();
        self.moveIndex = 0;
        //如果已經鬆開移動鍵,或者前方為障礙物,則停止移動,否則繼續移動
        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);
    }
};

最後,將地圖的陣列和地形擴大為大於螢幕大小

//地圖圖片陣列
var 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]
];
//地圖地形陣列
var 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]
];

為了實現地圖滾動,修改新增地圖的方法,根據引數來實現新增上面圖片的黃色地圖部分

//新增地圖
function addMap(cx,cy){
    var i,j,index,indexX,indexY;
    var bitmapdata,bitmap;
    var mapX = mapLayer.x / STEP;
    var mapY = mapLayer.y / STEP;
    var mx = cx<0?-1:0,my = cy<0?-1:0;
    if(imageArray == null){
        //地圖圖片資料
        bitmapdata = new LBitmapData(imglist["map"]);
        //將地圖圖片拆分,得到拆分後的各個小圖片的座標陣列
        imageArray = LGlobal.divideCoordinate(bitmapdata.image.width,bitmapdata.image.height,10,10);
    }
    mapLayer.removeAllChild();
    //在地圖層上,畫出15*10的小圖片
    for(i=my;i<9 +Math.abs(cy) && i-mapY < map.length;i++){
        for(j=mx;j<15 +Math.abs(cx)&& j-mapX < map[0].length;j++){
            //從地圖陣列中得到相應位置的圖片座標
            index = map[i-mapY][j-mapX];
            //小圖片的豎座標
            indexY = Math.floor(index /10);
            //小圖片的橫座標
            indexX = index - indexY*10;
            //得到小圖片
            bitmapdata = new LBitmapData(imglist["map"],indexX*32,indexY*32,32,32);
            bitmap = new LBitmap(bitmapdata);
            //設定小圖片的顯示位置
            bitmap.x = j*STEP - mapLayer.x;
            bitmap.y = i*STEP - mapLayer.y;
            //將小圖片顯示到地圖層
            mapLayer.addChild(bitmap);
        }
    }
}
//移除多餘地圖塊
function delMap(){
    var bitmap,i;
    for(i=0;i<mapLayer.childList.length;i++){
        bitmap = mapLayer.childList[i];
        if(bitmap.x + mapLayer.x < 0 || bitmap.x + mapLayer.x >= 480 || 
                bitmap.y + mapLayer.y < 0 || bitmap.y + mapLayer.y >= 288){
            mapLayer.removeChild(bitmap);
            i--;
        }
    }
}

看一下效果如下 enter image description here

人物的對話

對話的實現,在點選控制按鈕的方形按鈕時新增,所以,先在滑鼠抬起的時候,判斷是否點選了方形按鈕

function onup(event){
    isKeyDown = false;
    if(event.offsetX >= ctrlLayer.x + 280 && event.offsetX <= ctrlLayer.x+330){
        if(event.offsetY >= ctrlLayer.y+40 && event.offsetY <= ctrlLayer.y+100){
            //對話
            addTalk();
        }
    }
}

在完善addTalk()方法的時候,首先準備好對話的內容

var talkScriptList = {
    "talk1":new Array(
        {img:"m",name:"鳴人",msg:"我是木葉村的鳴人,你是誰?"},
        {img:"n",name:"黑衣忍者甲",msg:"你就是鳴人?九尾還在你身體裡嗎?"}
        ),
    "talk2":new Array(
        {img:"n",name:"黑衣忍者乙",msg:"鳴人,聽說忍者大戰就要開始了。"},
        {img:"m",name:"鳴人",msg:"真的嗎?一定要想想辦法啊。"}
        )
};

talk1,talk2中talk後面的數字,代表人物的編號,其中每個對話單位的img為人物的頭像,name為人物的名稱,msg為對話的內容 新增對話時的做法是,當點選方形按鈕後,判斷小鳴人前方是否有人,如果有人,則將這個人物的編號取出來,再從上面的陣列中獲取相應的對話內容,然後,將相應的內容顯示到遊戲螢幕上,具體實現程式碼如下

//對話內容
var talkScript;
var talkScriptList = {
    "talk1":new Array(
        {img:"m",name:"鳴人",msg:"我是木葉村的鳴人,你是誰?"},
        {img:"n",name:"黑衣忍者甲",msg:"你就是鳴人?九尾還在你身體裡嗎?"}
        ),
    "talk2":new Array(
        {img:"n",name:"黑衣忍者乙",msg:"鳴人,聽說忍者大戰就要開始了。"},
        {img:"m",name:"鳴人",msg:"真的嗎?一定要想想辦法啊。"}
        )
};
//對話序號
var talkIndex = 0;
//對話中
var talking = false;

/**
 * 新增對話
 * */
function addTalk(){
    //如果對話內容為空,則開始判斷是否可以對話
    if(talkScript == null){
        var key,tx = player.x,ty = player.y;
        switch (player.direction){
        case UP:
            ty -= STEP;
            break;
        case LEFT:
            tx -= STEP;
            break;
        case RIGHT:
            tx += STEP;
            break;
        case DOWN:
            ty += STEP;
            break;
        }
        for(key in charaLayer.childList){
            //判斷前面又沒有npc,有則開始對話
            if(charaLayer.childList[key].x == tx && charaLayer.childList[key].y == ty){
                if(talkScriptList["talk"+charaLayer.childList[key].index]){
                    talkScript = talkScriptList["talk"+charaLayer.childList[key].index];
                    talkIndex = 0;
                }
            }
        }
        //如果前方沒有npc,則返回
        if(talkScript == null)return;
    }
    //將對話層清空
    talkLayer.removeAllChild();
    //當對話開始,且按照順序進行對話
    if(talkIndex < talkScript.length){
        //得到對話內容
        var talkObject = talkScript[talkIndex];
        //對話背景
        bitmapdata = new LBitmapData(imglist["talk"]);
        bitmap = new LBitmap(bitmapdata);
        bitmap.width = 330;
        bitmap.height = 70;
        bitmap.x = 100;
        bitmap.y = 20;
        bitmap.alpha = 0.7;
        talkLayer.addChild(bitmap);
        //對話頭像
        bitmapdata = new LBitmapData(imglist[talkObject.img]);
        bitmap = new LBitmap(bitmapdata);
        bitmap.x = 0;
        bitmap.y = 0;
        talkLayer.addChild(bitmap);
        //對話人物名稱
        var name = new LTextField();
        name.x = 110;
        name.y = 30;
        name.size = "14";
        name.color = "#FFFFFF";
        name.text = "[" + talkObject.name + "]";
        talkLayer.addChild(name);
        //對話內容
        var msg = new LTextField();
        msg.x = 110;
        msg.y = 55;
        msg.color = "#FFFFFF";
        msg.text = talkObject.msg;
        talkLayer.addChild(msg);
        //對話內容逐字顯示
        msg.wind();
        talkLayer.x = 20;
        talkLayer.y = 50;
        talkIndex++;
    }else{
        //對話結束
        talkScript = null;
    }
}

效果看下圖 enter image description here

遊戲演示地址 http://lufylegend.com/demo/rpg/index.html

lufylegend.js引擎包內包含這個demo,請直接下載lufylegend.js引擎,檢視引擎包內原始碼

lufylegend.js引擎下載地址 http://lufylegend.com/lufylegend

相關文章