[phaser3學習]使用phaser3作一款飛刀小遊戲

前言

phaser做爲一款流行的遊戲/動畫框架,受到不少web開發者的青睞,最近筆者在逛意大利開發者:emanueleferonato論壇的時候發現了這款小遊戲,因此就照着說明作了一下,在這裏記錄下來.html

開發準備

nodejs+npm
http-server插件
phaser腳本
飛刀和靶子的圖像html5

或者node

git clone https://github.com/YexChen/canvas_game.git

這個項目裏面有phaser的腳本和須要的圖像文件git

開始製做

搭建基本的phaser項目

建立一個基本的html文件,引入phaser文件github

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="js/phaser.js"></script>
</head>
<body>
  <script>
  
  </script>
</body>
</html>

別忘了在當前目錄下啓動http-server,啓動服務器.打開localhost:8080(或其餘端口)來查看項目web

啓動服務器

那麼如今,咱們須要幹什麼呢?
咱們如今須要在頁面加載時加載一個遊戲實例,代碼以下:npm

let game,knifeGroup
let gameConfig = {
  rotateSpeed : 5,
  throwSpeed : 150,
  minAngle : 10
}
window.onload = function(){
    game = new Phaser.Game({
        type: Phaser.CANVAS,
        width: 600,
        height: 700,
        backgroundColor: 0xdddddd,
        scene: [playGame]
    })
}

Phaser.Game 是phaser遊戲的構建函數,定義了實例的類型,寬高,背景顏色,場景等信息,你們能夠console.log(Phaser)看一下定義.
playGame是接下來的場景.
gameConfig 是遊戲的參數,方便修改canvas

接下來咱們定義一下咱們的場景:segmentfault

class playGame extends Phaser.Scene{
      constructor(){
        super("playGame")
      }

      preload(){

      }

      create(){

      }

      update(){

      }
    }

場景在遊戲中至關於戲曲中的每一幕,經過Phaser.Scene.start來進行調用.服務器

一個遊戲對象對應多個場景

在Phaser遊戲中,場景建立時會先運行preload函數,用來預加載圖片模型.而後運行create函數,執行初始化代碼,最後在每一步中調用update函數更新

預加載圖片

preload(){
        this.load.image("target","image/target.png")
        this.load.image("knife","image/knife.png")
}

在preload中加入以上代碼,把圖片註冊進來.

加載物體

create(){
    this.target = this.add.image(game.config.width/2,game.config.height/5 *2,"target").setScale(0.5,0.5)
    this.target.depth = 1
    this.knife = this.add.image(game.config.width/2,game.config.height/5*4,"knife").setScale(0.5,0.5)
    this.knifeGroup = this.add.group()
    console.log(this)
}

this.add.image經過提供的寬高和上一步中提供的url來生成Image類型的對象(和原生的不同!),
對象的原型鏈上的setScale(x,y)函數能夠調整圖像的縮放.
knifeGroup 是空的group對象,用來存放以後的飛刀集合

讓咱們的圖像動起來

修改update函數:

update(){
        this.target.angle += gameOptions.rotateSpeed
}

好的,至此咱們的項目基礎就結束了,接下來來作飛刀的邏輯吧

扔飛刀邏輯

咱們首先須要監聽用戶的鼠標事件,可使用Phaser內置的函數來實現,在created中加入:

this.canThrow = true
    this.input.on("pointerdown",this.throwKnife,this)

throwKnife 是咱們扔飛刀的處理函數,咱們寫在update後面:

throwKnife(){
    if(!this.canThrow){
      return
    }
    this.canThrow = false
    this.tweens.add({
      targets: [this.knife],
      y: this.target.y+this.knife.height/8 * 3,
      duration: gameOptions.throwSpeed,
      callbackScope: this,
      onComplete: function(tween){
        
      },
    })
  }

咱們在用戶按下鼠標左鍵時,檢測是否可扔,若是可扔的話就讓咱們的飛刀作一個tweens動畫,this.tweens是一個tweens管理器,官方文檔比較殘廢,部分參數以下:

target : tweens動畫目標
y : 目標的y座標,
duration: 動畫時間
callbackScope: 回調函數的this值
onComplete: 完成時的回調函數

飛刀能夠飛啦

飛刀插上去之後,咱們要判斷這個飛刀是否是和其它飛刀的重合,筆者這裏的判斷方式是在每個飛刀插到盤面上時把當前輪盤的角度保存下來,當下一次投擲的時候判斷當前盤面旋轉度和以往的旋轉度距離是否小於最小值,若是小於最小值就遊戲結束,不然就插一次飛刀.
靈魂畫師
咱們在上面的onComplete函數裏面寫下代碼:

