1. 程式人生 > >【phaser.js學習筆記(1)】使用phaser.js製作遊戲

【phaser.js學習筆記(1)】使用phaser.js製作遊戲

phaser.js是一款開源的HTML5遊戲框架,GitHub主頁上star超過了2萬。phaser.js支援使用JavaScript或TypeScript編寫遊戲,支援WebGL和Canvas渲染並可藉助第三方工具編譯成iOS,Android原生程式。phaser.js有兩個版本:phaser 3和phaser CE(Community Edition)。phaser CE基於phaser 3並由社群主導,phaser 3是下一代phaser。

1、安裝phaser 3

使用npm安裝

npm install phaser

使用時引入

import 'phaser';

2、建立遊戲物件

import 'phaser';

// 遊戲物件
let game;

// 全域性遊戲設定
const gameOptions = {
    // 角速度,每幀多少度
    rotationSpeed: 3,
    // 投擲飛刀的時間,單位毫秒
    throwSpeed: 150,
    // 兩刀間最小間隔角度
    minAngle: 15
}

// 載入時初始化
window.onload = function () {
  // 配置資訊
  const config = {
    // 渲染型別
    type: Phaser.CANVAS,
    // 介面寬度,單位畫素
    width: 750,
    // 介面高度
    height: 1334,
    // 背景色
    backgroundColor: 0x444444,
    // 場景
    scene: [playGame]
  };

  // 宣告遊戲物件
  game = new Phaser.Game(config);
  // 獲取焦點,調節介面大小
  window.focus();
  resize();
  window.addEventListener("resize", resize, false);
}

首先定義全域性遊戲設定,主要包括各種遊戲引數。之後在視窗載入時宣告配置資訊並將配置資訊傳入Phaser.Game建構函式,獲取焦點、調整視窗。

視窗調整方法如下。

// 調節介面大小
function resize() {
  const canvas = document.querySelector("canvas");
  const windowWidth = window.innerWidth;
  const windowHeight = window.innerHeight;
  const windowRatio = windowWidth / windowHeight;
  const gameRatio = game.config.width / game.config.height;
  if(windowRatio < gameRatio){
    canvas.style.width = windowWidth + "px";
    canvas.style.height = (windowWidth / gameRatio) + "px";
  }
  else{
    canvas.style.width = (windowHeight * gameRatio) + "px";
    canvas.style.height = windowHeight + "px";
  }
}

高度始終為視窗高度,寬度根據高度等比例調整。

3、建立遊戲主場景

// 遊戲主場景
class playGame extends Phaser.Scene {
  // 構造器
  constructor() {
    super("PlayGame");
  }

  // 遊戲載入前載入資源
  preload() {
    // 載入圖片
    this.load.image("target", "target.png");
    this.load.image("knife", "knife.png");
  }

  // 場景建立時執行
  create(){
    // 是否可以投擲飛刀
    this.canThrow = true;
    // 已投飛刀陣列
    this.knifeGroup = this.add.group();
    // 增加一把刀
    this.knife = this.add.sprite(game.config.width / 2, game.config.height / 5 * 4, "knife");
    // 增加圓木
    this.target = this.add.sprite(game.config.width / 2, 400, "target");
    // 圓木在前,刀在後
    this.target.depth = 1;
    // 等待投擲飛刀
    this.input.on("pointerdown", this.throwKnife, this);
  }

  // 投擲飛刀方法
  throwKnife() {
    // 判斷是否可以投擲
    if (this.canThrow) {
      // 投擲後一段時間不可再次投擲
      this.canThrow = false;
      // 飛刀動畫
      this.tweens.add({
        // 將到加入targets
        targets: [this.knife],
        // y方向目標
        y: this.target.y + this.target.width / 2,
        // 動畫時間
        duration: gameOptions.throwSpeed,
        // 回撥範圍
        callbackScope: this,
        // 動畫完成後的回撥函式
        onComplete: function (tween) {
          // 判斷飛刀是否可以插入圓木
          let legalHit = true;
          // 獲取在圓木上旋轉的飛刀陣列
          const children = this.knifeGroup.getChildren();
          // 遍歷飛刀陣列
          for (let i = 0; i < children.length; i++) {
            // 判斷刀間夾角是否滿足條件
            if(Math.abs(Phaser.Math.Angle.ShortestBetween(
              this.target.angle, 
              children[i].impactAngle)) < gameOptions.minAngle) {
              // 不滿足條件
              legalHit = false;
              break;
            }
          }
          // 判斷是否滿足條件
          if (legalHit) {
            // 可以繼續投擲
            this.canThrow = true;
            // 飛刀陣列中增加本次飛刀
            const knife = this.add.sprite(this.knife.x, this.knife.y, "knife");
            // 儲存目標角度
            knife.impactAngle = this.target.angle;
            // 新增到陣列
            this.knifeGroup.add(knife);
            // 新生成一把刀
            this.knife.y = game.config.height / 5 * 4;
          }
          else{
            // 掉下來的動畫
            this.tweens.add({
              // 加到targets陣列
              targets: [this.knife],
              // y方向目標
              y: game.config.height + this.knife.height,
              // 旋轉度數,弧度制
              rotation: 5,
              // 動畫時間
              duration: gameOptions.throwSpeed * 4,
              // 回撥範圍
              callbackScope: this,
              // 回撥函式
              onComplete: function(tween) {
                // 開始新一局
                this.scene.start("PlayGame")
              }
            });
          }
        }
      });
    }
  }
  
  // 每幀更新
  update() {
    // 旋轉圓木
    this.target.angle += gameOptions.rotationSpeed;
    // 獲取圓木上的飛刀陣列
    const children = this.knifeGroup.getChildren();
    // 遍歷飛刀陣列
    for (let i = 0; i < children.length; i++){
      // 旋轉每個飛刀
      children[i].angle += gameOptions.rotationSpeed;
      // 度轉弧度
      const radians = Phaser.Math.DegToRad(children[i].angle + 90);
      // 計算x,y使其圍繞中心旋轉
      children[i].x = this.target.x + (this.target.width / 2) * Math.cos(radians);
      children[i].y = this.target.y + (this.target.width / 2) * Math.sin(radians);
    }
  }
}

場景類中除建構函式外主要有4種方法:preload、create、throwKnife和update。preload主要用於在場景開始前預載入資源,如圖片、音樂等。create用於場景建立,在場景第一次被建立時呼叫一次,主要用於建立遊戲元素和初始化一些引數。throwKnife是create方法中pointerdown事件的回撥函式,當檢測到點選事件時,判斷是否可以投擲飛刀並呼叫tweens動畫管理器執行動畫。update每幀都會執行,主要用於新增動畫。

遊戲截圖如下。


完整程式見我的GitHub。git clone後先執行npm install安裝phaser,之後執行webpack打包,最後啟動http-server訪問index.html。