什么是 Phaser ?

Phaser 是一款快速、免费以及开源 HTML5 游戏框架,它支持 WebGL 和 Canvas 两种渲染模式,能够在任何 Web 浏览器环境下运行,游戏能够经过第三方工具转为 iOS、Android 支持的 Native APP,容许使用 JavaScript 和 TypeScript 进行开发。html

目前 Phaser 存在三个版本:分别是 Phaser 2 版本、社区版本 Phaser CE 和最新版本 Phaser 3。git

关于 Phaser 3

2013 年 4 月 Richard Davey 在博客中首次公布了 Phaser,过了这么多年,已经从原先的 1.0 版本迭代到了目前的 2.6.2 正式版,Phaser 2 官方也宣布中止了维护、更新,转而由社区接手来负责维护、更新,衍生出来的版本称为社区版 Phaser CE。github

Phaser 2 的中止是由于将战场转移到了全新的 Phaser 3 版本。Phaser 3 于 2018 年 2 月 13 日发布到现在已经有至关长的一段时间了,它目前仍然处于开发阶段,一直未发布正式版,官方一直在努力解决该引擎存在的问题,文档和示例目前还处于完善阶段,但引擎的功能已很是完善了,已经能知足游戏开发的需求。算法

那么,Phaser 3 相比 Phaser 2 进步了什么?是否值得一用?下面就来说讲 Phaser 3 除了继承 Phaser 2 的优良基因外新增了哪些新特性,但愿能让你对 Phaser 3 有所了解。canvas

告别 Pixi.js

Phaser 2 一直采用开源的 Pixi 2 版本(Pixi.js 稳定版本为 v4)做为 2D 渲染引擎,在 Phaser 3 中已经告别依赖 Pixi,由于在 Phaser 3 官方有本身的特定需求,所以花费了大量的时间开发本身的渲染器,渲染器针对 Phaser 3 的工做原理进行构建,官方宣称性能各方面都明显比 Phaser 2 快不少,虽然目前官方暂时未给出具体的性能测试对比,最后官方说在将来会更注重性能以及兼容性方面的提高。数组

更便捷的层级设置 - setDepth

在 Phaser 2 中,调整游戏对象的层级并无像 CSS 设置 z-index 那样的方法。浏览器

经过 game.sprite.add 建立的游戏对象是根据顺序前后来决定层级关系的,越日后建立的层级越大,不少状况咱们都是动态建立的,这时元素就处于较高的层级,大部分状况不符合咱们的需求,Phaser 2 对层级设置有如下几种方案:框架

一、预先建立 Groupide

使用 game.add.group() 预先建立好 Group 来初始化层级,添加到 Group 的子元素层级就由 Group 来决定,由此能够将元素设置成不一样的层级,但这种方式不适合一些单元素,更适合层级分明的组元素。工具

1
2
3
4
5
6
7
let backLayer = game.add.group()
let middleLayer = game.add.group()
let frontLayer = game.add.group()

middleLayer.create(0, 0, 'middle')
backLayer.create(0, 0, 'back')
frontLayer.create(0, 0, 'front')

二、设置子元素层级

设置父元素下有设置子元素层级的 setChildIndex(),交换两个子元素层级的 swapChildren()、swap()

1
2
3
4
5
6
7
8
9
let bunny1 = game.add.sprite(0, 0, 'bunny1')
let bunny2 = game.add.sprite(0, 0, 'bunny2')

// 设置 bunny1 的层级为 3
game.world.setChildIndex(bunny1, 3)

// 交换 bunny1 和 bunny2 的层级
game.world.swapChildren(bunny1, bunny2)
game.world.swap(bunny1, bunny2)

三、层级置顶 bringToTop、置底 sendToBack

也有简单粗暴的将某个游戏对象置顶、置底层级的 bringToTop()sendToBack() 方法。

1
2
3
4
5
// 将 bunny1 置顶
game.world.bringToTop(bunny1)

// 将 bunny2 置底
game.world.sendToBack(bunny2)

四、新增 setDepth 方法

显然上面这些方法都不够简单易用,Phaser 3 中加入了 setDepth,只需给游戏对象调用 setDepth() 方法或直接设置 depth 属性便可,就像在 CSS 中设置 z-index 那样,轻松的控制场景中全部游戏对象的层级。

1
2
let bunny = game.add.sprite(0, 0, 'bunny')
bunny.depth = 1

功能更丰富的 - Camera