let isLegal = true
let children = this.knifeGroup.getChildren()
for(var i=0;i<children.length;i++){
  let child = children[i]
  if(Math.abs(Phaser.Math.Angle.ShortestBetween(this.target.angle,child.impactAngle))<gameOptions.minAngle){
    isLegal = false
    break
  }
}
if(isLegal){
  this.canThrow =  true
  let newKnife = this.add.image(this.target.x,this.target.y+this.knife.height/8 * 3,"knife").setScale(0.5,0.5)
  newKnife.impactAngle = this.target.angle
  this.knifeGroup.add(newKnife)
  this.knife.y = game.config.height/5 * 4
}
else{
  this.tweens.add({
    targets: [this.knife],
    y: game.config.height+this.knife.height,
    rotation: 5,
    duration: gameOptions.throwSpeed*4,
    callbackScope: this,
    onComplete(tween){
      this.scene.start("playGame")
    }
  })
}

咱們判斷以前全部飛刀的impactAngle值,若是沒有和當前角度相差10度的,咱們就插入新的飛刀,不然播放動畫之後重啓遊戲.

更新每一把飛刀的位置

好的,咱們扔飛刀的邏輯已經完成了,接下來咱們只須要遍歷每個knifeGroup裏面的子飛刀的位置,並在update更新函數裏面更新他們的位置,遊戲就算作完了.
在update函數裏面添加:

update(){
    this.target.angle += gameOptions.rotateSpeed
    let children = this.knifeGroup.getChildren()
    for(var i=0;i< children.length;i++){
      let child = children[i]
      child.angle += gameOptions.rotateSpeed
      let ang = Phaser.Math.DegToRad(child.angle)
      child.x = this.target.x - Math.sin(ang) * this.target.width/4
      child.y = this.target.y + Math.cos(ang) * this.target.width/4
    }
  }

咱們在飛刀移動時計算每一步偏移的角度,從而判斷出子飛刀child的x,y位移.
圖片描述

咱們的小遊戲就作完了,完整代碼以下,順便作了下記分牌:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="js/phaser.js"></script>
</head>
<body>
  <script>
    let game,knifeGroup,scoreText,score
    let gameOptions = {
      rotateSpeed : 5,
      throwSpeed : 150,
      minAngle : 10
    }
    window.onload = function(){
      game = new Phaser.Game({
        type: Phaser.CANVAS,
        width: 600,
        height: 700,
        backgroundColor: 0xdddddd,
        scene: [playGame]
      })
    }
    class playGame extends Phaser.Scene{
      constructor(){
        super("playGame")
      }

      preload(){
        this.load.image("target","image/target.png")
        this.load.image("knife","image/knife.png")
      }

      create(){
        this.target = this.add.image(game.config.width/2,game.config.height/5 *2,"target").setScale(0.5,0.5)
        this.target.depth = 1
        this.knife = this.add.image(game.config.width/2,game.config.height/5*4,"knife").setScale(0.5,0.5)
        this.knifeGroup = this.add.group()
        console.log(this)
        this.canThrow = true
        this.input.on("pointerdown",this.throwKnife,this)
        score = 0
        scoreText = this.add.text(16,16,"score:0",{fontSize:"32px",fill:"#000"})
      }

      update(){
        this.target.angle += gameOptions.rotateSpeed
        let children = this.knifeGroup.getChildren()
        for(var i=0;i< children.length;i++){
          let child = children[i]
          child.angle += gameOptions.rotateSpeed
          let ang = Phaser.Math.DegToRad(child.angle)
          child.x = this.target.x - Math.sin(ang) * this.target.width/4
          child.y = this.target.y + Math.cos(ang) * this.target.width/4
        }
      }

      throwKnife(){
        if(!this.canThrow){
          return
        }
        this.canThrow = false
        this.tweens.add({
          targets: [this.knife],
          y: this.target.y+this.knife.height/8 * 3,
          duration: gameOptions.throwSpeed,
          callbackScope: this,
          onComplete: function(tween){
            let isLegal = true
            let children = this.knifeGroup.getChildren()
            for(var i=0;i<children.length;i++){
              let child = children[i]
              if(Math.abs(Phaser.Math.Angle.ShortestBetween(this.target.angle,child.impactAngle))<gameOptions.minAngle){
                isLegal = false
                break
              }
            }
            if(isLegal){
              this.canThrow =  true
              let newKnife = this.add.image(this.target.x,this.target.y+this.knife.height/8 * 3,"knife").setScale(0.5,0.5)
              newKnife.impactAngle = this.target.angle
              this.knifeGroup.add(newKnife)
              this.knife.y = game.config.height/5 * 4
              score += 100
              scoreText.setText("score:" +score)
            }
            else{
              this.tweens.add({
                targets: [this.knife],
                y: game.config.height+this.knife.height,
                rotation: 5,
                duration: gameOptions.throwSpeed*4,
                callbackScope: this,
                onComplete(tween){
                  this.scene.start("playGame")
                }
              })
            }

          },
        })
      }
    }
  </script>
</body>
</html>
相關文章
相關標籤/搜索