【phaser.js学习笔记(2)】适配微信小游戏

微信小游戏目前还没有对phaser.js的官方支持,需要开发者自己进行适配。

1、phaser.js引擎适配

phaser小站在GitHub上发布了phaser2对微信小程序的适配(点击)。下面将使用这个引擎适配并将phaser.js学习笔记1中的例子移植到微信小游戏。

2、游戏案例的适配

案例的目录结构如下。


微信小游戏必须的文件主要有两个:game.js和game.json。game.js是程序的主入口,game.json是程序的配置项。案例中game.json如下。

{
  "deviceOrientation": "portrait"
}

上面的json中声明了游戏的默认方向是竖屏。

game.js如下。

import './js/libs/weapp-adapter.js'
import './js/main.js'

weapp-adapter.js是微信小游戏官方适配器,主要是因为微信小游戏内核没有BOM、DOM,没有挂载canvas的节点。main.js是我们自己编写的主入口,如下。

import Phaser from 'libs/phaser-wx.js'
import Scene from 'scene/index.js'

const game = new Phaser.Game({
  // 渲染类型
  renderer: Phaser.CANVAS,
  canvas: canvas,
  // type: Phaser.CANVAS,
  // 界面宽度,单位像素
  width: 750,
  // 界面高度
  height: 1334,
  // 背景色
  backgroundColor: 0x444444,
});

game.state.add('game', new Scene(game));
game.state.start('game');

phaser-wx.js是phaser小站的微信小游戏适配,直接引入lib文件。index.js是案例中主场景文件。在main.js文件中,声明Phaser.Game对象,添加场景并加载场景。

index.js如下。

import Phaser from '../libs/phaser-wx.js';

// 全局游戏设置
const gameOptions = {
  // 角速度,每帧多少度
  rotationSpeed: 3,
  // 投掷飞刀的时间,单位毫秒
  throwSpeed: 150,
  // 两刀间最小间隔角度
  minAngle: 15
}

export default class PlayGame extends Phaser.State {
  // 构造函数
  constructor(game) {
    super();
    this.game = game;
  }

  // 游戏载入前加载资源
  preload() {
    // 加载图片
    this.load.image("target", "target.png");
    this.load.image("knife", "knife.png");
  }

  // this.game.config.width / 2
  // 场景创建时执行
  create() {
    // 是否可以投掷飞刀
    this.canThrow = true;
    // 已投飞刀数组
    this.knifeGroup = this.add.group();
    // 增加一把刀
    this.knife = this.add.sprite(this.game.config.width / 2 - 20, this.game.config.height / 5 * 4, "knife");

    // 增加圆木
    this.target = this.add.sprite(this.game.config.width / 2, this.game.config.height / 5 * 1.8, "target");
    // 圆木在前,刀在后
    this.target.depth = 1;
    // 等待投掷飞刀
    // this.input.on("pointerdown", this.throwKnife, this);
    // this.input.touch.onTouchStart = this.throwKnife;
    this.input.onDown.add(this.throwKnife, this);
  }

  // 投掷飞刀方法
  throwKnife() {
    // 判断是否可以投掷
    if (this.canThrow) {
      // 投掷后一段时间不可再次投掷
      this.canThrow = false;
      this.game.add.tween(this.knife).to(
        { y: this.target.y + this.target.width / 4 },
        gameOptions.throwSpeed,
        Phaser.Easing.Sinusoidal.InOut,
        true)
        .onComplete.add(this.knifeTween, this);
    }
  }

  knifeTween() {
    // 判断飞刀是否可以插入圆木
    let legalHit = true;
    // 获取在圆木上旋转的飞刀数组
    const children = this.knifeGroup.children;
    // 遍历飞刀数组
    for (let i = 0; i < children.length; i++) {
      // 判断刀间夹角是否满足条件
      if (Math.abs(Phaser.Math.getShortestAngle(
        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 = this.game.config.height / 5 * 4;
    }
    else {
      // 掉下来的动画
      this.game.add.tween(this.knife).to(
        { 
          y: this.game.config.height + this.knife.height,
          rotation: 4
        },
        gameOptions.throwSpeed * 6,
        Phaser.Easing.Sinusoidal.InOut,
        true)
        .onComplete.add(this.newGame, this);
    }
  }

  newGame() {
    this.state.start('game');
  }

  // 每帧更新
  update() {
    // 修改锚点
    this.target.anchor.setTo(0.5, 0.5);
    // 旋转圆木
    this.target.angle += gameOptions.rotationSpeed;
    // 获取圆木上的飞刀数组
    // 修改获取数组方法->this.knifeGroup.children
    const children = this.knifeGroup.children;
    // 遍历飞刀数组
    for (let i = 0; i < children.length; i++) {
      // 旋转每个飞刀
      children[i].angle += gameOptions.rotationSpeed;
      // 度转弧度
      // phaser2修改为Phaser.Math.degToRad
      const radians = Phaser.Math.degToRad(children[i].angle + 90);
      // 计算x,y使其围绕中心旋转
      children[i].x = this.target.x + (this.target.width / 4) * Math.cos(radians);
      children[i].y = this.target.y + (this.target.width / 4) * Math.sin(radians);
    }
  }
}

以上与笔记1中有较大改动,一部分原因是因为微信小程序自身的限制,另一部分原因是因为适配器是基于phaser2,需要将笔记1中程序转换为phaser2。

构造函数中需要接受外部传入的game,并指定this.game = game。phaser2中要将pointerdown指定回调函数的方法改为:

this.input.onDown.add(this.throwKnife, this);

在throwKnife方法中,要将动画管理器tweens改为:

this.game.add.tween(this.knife).to(
  { y: this.target.y + this.target.width / 4 },
  gameOptions.throwSpeed,
  Phaser.Easing.Sinusoidal.InOut,
  true)
  .onComplete.add(this.knifeTween, this);

将飞刀动画单独封装为另一个方法knifeTween,当判断游戏结束时,播放飞刀掉落动画并开始新游戏。

newGame() {
  this.state.start('game');
}

phaser2中获取数组元素的方法为.children,度数转为弧度制方法改为Phaser.Math.degToRad。

微信小游戏截图如下。


完整程序见我的GitHub,git clone后使用微信web开发者工具打开并编译。

猜你喜欢

转载自blog.csdn.net/orangecsy/article/details/80591634