從零到一:用Phaser.js寫意地開發小遊戲(Chapter 4 - 遊戲即將開始)

圖片描述

回顧

上一節咱們介紹了加載場景,並利用加載好的資源,豐富了開始界面。如今點擊屏幕後還是一片黑暗,那麼,這一節咱們就來完成遊戲最核心的場景——play。咱們要作的是一個接蘋果的遊戲,爲此咱們會加入物理引擎,會使用一些過渡動畫以及監聽觸摸事件等等。html

物理引擎

幾乎每個遊戲框架都必須具有一個甚至多個物理引擎供開發使用,使用物理引擎能夠實現例如碰撞、加減速運動、摩擦力等效果。Phaser很是人性化,提供了3個物理引擎供開發者使用,每一個引擎各有本身的特色。下面來簡單介紹一下:html5

Arcade

最簡單快速的物理引擎,由於只支持AABB式的碰撞,計算速度最快,實現簡單的物理碰撞、接觸、重力等效果最佳。web

關於AABB下面有幾個連接可讓你去理解,全稱是Axis-Aligned Bounding Box,直譯就是軸對稱盒。例如一張星星的圖片,儘管邊上不少透明的部分,但若是使用AABB來計算碰撞的話,則會用一個矩形將星星框住,這樣計算起來很是方便,但精度就比較低。如此一來咱們也能夠想到,用Arcade構建的body是不能夠發生形變的。算法

圖片描述

相關概念:segmentfault


P2

若是說Arcade是小而精,P2引擎則是大而全了。各類物理模型都可實現,諸如多邊形、彈簧、摩擦力、碰撞物體的材質、反彈係數等等均可以實現。儘管在性能上有必定消耗,畢竟要作更多複雜的運算,但爲了效果,咱們也很經常使用P2,做者引進P2也是因爲它的全面。框架

圖片描述


Ninja

至於Ninja,則是比較專一精確的多種模式的碰撞檢測。例如凹凸面的碰撞、平面和球的碰撞等等。日常比較少用,有興趣的能夠查看官方示例,另外,做者給出引進Ninja的理由是:dom

It's a really nice little physics system, supporting AABB and Circle vs. Tile collision, with lots of defs for sloping, convex and concave tile types. But that's all it does, it's not trying to be anything more really.

圖片描述

Stack Exchange - Game Development上關於Phaser三個引擎的介紹
Difference between Arcade, P2 and Ninja physics in Phaser

Phaser做者寫的,關於物理引擎的介紹:
Explaining Phaser 2's multiple physics systems


Box2D

咦?爲何沒有上面沒有提到Box2D?很遺憾,這個引擎是收費的,40刀,若是沒有特別大的需求,估計也用不上。

附上:很是有趣的官方示例,車掉坑裏就爬不起來了。

圖片描述


正式開始

第一步:先佈置好場景
  • 添加背景

  • 添加主角

  • 添加分數

  • 播放背景音樂

背景音樂的使用:

// 建立背景音樂實例
var bgMusic = game.add.audio('bgMusic');
// 循環播放
bgMusic.loopFull();

注意:

場景的佈置和開始場景差很少,在開始場景中咱們添加了背景音樂。會有人問,爲何不進入遊戲就自動播放,是由於移動端的瀏覽器,必需要用戶操做才能播放音頻。

Safari HTML5 Audio and Video Guide
Warning: To prevent unsolicited downloads over cellular networks at the user’s expense, embedded media cannot be played automatically in Safari on iOS—the user always initiates playback.

另外可參考:

segmentfault上的討論:HTML5的audio標籤設置了autoplay屬性在手機端出現的問題

示例代碼:https://jsfiddle.net/Vincent_...


第二步:讓你的主角動起來
  • 監聽滑動事件

  • 移動主角位置

主要使用的就是input的addMoveCallback方法:

// 監聽滑動事件
game.input.addMoveCallback(function(pointer, x, y, isTap) {
    if (!isTap) man.x = x;
});

第四個參數很是有用,能夠判斷是否爲點擊事件,若是是點擊就不移動主角。

clipboard.png

示例代碼:https://jsfiddle.net/Vincent_...


就這麼簡單?NO,NO,NO

很快你就會發覺在PC上主角一直跟着鼠標移動,根本沒法停下來!

其實緣由也很簡單,在PC端,Phaser的move事件對應的是mousemove;在移動端,對應的是touchmove。這兩個事件有什麼區別?主要區別就是touchmove必須手指觸摸屏幕並滑動纔會觸發,而mousemove則不須要點住鼠標,只須要移動鼠標就會觸發。

因而,咱們來修改一下代碼:

// 是否正在觸摸
var touching = false;
// 監聽按下事件
game.input.onDown.add(function() {
    touching = true;
});
// 監聽離開事件
game.input.onUp.add(function() {
    touching = false;
});
// 監聽滑動事件
game.input.addMoveCallback(function(pointer, x, y, isTap) {
    if (!isTap && touching) man.x = x;
});

Good!加入了觸摸標記之後,咱們監聽了按下和離開事件,在PC端和移動端的表現一致了!

