在這個教程中,我將使用Phaser.js創建一個平台遊戲。

玩家可以使用左/右箭頭鍵移動,使用上箭頭鍵跳躍。目標是收集遊戲中的所有星星:

當玩家收集到所有星星時,我們將在頂部顯示“遊戲結束”,然後沒有其他操作。

雖然這非常簡單,但這是開始一個非常有趣的遊戲的開始,並且這也是展示Phaser以及JavaScript作為遊戲創作編程語言的絕佳方式。

設置專案

創建一個空文件夾,然後運行以下命令:

npm init -y

這將初始化一個最小的’package.json’文件。

然後運行以下命令:

npm install phaser

如果尚未安裝Parcel,請運行以下命令:

npm install -g parcel-bundler

現在創建一個’app.js’文件,然後運行:

parcel watch app.js

這將告訴Parcel在’dist/app.js’文件中構建我們的遊戲。

創建一個’index.html’文件,內容如下:

<!DOCTYPE html>
<html>
 <head>
 <script src="./dist/app.js"></script>
 </head>
</html>

安裝’browser-sync’以運行包含此文件夾內容的HTTP服務器:

npm install -g browser-sync

然後運行以下命令:

browser-sync start --server --files "."

以上命令會觀察當前文件夾(以及所有子文件夾)中的所有文件的變化,並在端口3000上啟動一個Web服務器,自動打開一個瀏覽器窗口以連接到服務器。

每次更改文件,瀏覽器都會刷新,因此我們可以更快地進行開發。

太好了!我們可以開始了。

初始化Phaser

打開’app.js’並編寫以下代碼:

import Phaser from 'phaser'

讓我們添加一個最小的配置:

const config = {
 width: 800,
 height: 600,
 backgroundColor: 0xffffff,
 scene: {
 preload,
 create,
 update
 },
 physics: {
 default: 'arcade',
 arcade: {
 gravity: { y: 300 },
 debug: false
 }
 }
}

const game = new Phaser.Game(config)

現在創建3個函數’preload()’、‘create()‘和’update()’:

function preload() {

}

function create() {

}

function update() {

}

添加藝術品

我稱之為“藝術品”,但它是我創建的,是你能找到的最醜的藝術品。

但是對於我們簡單的遊戲來說是可以的。下載那些文件並保存為:

ground.png

island.png

player.png

star.png

在創建一個“assets”文件夾,將它們放在其中。

創建一個畫布

現在回到’app.js’。

我們首先要做的是在’preload()‘中加載資源:

function preload() {
 this.load.image('ground', 'assets/ground.png')
 this.load.image('island', 'assets/island.png')
 this.load.image('star', 'assets/star.png')
 this.load.spritesheet('player', 'assets/player.png', {
 frameWidth: 32,
 frameHeight: 48
 })
}

我們為每個資源分配一個標籤。前三個使用’this.load.image()‘加載,最後一個使用’this.load.spritesheet()’,因為該圖像包含多個小圖像,我們將用它們來繪製角色動畫。

因此,我們還必須設置精靈表中每個圖像的尺寸(32x48像素)。

創建平台

現在來創建平台。

我們將創建一個新的物理靜態組來保存它們,因為它們是靜止的對象。

let platforms = this.physics.add.staticGroup()

然後我們添加地面:

platforms.create(400, 588, "ground")

還有5個島:

platforms.create(600, 450, "island")
platforms.create(50, 250, "island")
platforms.create(650, 220, "island")
platforms.create(250, 520, "island")
platforms.create(250, 320, "island")

這些數字表示2D空間中相對於左上角的X和Y坐標,並且參照每個圖像的中心。

這是您此時應該看到的畫面:

添加玩家

現在讓我們添加玩家。

在文件的頂部,在任何函數之外創建一個名為’player’的變量:

let player

然後在’create()‘中,將其添加到屏幕底部的中間:

player = this.physics.add.sprite(380, 500, "player")

我們設置一個小的彈跳效果:

player.setBounce(0.2)

這樣它就能在放到屏幕上之後迅速停止彈跳,並且我們設置它不能超出屏幕範圍:

player.setCollideWorldBounds(true)

這樣它就會出現,彈跳幾下後就會停在屏幕底部。

