開發第一個Phaser3遊戲

1. 前言

這是咱們第一個用Phaser3開發遊戲的教程。咱們將學習如何建立一個小遊戲,包括玩家在平臺上跑和跳,收集星星並避免一些很差的行爲。html

什麼是Phaser?

Phaser是一個HTML5旨在幫助開發者建立強大、跨瀏覽器的HTML5遊戲的框架。它是利用現代瀏覽器(桌面版和移動版)的優點而專門建立的。 對瀏覽器的惟一要求是對Canvas標籤的支持。git

每步的完整代碼和資源能夠在此處下載。在繼續以前,建議先看看Phaser3入門github

在咱們的編輯器中打開part1.html頁面,代碼主要結構以下所示:瀏覽器

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var game = new Phaser.Game(config);

function preload(){
}

function create(){
}

function update(){
}

config對象表示咱們想如何配置Phaser遊戲。能夠在此對象中設置許多選項,隨着咱們對Phaser瞭解加深將其進一步拓展。上述代碼中咱們設置了渲染器,尺寸和默認Scene。框架

config對象被傳給Phaser.Game對象的一個實例並賦值給game這個局部變量。這是Phaser遊戲生命週期的開始。編輯器

type屬性能夠是Phaser.CANVASPhaser.WEBGL或者Phaser.AUTOide

這是要用於遊戲的渲染上下文。 推薦值爲Phaser.AUTO,它會自動嘗試使用WebGL,可是若是瀏覽器或設備不支持WebGL,它將使用Canvas。 Phaser建立的Canvas元素將在調用腳本時添加到HTML文檔中,但也能夠根據須要在遊戲配置中指定一個父容器。函數

widthheight屬性用於設置Phaser建立的Canvas元素的尺寸。上面代碼是800x600像素,能夠設置成任何想要的尺寸,也表明遊戲的分辨率。學習

配置對象的scene屬性將在以後的內容更加詳細的介紹。動畫

2. 加載資源

讓咱們加載遊戲所須要的資源。這個能夠經過放在稱爲preload的Scene函數中來實現。 Phaser將在啓動時自動尋找該函數中並加載其中定義的全部內容。

以前的preload函數是空的,咱們作以下更改:

function preload(){
    this.load.image('sky', 'assets/sky.png');
    this.load.image('ground', 'assets/platform.png');
    this.load.image('star', 'assets/star.png');
    this.load.image('bomb', 'assets/bomb.png');
    this.load.spritesheet('dude', 'assets/dude.png',
        {frameWidth: 32, frameHeight: 48}
    );
}

這將加載5個資源:4張圖像和1個精靈表。load.image函數的第一個參數是個字符串,至關於資源的鍵值。

顯示圖像

爲了顯示一張咱們已經加載過的圖像資源,咱們能夠將下列代碼放到create函數中:

this.add.image(400,300,'sky');

在瀏覽器中訪問part3.html文件,能夠看到有個藍色的天空背景:

400和300是圖像的x和y座標。 爲何是400和300? 這是由於在 Phaser3中,默認狀況下全部遊戲對象都基於其中心位置。 背景圖像的尺寸爲800x600像素,所以,若是咱們將其設置爲0x0爲中心,只會看到其右下角。若是咱們設置爲400x300,將會看到整個圖像。

提示:咱們可使用 setOrigin函數改變這種設置。好比, this.add.image(0,0,'sky').setOrigin(0,0)

遊戲對象的顯示順序與建立它們的順序一致。 所以,若是想在背景上放置一個星星,只要將建立星星的代碼放在天空以後:

function create(){
    this.add.image(400, 300, 'sky');
    this.add.image(400, 300, 'star');
}

3. 平臺

讓咱們給遊戲添加一些平臺,

function create(){
    this.add.image(0, 0, 'sky').setOrigin(0,0);
    platforms = this.physics.add.staticGroup();
    platforms.create(400, 568, 'ground').setScale(2).refreshBody();
    platforms.create(600, 400, 'ground');
    platforms.create(50,250,'ground');
    platforms.create(750,220,'ground');
}

上述代碼用了this.physics,咱們將使用Arcade物理系統,在使用以前須要經過配置對象告訴Phaser咱們須要用它。

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
        arcade: {
            gravity: {y: 300},
            debug: false
        }
    },
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

