這是咱們第一個用Phaser3
開發遊戲的教程。咱們將學習如何建立一個小遊戲,包括玩家在平臺上跑和跳,收集星星並避免一些很差的行爲。html
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.CANVAS
,Phaser.WEBGL
或者Phaser.AUTO
。ide
這是要用於遊戲的渲染上下文。 推薦值爲Phaser.AUTO
,它會自動嘗試使用WebGL,可是若是瀏覽器或設備不支持WebGL,它將使用Canvas。 Phaser建立的Canvas元素將在調用腳本時添加到HTML文檔中,但也能夠根據須要在遊戲配置中指定一個父容器。函數
width
和height
屬性用於設置Phaser建立的Canvas元素的尺寸。上面代碼是800x600像素,能夠設置成任何想要的尺寸,也表明遊戲的分辨率。學習
配置對象的scene
屬性將在以後的內容更加詳細的介紹。動畫
讓咱們加載遊戲所須要的資源。這個能夠經過放在稱爲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'); }
讓咱們給遊戲添加一些平臺,
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,不然玩家就會從地面掉下去。
建立個名爲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幀向右跑。咱們定義了兩個動畫left
和right
。這是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);
如今咱們開始給咱們的遊戲加入一些鍵盤控制。Phaser
有內置的鍵盤管理器,一大好處就是咱們能夠用下面這樣方便的函數:
cursors = this.input.keyboard.createCursorKeys();
cursors
對象有四個屬性:up
,down
,left
,right
,它們都是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。
是時候給咱們的遊戲定個小目標了!咱們將在遊戲場景中添加一些星星,並讓玩家能夠去收集它們。在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
函數讓與玩家重疊了的星星不可見。
咱們可能還但願讓遊戲計分,並在遊戲中顯示。
建立兩個變量:
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);
爲了完善咱們的遊戲,是時候給遊戲增長一點挑戰了。想法是這樣的:當咱們收集完全部星星時,它將放出一顆炸彈,全部星星都會重現。 炸彈只會在水平方向隨機反彈,玩家觸碰到炸彈就會死。而咱們能夠再次收集星星,收集完它將釋放另外一枚炸彈。 因此,要在不死的狀況下得到儘量高的分數。
首先建立一個炸彈組和兩個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); } }
咱們用了Group
的countActive
方法來查看還剩多少星星。若是爲零,表示玩家已收集了全部星星,所以咱們迭代地啓用全部星星,並將其y座標置爲零。這將使全部星星再次從屏幕頂部掉落。
接下來的代碼將建立炸彈。 首先,咱們選擇一個隨機的x座標,老是在玩家相對的另外一側。 而後建立炸彈,將其設置爲與遊戲邊界碰撞,具備隨機速度。
本文咱們學習瞭如何使用Phaser3
開發第一個遊戲,主要包括加載資源、建立精靈、鍵盤控制、物體碰撞等等一些知識點,以後咱們能夠參考PHASER 3 EXAMPLES將這個簡單實例豐富起來。