示例代碼:https://jsfiddle.net/Vincent_...


這樣算完事了?NO,NO,NO

細心的你多測試了幾下,這時候發現了一個很是詭異的狀況,當開始點擊的時候,不是點在主角身上,主角就會瞬移過去!不難理解,由於咱們是直接設置主角的x座標,等於觸摸位置的x座標的。若是開始時x座標不在主角身上,就會在一瞬間移動到手指的位置。

因而,咱們又來修改一下代碼,很是簡單的一個方法:

// 監聽按下事件
game.input.onDown.add(function(pointer) {
    // 要判斷是否點住主角,避免瞬移
    if (Math.abs(pointer.x - man.x) < man.width / 2) touching = true;
});

上述代碼的意思就是,開始觸摸的位置必須在主角的最左邊到最右邊的x座標範圍內,纔算做開始觸摸,不然不算。

Excellent!如今能夠爲所欲爲地操控你的主角了!

示例代碼:https://jsfiddle.net/Vincent_...


第三步:讓蘋果掉下來吧
先來創造幾個蘋果看看

這裏用到了Phaser的group,實際上能夠理解成是一個數組,只不過更形象,組的經常使用方法:

  • add/addChild/addChildAt - 建立成員

  • countDead/countLiving - 統計成員

  • forEach/forEachAlive/forEachDead - 遍歷成員

  • remove/removeAll/removeChildAt - 刪除成員

  • create - 建立成員

  • bringToTop - 整個組的元素的圖層提到最上層

另外組自己也有x,y等屬性,也就是說,整個組的成員均可以根據組的偏移值而一塊兒偏移!另外組還提供了不少豐富的方法,活用組能夠達到事半功倍的效果。

// 添加蘋果組
var apples = game.add.group();
var green = apples.create(50, 0, 'green');
var red = apples.create(150, 0, 'red');
var yellow = apples.create(250, 0, 'yellow');

示例代碼:https://jsfiddle.net/Vincent_...


定時隨機創造蘋果

上面咱們看到有三種蘋果,那麼下面咱們來實現:每隔一段時間,隨機建立三種蘋果中的一種,而且擺放到不一樣的位置。

爲此咱們用到Phaser的timer,用於建立定時任務。會有人問爲何不用setInterval,setTimeout這些,是由於Phaser只要焦點離開了頁面,就會自動暫停遊戲,包括定時任務也會暫停,而setInterval和setTimeout則不會。

通常會用到addloop兩個方法,分別對應setTimeout和setInterval:

clipboard.png

clipboard.png

咱們修改一下代碼:

// 添加蘋果組
var apples = game.add.group();
// 蘋果類型
var appleTypes = ['green', 'red', 'yellow'];
var appleTimer = game.time.create(true);
appleTimer.loop(1000, function() {
    var x = Math.random() * game.world.width;
    var y = Math.random() * game.world.height;
    var type = appleTypes[Math.floor(Math.random() * appleTypes.length)];
    apples.create(x, y, type);
});
appleTimer.start();

如今每隔1秒就會在屏幕隨機位置出現一個蘋果了,並且種類是隨機的。

示例代碼:https://jsfiddle.net/Vincent_...


最後,咱們讓蘋果掉下來

這裏就要使用到物理引擎了,考慮到接蘋果的遊戲對碰撞精度要求不是很高,咱們選擇使用Arcade,也就是Phaser默認的物理引擎。

關鍵代碼:

// 開啓物理引擎
game.physics.startSystem(Phaser.Physics.Arcade);
game.physics.arcade.gravity.y = 300;
// 設置蘋果加入物理運動
game.physics.enable(apple);

因而,咱們繼續修改上面的代碼:

// 添加蘋果組
var apples = game.add.group();
// 蘋果類型
var appleTypes = ['green', 'red', 'yellow'];
var appleTimer = game.time.create(true);
appleTimer.loop(1000, function() {
    var x = Math.random() * game.world.width;
    var type = appleTypes[Math.floor(Math.random() * appleTypes.length)];
    var apple = apples.create(x, 0, type);
    // 設置蘋果大小
    var appleImg = game.cache.getImage(type);
    apple.width = game.world.width / 8;
    apple.height = apple.width / appleImg.width * appleImg.height;
    // 設置蘋果加入物理運動
    game.physics.enable(apple);
});
appleTimer.start();
// 開啓物理引擎
game.physics.startSystem(Phaser.Physics.Arcade);
game.physics.arcade.gravity.y = 300;

Perfect!如今滿天蘋果都會有了重力,加速掉向地上了。

示例代碼:https://jsfiddle.net/Vincent_...


小結

這一節內容比較多,咱們首先佈置了遊戲場景,加入了背景音樂。而後實現了對主角的操做,最後實現了蘋果的隨機掉落。通過這一節,萬事俱備只欠東風,下一節咱們就來完成這個遊戲的剩餘邏輯,好比接蘋果加分,接到炸彈或蘋果掉到地上游戲結束,還有加入更豐富的音效。

遊戲截圖:

clipboard.png

未完待續

回顧:
下一節:Chapter 5 - 遊戲大功告成
相關文章
相關標籤/搜索