在瀏覽器中訪問part4.html文件能夠看到,

咱們用

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

建立了一個靜態物理組,並將其賦值給platforms。 在Arcade物理系統中,有兩種類型的物理實體:動態和靜態。 動態物體是能夠因爲受到速度或加速度之類的力而移動的物體。它可能會因爲和其它物體碰撞而彈開。

而靜態物體僅具備位置和大小。 它不會受到重力的影響,咱們沒法在其上設置速度,而且當物體與其碰撞時,它不會所以而移動。因爲這個特性,它很是適合咱們遊戲中須要的地面和平臺。

那什麼是組呢?顧名思義,它將相似的對象組合在一塊兒並將它們做爲一個總體加以控制。好比,咱們能夠檢查組和其餘遊戲對象是否發生碰撞。

建立了平臺組後,咱們就以用其建立平臺了:

platforms.create(400, 568, 'ground').setScale(2).refreshBody();
platforms.create(600, 400, 'ground');
platforms.create(50,250,'ground');
platforms.create(750,220,'ground');

如今,咱們能夠看到上圖所示的內容了。代碼的第一行咱們建立了地面,以後將其放大兩倍。由於原始的ground圖像是400x32像素的,而咱們的遊戲界面的尺寸是800x600,因此咱們須要將圖像放大兩倍,也就是變成800x64,不然玩家就會從地面掉下去。

4. 玩家

建立個名爲player的變量,並將下列代碼寫在create函數中:

player = this.physics.add.sprite(100,450,'dude');
player.setBounce(0.2);
player.setCollideWorldBounds(true);

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

this.anims.create({
    key: 'turn',
    frames: [{key: 'dude', frame: 4}],
    frameRate: 20
});

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

主要作了兩件事:建立物理精靈和建立可使用的一些動畫。

物理精靈

代碼的第一部分建立了精靈:

player = this.physics.add.sprite(100,450,'dude');
player.setBounce(0.2);
player.setCollideWorldBounds(true);

咱們建立了一個精靈並賦值給player,並讓其顯示在遊戲的底部(100x450)。精靈建立是經過Physics Game Object Factory(this.physics.add),意味着它是動態物體。

建立精靈後,將反彈值設爲0.2。 這意味着當它跳下後着陸時,它會反彈得比較小。 而後將精靈設置會與遊戲邊界碰撞。 默認狀況下,遊戲邊界在遊戲尺寸的以外。 當咱們將遊戲尺寸設置爲800x600時,玩家將沒法在該區域以外活動,將避免玩家跑出屏幕邊緣或跳出頂部。

動畫

回頭看一下preload函數,會看到dude是做爲精靈表而不是圖像加載的。 那是由於它包含動畫幀。 完整的精靈表以下所示:

總共有9幀,4幀向左跑,1幀面向鏡頭,4幀向右跑。咱們定義了兩個動畫leftright。這是left動畫:

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

left動畫使用幀0、一、2和3,以每秒10幀的速度運行。repeat: -1指的是讓動畫循環運行。

查看一下如今遊戲的運行狀況,咱們會發現玩家會從地面掉下來……

爲了讓玩家與平臺碰撞,咱們能夠建立一個Collider對象。 讓該對象監視兩個物理對象(能夠包括組),並檢測它們之間是否存在碰撞或重疊。 若發生這種狀況,則能夠選擇調用相應的函數,僅僅爲了檢測與平臺碰撞,咱們並不須要調用什麼函數:

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

5. 鍵盤控制

如今咱們開始給咱們的遊戲加入一些鍵盤控制。Phaser有內置的鍵盤管理器,一大好處就是咱們能夠用下面這樣方便的函數:

cursors = this.input.keyboard.createCursorKeys();

cursors對象有四個屬性:updownleftright,它們都是Key對象的實例。咱們須要作的就是在update函數中進行處理:

cursors = this.input.keyboard.createCursorKeys();
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('turn');
}

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

當咱們按下鍵盤<-鍵時,玩家的運動速度設爲-160,並播放left動畫,其它按鍵也進行相似處理。值得注意的是,咱們在最後的if語句中加入的player.body.touching.down這個條件,若不加的話,玩家將能夠上演「縱雲梯」,咱們不但願這樣,因此加入了這個條件。詳情請看Phaser.Physics.Arcade.Body

