【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如下。1
2
3{
"deviceOrientation": "portrait"
}
上面的json中声明了游戏的默认方向是竖屏。
game.js如下。1
2import './js/libs/weapp-adapter.js'
import './js/main.js'
weapp-adapter.js是微信小游戏官方适配器,主要是因为微信小游戏内核没有BOM、DOM,没有挂载canvas的节点。main.js是我们自己编写的主入口,如下。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import 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如下。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130import 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指定回调函数的方法改为:1
this.input.onDown.add(this.throwKnife, this);
在throwKnife方法中,要将动画管理器tweens改为:1
2
3
4
5
6this.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,当判断游戏结束时,播放飞刀掉落动画并开始新游戏。1
2
3newGame() {
this.state.start('game');
}
phaser2中获取数组元素的方法为.children,度数转为弧度制方法改为Phaser.Math.degToRad。
微信小游戏截图如下。
完整程序见我的GitHub,git clone后使用微信web开发者工具打开并编译。