相机功能在 Phaser 3 中彻底重建了,由于相机功能在 Phaser 2 中的发挥很是有限,例如对相机执行一些 scale 操做就可能引起各类各样的问题,所以在 Phaser 3 中针对这些问题进行了优化,在 Phaser 3 依然保留跟随、移动、摇晃、淡化等相机功能,新增了 3D、缩放、旋转以及多组相机的功能。

一、3D 相机

以插件的形式存在,须要额外引入 camera3d.min.js 文件,能够实现 3D 的形变效果。

3d_camera

3D 相机 - 在线例子

二、缩放相机

能够对相机距离进行远近的拉伸。

scale_camera

缩放相机 - 在线例子

三、旋转相机

对相机进行旋转。

rotate_camera

旋转相机 - 在线例子

四、多组相机

建立多组相机,相机能够彼此相邻,也能够相互定位。

multi_camera

多组相机 - 在线例子

避免混淆 Scenes 替代 States

在 Phaser 2 中有一个 State Manager,你游戏中的每个部分都发生在一个独立的 State 中。Phaser 一次只能运行一个 State,全部的游戏级系统都会自动映射到此 State。当你使用 this.input 时,其实是访问了 Game.input 的引用。

在 Phaser 3 中再也不有 States 这样的东西了,如今它们统一称为 Scenes,这是一个更准确的说法,避免与 state machines 混淆。Scenes 能够被认为是一个独立的世界,它拥有本身的相机系统、显示列表、更新步骤、事件处理、物理系统等等。

Scale Manager 屏幕适配更新

最初官方将旧版本的 Phaser 2 Scale Manager 适配缩放功能移植到 Phaser 3,没过多久,官方发现目前的适配方案并不完美,由于自 Phaser 2 发布以来,浏览器已经发生了巨大的变化,已经不能知足如今的需求了,现在已经有更好的方法来处理画布缩放的问题了。

所以,官方对 Scale Manager 进行更新,使用较新的缩放方法(例如:CSS 属性 contains)来从新编写这块代码功能,还会为不支持此功能的浏览器提供一些兼容方案,而且会加入 iOS、Android 全屏 API 的支持。

不过,目前该功能还在开发中,它将在 Phaser 3.16 版本完成,因此官方 Demo 的缩放功能例子还暂时未能使用。

scaleManager

Scale Manager - 在线例子

游戏对象结构更平面

Phaser 2 使用了树状结构,有一个根对象,游戏中全部的游戏对象都来自于根对象,若是是组对象下面有子对象,子对象下有更多的子对象,在 Phaser 3 中则是彻底线性的结构,游戏对象不会包含其余对象,而且对象组不具备任何的位置或属性。

灵活性更强的 Tween 动画

Phaser 3 相比 Phaser 2 带来了更灵活、易用的 Tween 动画配置,下面是关于 Phaser 3 Tween 中可配置的参数一览。

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
// Phaser 3 可配置参数一览
this.tweens.add({
targets: [sprite1, sprite2, sprite3], // 容许单个或多个游戏对象
paused: false, // 初始是否为暂停状态
callbackScope: tween,

onStart: function() { }, // 开始时执行回调
onStartScope: callbackScope,
onStartParams: [],

delay: 0, // 第一次播放前的停顿时长

duration: 1000, // 动画总时长
ease: 'Linear', // 提供了多达 44 种动画速度曲线
easeParams: null,

onUpdate: function() { }, // 补间更新时执行回调
onUpdateScope: callbackScope,
onUpdateParams: [],

hold: 0, // 反向播放前停顿的时长
yoyo: false, // 是否反向播放
flipX: false, // 动画结束后,元素是否 X 轴翻转
flipY: false, // 动画结束后,元素是否 Y 轴翻转
onYoyo: function() { }, // 反向播放时执行回调
onYoyoScope: callbackScope,
onYoyoParams: [],

repeat: 0, //重复播放次数,-1 : infinity
onRepeat: function() { } // 重复播放时执行回调
onRepeatScope: callbackScope,
onRepeatParams: [],
repeatDelay: 0, // 重复播放以前停顿的时长

loop: -1, // 循环次数 -1 : infinity
onLoop: function() { }, // 循环播放时执行回调
onLoopScope: callbackScope,
onLoopParams: [],
loopDelay: 0, // 停顿多久的时长进入下一次循环

completeDelay: 0, // 动画完成前的停顿时间
onComplete: function () {}, // 动画结束后执行回调
onCompleteScope: callbackScope,
onCompleteParams: [],

// 属性值
x: '+=600',
y: 500,
rotation: ...,
angle: ...,
alpha: ...,
// ...

// 或者
props: {
x: { value: '+=600', duration: 3000, ease: 'Power2' }
y: { value: '500', duration: 1500, ease: 'Bounce.easeOut' }
},

// 又或者
props: {
x: {
duration: 400,
yoyo: true,
repeat: 8,
ease: 'Sine.easeInOut',
value: {
getEnd: function (target, key, value) {
destX -= 30
return destX
},
getStart: function (target, key, value) {
return value + 30
}
}
},
....
},
offset: null,
useFrames: false, // 使用帧或是毫秒
})

