《Cocos Creator遊戲實戰》關卡功能實現

關卡功能實現

創建節點

設置關卡信息

實現關卡界面

爲預製添加腳本

完善Game.js邏輯


在上一節教程中我們講解了打磚塊的主要功能與邏輯實現,在這一篇教程中,筆者會在它的基礎上增加關卡功能(建議先閱讀上一節教程)。

運行效果如下:

 

Cocos Creator版本:2.2.0

後臺回覆"關卡",獲取該項目完整文件:

 

創建節點

1. bg就是一個背景圖片。

 

2. levelsLayout爲一個佈局節點,節點上的Layout組件屬性設置如下(除了Type和Resize Mode,其他屬性大家可以根據需要自行修改):

該節點用來對各個關卡進行佈局,完成後樣子如下:

 

3. level是一個預製節點,其子節點num用於提示當前關卡數,star節點用於提示是否已經通關(沒有通關的時候爲灰色,通關後變爲黃色)。另外num節點初始狀態不可見,只有玩家通過當前關卡後,後面一個關卡的數字纔會顯示(當然第一關在一開始就要顯示數字)。

 

設置關卡信息

我們在scripts文件夾中新建一個Settings.js腳本,編寫如下代碼:

// Settings.js
let settings = [
    {                               
        level: 1,                   // 第1關
        row: 3,                     // 行數
        col: 3,                     // 列數
        spaceX: 20,                 // 列間隔
        spaceY: 20,                 // 行間隔
        brickWidth: 200,            // 磚塊寬度
        brickHeight: 100,           // 磚塊高度
        levelState: 'UNLOCKED',     // 關卡狀態
        transparentBricks: [[1,0], [2,2]]  // 剛開始就透明的磚塊
    },

    {   
        level: 2,                   // 第2關
        row: 6,
        col: 6,
        spaceX: 10,
        spaceY: 10,
        brickWidth: 120,
        brickHeight: 70,
        levelState: 'LOCKED',
        transparentBricks: [[3,5], [4,1], [3,4]]
    },

    {                               
        level: 3,                   // 第3關
        row: 9,
        col: 9,
        spaceX: 10,
        spaceY: 10,
        brickWidth: 100,
        brickHeight: 50,
        levelState: 'LOCKED',
        transparentBricks: [[7,5], [3,1], [5,7],[7,2],[6,8],[7,7]]
    },

    {                               
        level: 4,                   // 第4關
        row: 12,
        col: 15,
        spaceX: 5,
        spaceY: 5,
        brickWidth: 80,
        brickHeight: 40,
        levelState: 'LOCKED',
        transparentBricks: [[1,1], [2,2], [3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]]
    },

    {                               
        level: 5,                   // 第5關
        row: 12,
        col: 15,
        spaceX: 5,
        spaceY: 5,
        brickWidth: 80,
        brickHeight: 40,
        levelState: 'LOCKED',
        transparentBricks: [[1,1], [2,2], [3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]]
    },

    {                               
        level: 6,                   // 第6關
        row: 13,
        col: 13,
        spaceX: 4,
        spaceY: 4,
        brickWidth: 60,
        brickHeight: 30,
        levelState: 'LOCKED',
        transparentBricks: [[9,9], [1,1], [3,4],[5,4],[5,6],[7,6],[7,8],[8,10],[9,1]]
    },
]

export {settings};

在這個腳本中我們就新建了一個JSON變量settings,其中每個數組元素都包含了相應關卡的具體配置(這裏共有六個關卡)。這裏筆者講一下levelState和transparentBricks這兩個鍵:

  • levelState用來判斷當前關卡的狀態:未解鎖,解鎖或通過。
  • 通過控制transparentBricks我們就可以創建出形狀各異的磚塊佈局。

最後用export輸出該變量,我們會在其他腳本中調用。

 

實現關卡界面

新建Select.js腳本,編寫如下代碼:

// Select.js
import {settings} from './Settings.js';

