微信小游戏目前还没有对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开发者工具打开并编译。