一、动画各阶段的 Delay

Phaser 3 在动画的完成、重复、循环、反向这四个阶段分别加入了 Delay 方法来让开发者控制,大大增长了动画编辑的灵活性。

completeDelay:在动画结束前须要暂停的时间
repeatDelay:循环动画开始前须要暂停的时间
loopDelay:延迟多久进入下一个循环
hold:动画在反向播放前的暂停时间

二、反向播放时回调 onYoyo

容许在动画进行反向播放时执行回调。

1
2
3
this.tweens.add({
onYoyo: function() { }
})

三、针对性配置 props

能够针对每个属性值进行单独的配置,例如动画时长、速度曲线等等。

1
2
3
4
5
6
this.tweens.add({
props: {
x: { value: '+=600', duration: 3000, ease: 'Power2' },
y: { value: '500', duration: 1500, ease: 'Bounce.easeOut' }
}
})

四、容许动画执行先后赋值 getEnd、getStart

getEnd()getStart() 容许在动画开始阶段和结束阶段设置补间动画的值。

例如我但愿游戏对象开始前在原来的位置先减 20px,再从这个位置向右移动 200 px。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
this.bunny = this.add.sprite(0, 0, 'bunny')

this.tweens.add({
tragets: [this.bunny],
props: {
x: {
duration: 2000,
value: {
getStart: function(target, key, value) {
// target -> 目标对象
// key -> 当前属性值
// value -> 当前的值
return value - 20
},
getEnd: function(target, key, value) {
return value + 200
}
}
}
}
})

游戏对象翻转后没法缩放

在 Phaser 2 中,若是须要对一个游戏对象进行水平或垂直的镜像翻转,一般使用 Sprite.scale.x = -1 来翻转游戏对象,这样就形成翻转后没法缩放的尴尬状况,在 Phaser 3 中改善了该问题,提供了 flipXflipY 属性专门来实现镜像翻转功能,这样既能够翻转又能够旋转游戏对象,另外不管游戏对象原点不管设置的值为多少,都始终以游戏对象的中心翻转。

1
2
3
let bunny = game.add.sprite(100, 100, 'bunny')
bunny.flipX = -1
bunny.scale.x = .9

新增 Spine 骨骼动画支持

在 Phaser 3 中将支持 Spine 建立 2D 骨骼动画,骨骼动画是将图片绑定到骨骼上,而后再控制骨骼来实现动画,2D 骨骼动画相比传统的逐帧动画优点在于:

  • 更小的文件体积:由于传统逐帧动画须要提供每一帧图片,Spine 须要保存动画数据以及骨骼所需的图片。
  • 美术需求:Spine 动画须要的美术资源更少。
  • 流畅性:Spine 动画使用差值算法计算中间帧,动画总能保持流畅效果。
  • 换肤:图片绑定在骨骼上,能轻松实现换肤效果。
  • 混合动画:容许多个动画进行混合,好比一个游戏人物一边开枪,同时跑动、跳跃、旋转。
  • 程序控制:能够经过代码来控制骨骼动画的状态。

Phaser Spine 会以一个独立的插件形式存在,像 Camera 3D 那样,而且 Phaser Spine 将会支持官方支持的全部功能。

phaser-spine

Phaser Spine 在线例子

困惑的 Anchor / Origin

anchor 在 Pixi 中是最容易被误解的属性之一,大多数人认为 anchor 是设置一个注册点,实际上它是设置了纹理偏移量,所以在 Phaser 3 中取消了该属性,取而代之的是 originXoriginYsetOrigin(x, y) 方法。

在 Phaser 3 中全部的游戏对象如今都是默认中心对齐,相似于 Phaser 2 设置了 anchor(0.5) 方法,若是但愿以左上角来定位能够经过 setOrigin(0) 方法来设置游戏对象。