然而,我們希望玩家能停在地面上方。

我們可以通過在玩家和平台之間添加一個碰撞規則來實現這一點:

this.physics.add.collider(player, platforms)

這樣,玩家不僅會站在地面上,還會停在屏幕上漂浮的其他5個島上。

使玩家移動

現在讓我們使玩家移動。

在文件的頂部,在’player’聲明附近添加一個變量:

let cursors

然後在’create()‘中添加以下代碼:

cursors = this.input.keyboard.createCursorKeys()

以允許訪問鍵盤事件。

現在在現在是空的’update()‘函數中,我們要檢查此變量:

function update() {
 if (cursors.left.isDown) {
 player.setVelocityX(-160)
 } else if (cursors.right.isDown) {
 player.setVelocityX(160)
 } else {
 player.setVelocityX(0)
 }
}

‘update()‘由遊戲循環連續調用,因此每當有一個鍵被按下,我們就在X軸上更改玩家的速度。如果沒有按下鍵,則將其設置為保持靜止。

使玩家動畫

現在讓我們在移動時使玩家圖像改變。

在’create()‘中,我們創建了3個動畫:當玩家靜止,向左移動時,向右移動時:

this.anims.create({
 key: 'still',
 frames: [{ key: 'player', frame: 4 }],
 frameRate: 20
})

this.anims.create({
 key: 'left',
 frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
 frameRate: 10,
 repeat: -1
})

this.anims.create({
 key: 'right',
 frames: this.anims.generateFrameNumbers('player', { start: 5, end: 8 }),
 frameRate: 10,
 repeat: -1
})

‘still’並不是真正的動畫,因為它只有一個幀。但’left’和’right’各由4個幀組成,並且它們被無限重複以模擬走路。

現在我們需要在’update()‘中激活這些動畫:

function update() { 
 if (cursors.left.isDown) {
 player.setVelocityX(-160)
 player.anims.play('left', true)
 } else if (cursors.right.isDown) {
 player.setVelocityX(160)
 player.anims.play('right', true)
 } else {
 player.setVelocityX(0)
 player.anims.play('still')
 }
}

’left’和’right’的’true’參數設置了動畫循環。

跳躍

為了讓玩家能夠跳躍,在’update()‘中添加以下代碼:

if (cursors.up.isDown && player.body.touching.down) {
 player.setVelocityY(-330)
}

每當玩家站在底部(‘player.body.touching.down’)並按下上箭頭時,我們就向上推它。重力會模擬類似於我們在現實世界中做的跳躍。

添加星星

現在讓我們將星星添加到屏幕中。

我們通過創建一個物理組來添加8個星星,並且使它們與平台碰撞,這樣它們就會停在平台上:

let stars = this.physics.add.group()
stars.create(22, 0, "star")
stars.create(122, 0, "star")
stars.create(222, 0, "star")
stars.create(322, 0, "star")
stars.create(422, 0, "star")
stars.create(522, 0, "star")
stars.create(622, 0, "star")
stars.create(722, 0, "star")

this.physics.add.collider(stars, platforms)

允許玩家收集星星

為了讓玩家收集星星,我們將在’create()‘中添加一個碰撞檢測的物理效果,當玩家接觸到一顆星星時觸發:

this.physics.add.overlap(player, stars, (player, star) => {}, null, this)

當這種情況發生時,我們將隱藏星星:

this.physics.add.overlap(
 player,
 stars,
 (player, star) => {
 star.disableBody(true, true)
 },
 null,
 this
)

讓我們創建一個星星計數器。當收集到一顆星星時,我們將其進行增加:

let score = 0

this.physics.add.overlap(
 player,
 stars,
 (player, star) => {
 star.disableBody(true, true)
 score += 1
 },
 null,
 this
)

我們可以在屏幕上方顯示它:

let score = 0
let scoreText = this.add.text(16, 16, "Stars: 0", {
 fontSize: "32px",
 fill: "#000",
})

this.physics.add.overlap(
 player,
 stars,
 (player, star) => {
 star.disableBody(true, true)
 score += 1
 scoreText.setText("Stars: " + score)
 },
 null,
 this
)

完成!我們的小遊戲可以運行了!