《從0到1上線微信小遊戲》第三節 實現方塊消除和遊戲失敗邏輯

第三節 實現方塊消除和遊戲失敗邏輯

方塊消除

遊戲失敗


在上一節我們實現了形狀的旋轉和移動功能,那隻要再實現標題中的這兩個功能,俄羅斯方塊這個遊戲基本上也就算完成了(可以動手玩了)。

 

方塊消除

判斷是否要消除的方塊的邏輯很簡單,只需要檢查某一行是否被方塊填滿即可——也就是說,如果某一行上所有方塊的寬度總和等於屏幕寬度的話,那麼我們就可以消除這一行了。

代碼如下:

// Game.js
removeLines() {
    // 消除
    let lines = [];                                 // 用於記錄被消除的行編號(第幾行)
    for (let i=0; i<this.row; i++) {
        let tempWidth = 0;                          // 用於判斷是否進行消除
        let tempTile = [];                          // 存儲某一行上要被消除的方塊預製
        let y = Math.round(-i*this.tileHeight);     // 當前行的y值

        // 判斷confirmedTileArray中方塊的y值跟當前行的y值是否相同
        for (let j=0; j<this.confirmedTileArray.length; j++) {
            let confirmedY = Math.round(this.confirmedTileArray[j].y);
            if (y == confirmedY) {
                tempTile.push(this.confirmedTileArray[j]);  // 如果相同則存儲該方塊
                tempWidth += this.tileWidth;                // 並增加tempWidth值
            }
        }
        
        // 判斷tempWidth值是否等於(或超過)shapeBoard的寬度,若超過,則說明該行已被填滿
        if (tempWidth >= this.shapeBoard.width) {
            lines.push(i);
            tempTile.forEach(e=>{
                // 從confirmedTileArray中刪除相關方塊
                for (let j=0; j<this.confirmedTileArray.length; j++) {
                    if (e == this.confirmedTileArray[j])
                        this.confirmedTileArray.splice(j, 1);
                }
                this.tilePool.put(e);                       // 回收方塊
            });
        }
    }
},
  • 首先循環所有行,每次循環時查找confirmedTileArray中哪些方塊的y值跟當前行y值相同,這樣就可以知道這一行上有所少個方塊了。
  • 每找到一個方塊,那我們就把它防暑temTile數組中,並且讓tempWidth值增加(一個方塊寬度)。
  • 如果tempWidth等於(正常來講不會超過)屏幕寬度,那麼就說明這一行已經被填滿了,允許消除。
  • 接着將當前行的編號放到lines數組中(用於之後的方塊下落),再從confirmedTileArray中刪除相關的方塊元素,當然也要把這個方塊回收到節點池中。

在moveDown方法中調用剛編寫好的removeLines(),注意只有方塊觸底和碰到其他方塊時才進行調用:

// Game.js
moveDown () {
    // 往下移動一步
    for (let i=0; i<this.shapeTileArray.length; i++) {
        let x = Math.round(this.shapeTileArray[i].x);
        let y = Math.round(this.shapeTileArray[i].y - this.tileHeight);

        // 如果觸底,則不再下降
        if (Math.abs(y) >= this.shapeBoard.height)  {
            this.shapeTileArray.forEach(element => {                // 將確定的方塊放入this.confirmedTileArray
                this.confirmedTileArray.push(element);
            });

            this.removeLines();                                     // 消除方塊
            this.makeShape();                                       // 重新生成形狀
            return false;
        }


        // 如果碰到其他方塊,則不再下降
        for (let j=0; j<this.confirmedTileArray.length; j++) {
            let confirmedX = Math.round(this.confirmedTileArray[j].x);
            let confirmedY = Math.round(this.confirmedTileArray[j].y);

            if (confirmedX==x && confirmedY==y) {
                this.shapeTileArray.forEach(element => {            // 將確定的方塊放入this.confirmedTileArray
                    this.confirmedTileArray.push(element);
                });

                this.removeLines();                             // 消除方塊
                this.makeShape();                               // 沒輸則重新生成形狀
                return false;
            }
        }
    }

    ...
},

 