6. 收集星星

是時候給咱們的遊戲定個小目標了!咱們將在遊戲場景中添加一些星星,並讓玩家能夠去收集它們。在create函數中添加以下代碼:

stars = this.physics.add.group({
    key: 'star',
    repeat: 11,
    setXY: {x: 12, y: 0, stepX: 70}
});

stars.children.iterate(function(child){
    child.setBounceY(Phaser.Math.FloatBetween(0.4,0.8));
});

與建立平臺組相似,只不過此次咱們建立的是動態物理組,而不是靜態物理組。

代碼將迭代組中的全部元素,併爲他們提供介於0.4和0.8之間的隨機Y反彈值。 反彈範圍介於0(徹底沒有反彈)和1(完整反彈)之間。 全部的星星都是在y=0處產生的,因爲重力它們會掉落,直到它們與平臺或地面碰撞。 反彈值表示它們將隨機反彈,直到最終穩定下來。

但若是咱們如今運行代碼,星星會掉到遊戲的底部而不見了。 爲此,咱們須要檢查它們是否與平臺發生碰撞。 咱們能夠用另外一個Collider對象來作到這點:

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

咱們遊戲的目標是讓玩家能夠收集星星,爲此,須要檢測玩家是否和星星發生重疊:

this.physics.add.overlap(player, stars, collectStar, null, this);

以上代碼告訴Phaser,若玩家和星星重疊了就調用collectStar函數。

function collectStar(player, star){
    star.disableBody(true, true);
}

collectStar函數讓與玩家重疊了的星星不可見。

7. 計分

咱們可能還但願讓遊戲計分,並在遊戲中顯示。

建立兩個變量:

var score = 0;
var scoreText;

score用來記錄分數,scoreText將是個Text對象,用於在遊戲中顯示分數。在create函數中建立Text對象的一個實例,並將其賦值給scoreText

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

每次咱們收集到星星,分數就會增長,因而咱們能夠將其代碼加入到以前的collectStar函數中。

score += 10;
scoreText.setText('Score: ' + score);

8. 炸彈

爲了完善咱們的遊戲,是時候給遊戲增長一點挑戰了。想法是這樣的:當咱們收集完全部星星時,它將放出一顆炸彈,全部星星都會重現。 炸彈只會在水平方向隨機反彈,玩家觸碰到炸彈就會死。而咱們能夠再次收集星星,收集完它將釋放另外一枚炸彈。 因此,要在不死的狀況下得到儘量高的分數。

首先建立一個炸彈組和兩個Collider對象:

bombs = this.physics.add.group();

this.physics.add.collider(bombs, platforms);
this.physics.add.collider(player, bombs, hitBomb, null, this);

玩家碰到炸彈,將調用hitBomb函數。這裏咱們作的是讓玩家變成紅色,並結束遊戲。

function hitBomb(player, bomb){
    this.physics.pause();
    player.setTint(0xff0000);
    player.anims.play('turn');
    gameOver = true;
}

而後,咱們修改一下hitStar函數,以便釋放炸彈:

function collectStar(player, star){
    star.disableBody(true, true);
    score += 10;
    scoreText.setText('Score: ' + score);

    if (stars.countActive(true) === 0){
        stars.children.iterate(function(child){
            child.enableBody(true, child.x, 0, true, true);
        });
        var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
        var bomb = bombs.create(x, 16, 'bomb');
        bomb.setCollideWorldBounds(true);
        bomb.setVelocity(Phaser.Math.Between(-200,200), 20);
    }
}

咱們用了GroupcountActive方法來查看還剩多少星星。若是爲零,表示玩家已收集了全部星星,所以咱們迭代地啓用全部星星,並將其y座標置爲零。這將使全部星星再次從屏幕頂部掉落。

接下來的代碼將建立炸彈。 首先,咱們選擇一個隨機的x座標,老是在玩家相對的另外一側。 而後建立炸彈,將其設置爲與遊戲邊界碰撞,具備隨機速度。

總結

本文咱們學習瞭如何使用Phaser3開發第一個遊戲,主要包括加載資源、建立精靈、鍵盤控制、物體碰撞等等一些知識點,以後咱們能夠參考PHASER 3 EXAMPLES將這個簡單實例豐富起來。

參考

相關文章
相關標籤/搜索