Phaser 編程技巧,phaser編程技巧

來源:互聯網
上載者:User

Phaser 編程技巧,phaser編程技巧

2015年2月6日

歡迎!

在連續幾周討論了平台跳躍遊戲的機制之後,我們也應該休息一下了。因此,本周的教程將基於論壇上經常談論的特性:網格運動,或者可以說得更加明確一點:如何像Pacman(譯者註:在紅白機上叫做吃豆子,或者小精靈)那樣在網格中移動。

我們本周討論的代碼可以讓玩家優雅地在瓦片地圖中移動,在很小的空間中轉彎。我們還將構建Pacman遊戲的核心代碼。

擷取原始碼

在這裡我只會著重高亮最重要的部分代碼。所以請先瀏覽一下代碼。如果你對一些代碼有疑問,你可以去論壇詢問。

運行/編輯汽車遊戲代碼可以到 jsbin 或者 codepen (譯者:國內使用者可訪問runjs)

運行/編輯Pacman代碼可以到jsbin or codepen (譯者:國內使用者可訪問runjs)

複製Phaser編程技巧代碼可以到git repo。

基礎設施的構建

我們需要一個玩家精靈和一張瓦片地圖。瓦片地圖包含來了關卡的布局。在這裡,我們在Tiled(譯者註:Tiled官網 http://www.mapeditor.org/)中畫了一個簡單的關卡:

這個軟體匯出了一個JSON檔案,然後和tileset一起匯入遊戲中。在 create 方法中我們產生了所有的對象:

this.map = this.add.tilemap('map');this.map.addTilesetImage('tiles', 'tiles');this.layer = this.map.createLayer('Tile Layer 1');this.map.setCollision(20, true, this.layer);this.car = this.add.sprite(48, 48, 'car');this.car.anchor.set(0.5);this.physics.arcade.enable(this.car);this.cursors = this.input.keyboard.createCursorKeys();this.move(Phaser.DOWN);

我們建立了地圖和圖層。碰撞被設定到20號瓦片上(暗灰色的磚塊)。汽車擺放在地圖的左上方,並且一開始就向下移動。.

在 update 函數中,我們檢測與瓦片地圖的碰撞:

this.physics.arcade.collide(this.car, this.layer);
當前的問題

玩家的地圖中的移動是一件需要解決的遊戲的挑戰。 儘管表面上這個看起來很簡單,但是實際上這需要玩家對象對周邊的情況有一個基本的瞭解。

玩家通過上下左右方向鍵來控制,當按鍵按下的時候,玩家開始向著對應的方向不停的移動,直到撞到牆壁或者按下其他方向鍵轉到其他方向。

在上面這個中,汽車即將接近一個交叉路口。如果使用者不按任何鍵,它將繼續向下移動。然而,如果正好在到達牆的右邊的空隙時按下右鍵,汽車就會向右開。

你被包圍了

所以,汽車如何知道他是否可以轉彎,什麼時候它應該轉彎呢?為了弄清楚這個,我們在汽車四周建立了4塊臨時瓦片。

在 update 函數中,我們將使用Phaser Tilemap類中內建的特性,此特性可用於掃描特殊的瓦片:

this.marker.x = this.math.snapToFloor(Math.floor(this.car.x), 32) / 32;this.marker.y = this.math.snapToFloor(Math.floor(this.car.y), 32) / 32;var i = this.layer.index;var x = this.marker.x;var y = this.marker.y;this.directions[Phaser.LEFT] = this.map.getTileLeft(i, x, y);this.directions[Phaser.RIGHT] = this.map.getTileRight(i, x, y);this.directions[Phaser.UP] = this.map.getTileAbove(i, x, y);this.directions[Phaser.DOWN] = this.map.getTileBelow(i, x, y);

Tilemap.getTileLeft 及其同類函數正是用於實現我們上面所說的功能:返回給定座標左邊的瓦片(如果沒有找到,則範圍null)。

因為這些函數是基於瓦片座標而不是像素的,所以我們首先要找出我們的汽車的地圖中的確切位置。我們對汽車的x和y值調用 Math.floor 函數,然後使用 Phaser.Math.snapToFloor 轉換為網格座標。這幾步就會得到汽車所在的確切瓦片。我們把結果存放在 marker 變數中。

周圍四塊瓦片存放在 directions 數組中。啟用渲染調試開關,我們能夠看到汽車知道他四周的相關資訊:

綠色的瓦片表示汽車可以安全的移動過去。紅色的表示是障礙物,白色的表示當前的移動方向。

放置一個轉彎標識

確認汽車是否可以轉彎是第一個要解決的事情。第二個要解決的是要告訴它什麼時候轉彎,因為我們想要它在快達到地圖合適的位置的時候轉彎,否則,它就會撞到牆上停止向前。

可以利用 checkDirection 函數來實現這個。

這個函數需要傳入一個參數:汽車將要轉彎的方向。這是一個Phaser方向常量,例如Phaser.LEFT 或 Phaser.DOWN

這個函數做的第一件事就判斷是否滿足以下任意一個條件:

  • 汽車的運動方向就是要轉向的那個方向

  • 那個方向上沒有瓦片

  • 那個方向上的瓦片不是一個“安全瓦片”(例如是一堵牆)

如果不滿足上面任意一個條件,接下來就會設定一個轉向標誌。這個標誌儲存在 turnPoint 中,這是個  Phaser.Point  對象,儲存了我們要汽車改變方向時所在的點的座標。

if (this.current === this.opposites[turnTo]){    this.move(turnTo);}else{    this.turning = turnTo;    this.turnPoint.x = (this.marker.x * this.gridsize) + (this.gridsize / 2);    this.turnPoint.y = (this.marker.y * this.gridsize) + (this.gridsize / 2);}

理想的轉彎點就是汽車當前正駛入的那個方塊的中心。在圖中可以看到一個黃點:

Warm and Fuzzy Inside

當 car.x 和 car.y 與轉彎點的值匹配時,汽車將轉向新的方向。如果汽車以每幀一個像素的速度移動的話,那沒問題。但是如果我們想要應用加速效果,或者其他改變汽車速度的方法,就會出問題。因為汽車的x/y座標將只會是與轉彎點接近而不是正好相等。

為瞭解決這個問題,我們使用了 Phaser.Math.fuzzyEqual 這個函數。它接受兩個值和一個閾值。它將比較兩個值,如果他們在差在閾值範圍內,他們被認為是相等:

this.math.fuzzyEqual(a, b, threshold)

這正滿足我們的需求。對於速度為150,我們的閾值可以設定為3。這個值足夠可以保證汽車不會跳過轉彎點。在 update 函數中,我們將檢查汽車是否已經到達了轉彎點。

當汽車到達時,我們將重新設定它的座標,同時重新設定汽車的剛體的座標,然後轉向新的方向:

this.car.x = this.turnPoint.x;this.car.y = this.turnPoint.y;this.car.body.reset(this.turnPoint.x, this.turnPoint.y);this.move(this.turning);this.turning = Phaser.NONE;

通過增加上面的這最後一部分代碼,你現在可以自由的在地圖上行駛,在拐角轉彎,隨意的的撞牆。

進入Pacman

讓我們來用上面的工作機制去複製一個Pacman。一開始的構建是一樣的:一個玩家精靈和一幅瓦片地圖。不同的在於我們的Pacman精靈是動態:

動畫由 Phaser Animation Manager 來處理:

this.pacman.animations.add('munch', [0, 1, 2, 1], 20, true);this.pacman.play('munch');

然而,在 move 函數中,我們需要將它的臉轉向新的方向:

this.pacman.scale.x = 1;this.pacman.angle = 0;if (direction === Phaser.LEFT){    this.pacman.scale.x = -1;}else if (direction === Phaser.UP){    this.pacman.angle = 270;}else if (direction === Phaser.DOWN){    this.pacman.angle = 90;}

我們重設了它的水平縮放和角度,然後基於它的方向進行調整。它的臉預設是朝右的,所以我們可以通過調整 scale.x 來讓它朝左。要讓它朝上或者朝下,就要進行旋轉。

另外一個重要的部分就是:Pacman實際上比網格要大,所以我們需要調整它的剛體以網格大小:

this.pacman.body.setSize(16, 16, 0, 0);

這一句是在精靈(32x32大小)的中心位置設定了一個16x16大小的剛體,這就完美的適應了16x16大小的網格。

豆子

Pacman 需要一些豆子來吃。豆子已經使用了7號瓦片畫到了瓦片地圖上。所以我們將使用Phaser特性來將所有的7號瓦片轉變為精靈。

this.dots = this.add.physicsGroup();this.map.createFromTiles(7, this.safetile, 'dot', this.layer, this.dots);this.dots.setAll('x', 6, false, false, 1);this.dots.setAll('y', 6, false, false, 1);

這裡首先擷取豆子瓦片,用空白瓦片(安全瓦片)來代替,然後為每一個空白瓦片在 dots 組中添加一個精靈。 setAll 函數用來調整豆子精靈的位置,添加6個像素的位移,因為他們只有4x4大小,這可以讓他們處於瓦片的中心。

Pacman與豆子之間的碰撞檢測在 update 函數中:

this.physics.arcade.overlap(this.pacman, this.dots, this.eatDot, null, this);

如果他們重疊了,就調用:

eatDot: function (pacman, dot) {    dot.kill();    if (this.dots.total === 0)    {        this.dots.callAll('revive');    }},

豆子被銷毀了。如果豆子組中的豆子數量變為零,我們要讓豆子重生。所以你可以重新把豆子吃光!

希望你可以看到,我們只用很少的代碼,我們現在實現了一個最基本的吃豆子遊戲。

Star Bug

基於上面這些代碼,我們利用這些概念將遊戲進一步演變。增加更多的關卡、會飛的敵人和大量的收藏品。最終的結果就是Star Bug遊戲:

這個遊戲將會出現在我們即將面世的 Phaser Book of Games 這本書中。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.