此時我們運行遊戲,發現滿足條件後方塊可以被正常消除:

不過消除之後其他方塊並未下落。所以我們還需要編寫一個dropConfirmedTiles方法:

// Game.js
dropConfirmedTiles (lines) {
    // 讓其他未消除的方塊下落
    for (let i=0; i<lines.length; i++) {
        for (let j=0; j<this.confirmedTileArray.length; j++) {
            let confirmedY = Math.round(this.confirmedTileArray[j].y);
            
            // 只有消除行上方的方塊才允許下降
            if (confirmedY <= -lines[i]*this.tileHeight)
                continue;

            this.confirmedTileArray[j].y -= this.tileHeight;
        }
    }
},

不過請注意,並不是所有的方塊都會下落,只有在消除行上方的方塊纔可以。

記得在removeLines方法最後調用dropConfirmeTile():

// Game.js
removeLines() {
    ...

    // 讓其他未消除的方塊下落
    if (lines.length)
        this.dropConfirmedTiles(lines);
},

 

遊戲失敗

當某一形狀中的各方塊下落完畢後,如果任一方塊超出屏幕頂端,則遊戲失敗:

// Game.js
judgeLose() {
    for (let i=0; i<this.confirmedTileArray.length; i++) {
        let confirmedY = Math.round(this.confirmedTileArray[i].y);
        
        // 如果有任何一個方塊超出頂端,則輸
        if (confirmedY >= 0) 
            return true;
    }
    return false;
},

循環confirmedTileArray,讓我們看看是哪個方塊超出了屏幕頂端(通過y值判斷)。

 

遊戲失敗了就要有失敗的樣子。在層級管理其中添加一個Sprite類型節點顯示Game Over圖片,以及一個重新開始按鈕。

將gameOver的透明度設爲0,然後隱藏restartBtn節點(遊戲失敗了我們再顯示):

  

編寫lose方法,該方法在遊戲判定失敗後調用:

// Game.js
lose () {
    // 遊戲失敗
    this.unschedule(this.moveDown);             // 取消計時器

    let fadeInAction = cc.fadeIn(1);            
    this.gameOverNode.runAction(fadeInAction);  // 顯示Game Over圖片

    this.restartNode.active = true;             // 顯示restart按鈕
},

Game Over圖片我們用漸顯,而restart按鈕則直接通過active進行顯示。

記得在properties中添加以下兩個屬性:

// Game.js
properties: {
    ...
    gameOverNode: cc.Node,
    restartNode: cc.Node,
},

restart按鈕的事件函數非常簡單,重新載入當前場景即可:

// Game.js
restart() {
    // 重新開始
    cc.director.loadScene('俄羅斯方塊');
},

 

最後我們在moveDown方法中調用judeLose()判斷遊戲是否失敗就行啦:

moveDown () {
    // 往下移動一步
    for (let i=0; i<this.shapeTileArray.length; i++) {
        ...


        // 如果碰到其他方塊,則不再下降
        for (let j=0; j<this.confirmedTileArray.length; j++) {
            let confirmedX = Math.round(this.confirmedTileArray[j].x);
            let confirmedY = Math.round(this.confirmedTileArray[j].y);

            if (confirmedX==x && confirmedY==y) {
                this.shapeTileArray.forEach(element => {            // 將確定的方塊放入this.confirmedTileArray
                    this.confirmedTileArray.push(element);
                });

                if (this.judgeLose()) {
                    this.lose();                                    // 遊戲失敗
                }
                else {
                    this.removeLines();                             // 消除方塊
                    this.makeShape();                               // 沒輸則重新生成形狀
                }
                return false;
            }
        }
    }

    ...
},

運行截圖如下:

 

雖然標準的俄羅斯方塊遊戲沒有"贏"這一說法,但規矩是死的,我們完全可以發揮自己的想象力讓俄羅斯方塊可以贏對吧,比如可以給遊戲添加關卡功能。大家可以點擊該鏈接去了解下如何實現這一功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章