origin

新增 Phaser Matter Collision 插件

在 Phaser 2 中已集成了三款物理引擎,分别是:Arcade、P2 和 Ninja,在 Phaser 3 中又新增了对 Matter.js 物理引擎的支持,Matter.js 是一款很是优秀的物理引擎,你能够到 Github - Matter.js 查看全部的 Demo 案例。官方为了能够更轻松的管理 Phaser 游戏引擎和 Matter.js 物理引擎的碰撞,在 Phaser 3 上对 Matter.js 的 API 封装推出了 phaser-matter.collision-plugin 插件来下降开发成本。

1
2
3
4
5
6
7
8
const player = this.matter.add.sprite(0, 0, 'player')
const trapDoor = this.matter.add.sprite(200, 0, 'door')

this.matterCollision.addOnCollideStart({
objectA: player,
objectB: trapDoor,
callback: () => console.log('Player touched door!')
})

collision-simple-demo

Phaser Matter Collision - 在线例子

新增 Shape 游戏对象

Phaser 3.13 版本新增一个名为 Shape 的游戏对象,扩展了 11 种不一样类型的 Shape(之后会新增更多),要比以前的 Graphics 对象性能更好,那么都支持哪些形状呢?下面是例子:

一、圆弧

容许你绘制圆形或部分圆形,能够设置开始和结束的角度,而且能够设置圆形平滑程度。

arc

圆弧 - 在线例子

二、椭圆

容许建立不一样宽高的椭圆形,能够被设置为填充或描边,一样能够设置椭圆的平滑程度。

ellipse

椭圆 - 在线例子

三、网格

我在开发游戏的过程当中,使用网格的状况较少,但其实网格是很是实用的,能够帮助你对齐游戏中的元素,例如背景、人物、图标等等。网格能够设置每一个单元格的宽高,单元格能够单一个颜色或者是交替的颜色,甚至能够设置单元格之间的间距,很是灵活好用。

grid

网格 - 在线例子

四、线

在任意两点之间进行绘制,而且能够给它们一个颜色和粗细程度。

line

线 - 在线例子

五、多边形

其实是一个点组成,这些点能够经过数组、对象的方式提供,而后进行填充和描边生成形状。

polygon

多边形 - 在线例子

六、矩形

简单的矩形,没什么好说的。

rectangle

矩形 - 在线例子

七、星形

容许建立一个星形,你能够控制星形上星星点的数量以及它的内半径和外半径。

star

星形 - 在线例子

八、三角形

容许建立三角形,能够设置填充和描边。

triangle

三角形 - 在线例子

九、Iso 三角形

能够绘制一个等角三角形,像金字塔那样,能够设置是否颠倒、宽高以及每个面的颜色,这是一个有趣的形状,包括下一个。

isotriangle

Iso 三角形 - 在线例子

十、Iso 盒子

与 Iso 三角形类似,它绘制一个等角的盒子,能够设置每一个面的颜色以及投影角度的颜色。

isoBox

代码也很是简单:

1
2
3
var t1 = this.add.isobox(150, 500, 200, 400, 0x00b9f2, 0x016fce, 0x028fdf)
var t2 = this.add.isobox(400, 500, 200, 400, 0xffe31f, 0xf2a022, 0xf8d80b)
var t3 = this.add.isobox(640, 500, 100, 100, 0x8dcb0e, 0x3f8403, 0x63a505)

Iso 盒子 - 在线例子

经过组成能够实现一些有趣的形状,好比一只小鸟或者是等距风格的景观。

isobird

小鸟 - 在线例子

isoland

风景 - 在线例子

尾巴

不管是 Phaser 2 或是 Phaser 3 你均可以使用,若是你追求稳定、保守能够选择 Phaser 2,若是你喜欢尝试新特性并愿意挖掘、不畏 Bug 能够选择 Phaser 3,它的 API 要比 CE 更简洁,更容易入手。另外,Phaser 3 目前还处于开发阶段,因此本篇关于 Phaser 3 特性的文章还会持续的更新。

最后,若是你有更好的建议或意见,欢迎在下方评论区留言,感谢您的阅读。

参考

Phaser World Back Issues

Phaser - HTML5 Game Framework

H5游戏开发
感谢您的阅读,本文由 凹凸实验室 版权全部。如若转载,请注明出处:凹凸实验室( https://aotu.io/notes/2018/12/23/phaser3/
上次更新:2019-04-20 19:28:31