cc.Class({
    extends: cc.Component,

    properties: {
        levelPrefab: cc.Prefab,
        levelsLayout: cc.Node
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad () {
        this.initLevels();
    },

    initLevels () {
        if (!cc.sys.localStorage.getItem('settings')) {
            for (let i=0; i<settings.length; i++) {
                let level = cc.instantiate(this.levelPrefab);
                level.settings = settings[i];
                level.getComponent('Level').changePic(settings[i]['levelState'], (i+1).toString());
                this.levelsLayout.addChild(level);
            }
            // 將所有關卡信息存入本地(針對首次遊戲)
            cc.sys.localStorage.setItem('settings', JSON.stringify(settings));
        }
        else {
            // 如果玩家已經玩過,則從本地存儲中獲取關卡配置信息
            let newSettings = JSON.parse(cc.sys.localStorage.getItem('settings'));
            for (let i=0; i<newSettings.length; i++) {
                let level = cc.instantiate(this.levelPrefab);
                level.settings = newSettings[i];
                level.getComponent('Level').changePic(newSettings[i]['levelState'], (i+1).toString());
                this.levelsLayout.addChild(level);
            }
        }
    }
});

下面是對該腳本代碼的解釋:

  • 在該腳本的開頭我們導入了Settings.js中的setting變量。
  • 在properties中添加levelPrefab和levelsLayout屬性。
  • initLevels方法用於創建各個關卡預製,並添加到佈局中。

在initLevels方法中,我們首先判斷本地存儲中是否有settings項。

如果沒有的話,那麼說明玩家第一次玩,於是我們就新建預製,並將Settings.js中的各個關卡信息保存到相應預製中,調用changePic方法來設置預製相應的圖片(該方法會根據levelState來設置相應的圖片)。最後我們要將所有關卡信息存入本地,我們之後也會在Game.js的win方法中更新關卡信息,而遊戲以後也都會只從本地存儲中讀取關卡信息了(當然可以選擇把本地存儲改爲服務器存儲)。

如果有的話,那麼說明玩家不是第一次玩了,於是我們就從本地中讀取關卡信息,創建並設置預製。

 

爲預製添加腳本

新建Level.js腳本,添加代碼如下:

// Level.js
cc.Class({
    extends: cc.Component,

    properties: {
        unlockedPic: cc.SpriteFrame,
        lockedPic: cc.SpriteFrame,
        greyStarPic: cc.SpriteFrame,
        yellowStarPic: cc.SpriteFrame,
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad () {
        // 觸摸監聽
        this.node.on('touchstart', this.onTouchStart, this);
    },

    changePic (levelState, num) {
        // 更改圖片
        if (levelState == 'UNLOCKED') {
            // 解鎖關卡
            this.node.children[0].active = true;
            this.node.children[0].getComponent(cc.Label).string = num;
            this.node.getComponent(cc.Sprite).spriteFrame = this.unlockedPic;
            this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.greyStarPic;
        }
        else if (levelState == 'PASSED') {
            // 通關
            this.node.children[0].active = true;
            this.node.children[0].getComponent(cc.Label).string = num;
            this.node.getComponent(cc.Sprite).spriteFrame = this.unlockedPic;
            this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.yellowStarPic;

        }
        else if (levelState == 'LOCKED') {
            // 關卡未解鎖
            this.node.getComponent(cc.Sprite).spriteFrame = this.lockedPic;
            this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.greyStarPic;
        }     
    },

    onTouchStart () {
        if (this.node.settings['levelState'] == 'LOCKED')
            return;
        
        // 將目標關卡信息存入本地,在Game.js中取出
        cc.sys.localStorage.setItem('currentLevelInfo', JSON.stringify(this.node.settings));
        cc.director.loadScene('打磚塊');
    }
});

下面是對該腳本代碼的解釋:

  • 在properties中添加四個屬性,都是SpriteFrame類型。前兩張圖片用於關卡背景,後兩張用於星星。
  • 在onLoad方法中添加觸摸監聽。在onTouchStart方法中我們首先根據關卡的levelState來判斷它是否已經解鎖,如果已經解鎖則將當前關卡信息存入currentLevelInfo項中,然後進入打磚塊場景。
  • 在changgePic方法中,我們同樣根據levelState來設置相應圖片。相信看代碼大家可以看懂,這裏筆者就不再贅述。

 

完善Game.js邏輯

在Game.js腳本中,我們首先在onLoad方法中獲取currentLevelInfo項,並設置相關變量:

// Game.js
onLoad () {
    ...

    // 首先獲取當前關卡信息
    let currentLevelInfo = JSON.parse(cc.sys.localStorage.getItem('currentLevelInfo'));
    this.level = currentLevelInfo['level'];                                           // 第幾關
    this.row = currentLevelInfo['row'];                                               // 行數
    this.col = currentLevelInfo['col'];                                               // 列數
    this.spaceX = currentLevelInfo['spaceX'];                                         // 列間隔
    this.spaceY = currentLevelInfo['spaceY'];                                         // 行間隔
    this.brickWidth = currentLevelInfo['brickWidth'];                                 // 磚塊寬度
    this.brickHeight = currentLevelInfo['brickHeight'];                               // 磚塊高度
    this.transparentBricks = currentLevelInfo['transparentBricks'];                   // 剛開始就透明的磚塊
    this.speed = 20;                                                                  // bar移動速度

    ...
},

然後在initBricksLayout方法中根據當前關卡中的transparentBrick來設置透明磚塊:

// Game.js
initBricksLayout () {
    ...

    // 循環放置磚塊
    for (let i=0; i<this.row; i++) {
        for (let j=0; j<this.col; j++) {

            ...

            // 看看是不是透明磚塊
            for (let k=0; k<this.transparentBricks.length; k++) {
                if (this.transparentBricks[k][0]==i && this.transparentBricks[k][1]==j) {
                    brick.opacity = 0;                             // 變透明
                    brick.removeComponent(cc.RigidBody);           // 移出剛體組件,讓該磚塊無法與球碰撞
                }
            }
        }
    }
},

最後我們在win方法中更新關卡信息,只用更改關卡中的levelState就行啦:

// Game.js
win () {
    // 更新關卡信息
    let settings = JSON.parse(cc.sys.localStorage.getItem('settings'));
    settings[this.level-1]['levelState'] = 'PASSED';        // 當前關卡狀態變爲通過(數組下標-1)
    settings[this.level]['levelState'] = 'UNLOCKED';        // 下一關卡狀態變爲解鎖
    cc.sys.localStorage.setItem('settings', JSON.stringify(settings));

    console.log('恭喜過關!');
    cc.director.loadScene('關卡');
},

好了,那麼今天的教程就到這,希望大家有所收穫~

發佈了85 篇原創文章 · 獲贊 170 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章