玩家擋板和控制

這是 Gamedev Phaser 教程第 7 步(共 16 步)。我們已經讓球移動並從牆壁反彈,但很快就會變得無聊——沒有互動性!我們需要一種引入遊戲玩法的方式,因此在本篇文章中,我們將建立一個擋板來移動並擊球。

渲染擋板

從框架的角度來看,擋板與球非常相似——我們需要新增一個屬性來表示它,載入相關的影像資源,然後進行魔法操作。

載入擋板

首先,在 ball 屬性之後,新增我們將在遊戲中使用的 paddle 屬性。

js
class ExampleScene extends Phaser.Scene {
  ball;
  paddle;
  // ...
}

然後,在 preload 方法中,透過新增以下新的 load.image() 呼叫來載入 paddle 影像。

js
class ExampleScene extends Phaser.Scene {
  // ...
  preload() {
    this.load.image("ball", "img/ball.png");
    this.load.image("paddle", "img/paddle.png");
  }
  // ...
}

以免我們忘記,此時,您應該獲取 擋板圖形 並將其儲存在您的 /img 資料夾中。

使用物理引擎渲染擋板

接下來,我們將透過在 create() 方法中新增以下 add.sprite() 呼叫來初始化我們的擋板——將其新增到最底部。

js
this.paddle = this.add.sprite(
  this.scale.width * 0.5,
  this.scale.height - 5,
  "paddle",
);

我們可以使用 scale.widthscale.height 值將擋板定位在我們想要的位置:this.scale.width * 0.5 將位於螢幕的中間。在我們的例子中,世界與畫布相同,但對於其他型別的遊戲,如橫卷軸遊戲,世界會更大,您可以對其進行調整以建立有趣的效果。

您會注意到,如果此時重新載入 index.html,擋板當前位於螢幕的最底部,對於擋板來說太低了。為什麼?因為計算位置的起點是從物件的中心開始的。我們可以更改這一點,將原點設定在擋板寬度中間和高度底部,這樣更容易將其定位在螢幕底部邊緣。在上一行新增程式碼的下方新增以下一行。

js
this.paddle.setOrigin(0.5, 1);

擋板現在已定位在我們想要的位置。現在,為了使其與球碰撞,我們必須為擋板啟用物理引擎。繼續在 create() 方法的末尾新增以下新行。

js
this.physics.add.existing(this.paddle);

現在魔法可以開始發生了——框架可以負責在每一幀檢查碰撞檢測。要在擋板和球之間啟用碰撞檢測,請按所示方式將 collide() 方法新增到 update() 方法中。

js
class ExampleScene extends Phaser.Scene {
  // ...
  update() {
    this.physics.collide(this.ball, this.paddle);
  }
}

第一個引數是我們感興趣的物件之一——球,第二個是另一個物件,擋板。這有效,但並不完全如我們所料——當球撞擊擋板時,擋板會從螢幕上掉下來!我們只希望球從擋板上反彈,而擋板保持在原地。我們可以將擋板的 body 設定為不可移動,這樣當球撞擊它時它就不會移動。為此,請在 create() 方法的末尾新增以下行。

js
this.paddle.body.setImmovable(true);

第二個您會注意到的問題是,球撞擊擋板後,它開始水平移動而不是反射回來。要解決此問題,我們還需要在球本身上設定反彈因子(我們已經透過 setCollideWorldBounds() 為牆壁碰撞做了這一點)。將以下行新增到 create() 方法中,緊跟在 ball.body.setCollideWorldBounds(true, 1, 1) 行之後(我們希望將所有球的配置保留在一起)。

js
this.ball.body.setBounce(1);

現在它按預期工作。

控制擋板

下一個問題是我們無法移動擋板。要解決此問題,我們可以使用系統的預設輸入(取決於平臺,滑鼠或觸控)並將擋板位置設定為 input 位置所在的位置。按所示方式將以下新行新增到 update() 方法中。

js
this.paddle.x = this.input.x;

現在,在每一幀中,擋板的 x 位置都會相應地調整為輸入的 x 位置。但是,當我們開始遊戲時,擋板的位置不在中間。這是因為輸入位置尚未定義。要解決此問題,我們可以將預設位置(如果尚未定義輸入位置)設定為螢幕的中間。將上一行更新為以下內容。

js
this.paddle.x = this.input.x || this.scale.width * 0.5;

如果您還沒有這樣做,請重新載入您的 index.html 並嘗試一下!

定位球

我們已經使擋板按預期工作,現在讓我們將其定位在球上。這與定位擋板非常相似——我們需要將其水平放置在螢幕中間,垂直放置在底部,並與底部保持一點偏移。為了將其精確地放置在我們想要的位置,我們將原點設定為球的精確中心。找到現有的 this.ball = this.add.sprite(...) 行,並將其替換為以下幾行。

js
this.ball = this.add.sprite(
  this.scale.width * 0.5,
  this.scale.height - 25,
  "ball",
);

速度幾乎保持不變——我們只是將第二個引數的值從 150 更改為 -150,因此球將向上移動而不是向下移動開始遊戲。找到現有的 this.ball.body.setVelocity() 行並將其更新為以下內容。

js
this.ball.body.setVelocity(150, -150);

現在球將從擋板的中間開始。

Compare your code

這是您到目前為止應該看到的效果,即時執行。要檢視其原始碼,請單擊“播放”按鈕。

後續步驟

我們可以移動擋板並讓球從擋板上反彈,但如果球仍然從螢幕底部邊緣反彈,那有什麼意義呢?讓我們引入失敗的可能性——也稱為 遊戲結束 邏輯。