首先介绍phaser和animate.css
animate.css相信大部分做前端的同学都用过,是一款强大的css动画库,里面有上百种常用小动效。简单的加一个类名就可以让我们写的页面变得生动有趣起来。是由css的keyframes来实现的。
phaser是一款js游戏引擎,基于canvas和webgl。内置各种功能,比如精灵,spine,音视频,dragonBones,物理引擎,粒子效果等等。不向cocos,白鹭等是一个大生态全家桶,phaser很灵活,很容易插入到现有项目中。我之前深入使用过一段时间,怎么硕呢,如果你是个人玩票性质想写点有意思的小东西还是很推荐的,官方例子很多,照着例子就能拼出一个不错的游戏。但是如果要重度使用,做一个功能复杂,大而全的游戏,还是不推荐了,因为他的文档实在是太太太太烂了,我摸索了好久才弄明白它那自动生成的文档应该怎么看。还有就是一个隐藏bug,遇到了真是很难绕过去,比如cpu占用过高、资源清理不掉、切换场景时候全局注册插件失效、第三方插件的兼容等等。还有phaser生态不行,官方论坛发帖量少的可怜。另外phaser4马上要出了,估计又是一次断代更新。。。
为什么要写这个库?
因为phaser写一个小动效真的比较麻烦。
1.动效无非就是对元素进行缩放、位移、渐变。只要这三个变量组合得当就可以得出舒服的效果,我们要自己写,没有专业的ui、ue来帮我们走查,很难控制好时间和幅度,而animte.css中的所有动画,如果你读了一下源码,就知道一定是一个专业的动效师设计的。时间都精确到了小数点后两位,位移曲线也不是用的css默认提供的那些。
2.phaser是纯js的。用css写一个左右晃动的动画很简单,只需要写简单几行即可
@keyframes shake{
0%{ transform: translateX(-10px); }
100%{ transform: translateX(10px); }
}
.shake{
animation: shake 1s ease;
}
而phaser一个gameObject没有基于本身的坐标,我们要基于世界坐标来进行位移。并且也没有提供很多默认的量供选择,要进行手动转换,比如translateX
就需要对x坐标进行改变,translateY
需要对y坐标进行改变,rotate
需要改变angle
值。
实现步骤
1.对animate.css中所有css文件进行遍历转换为js对象,我写了一个postCSS插件来实现这个功能。
比如bounce动画原本是这样的
@keyframes bounce {
from,
20%,
53%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0);
}
40%,
43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -30px, 0) scaleY(1.1);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -15px, 0) scaleY(1.05);
}
80% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0) scaleY(0.95);
}
90% {
transform: translate3d(0, -4px, 0) scaleY(1.02);
}
}
.bounce {
animation-name: bounce;
transform-origin: center bottom;
}
转换完是这样的
module.exports = {
"common": {
"animation-name": "bounce",
"transform-origin": "center bottom"
},
"list": {
"0": [
{
"animation-timing-function": "cubic-bezier(0.215, 0.61, 0.355, 1)"
},
{
"transform": "translate3d(0, 0, 0)"
}
],
"20": [
{
"animation-timing-function": "cubic-bezier(0.215, 0.61, 0.355, 1)"
},
{
"transform": "translate3d(0, 0, 0)"
}
],
"40": [
{
"animation-timing-function": "cubic-bezier(0.755, 0.05, 0.855, 0.06)"
},
{
"transform": "translate3d(0, -30px, 0) scaleY(1.1)"
}
],
"43": [
{
"animation-timing-function": "cubic-bezier(0.755, 0.05, 0.855, 0.06)"
},
{
"transform": "translate3d(0, -30px, 0) scaleY(1.1)"
}
],
"53": [
{
"animation-timing-function": "cubic-bezier(0.215, 0.61, 0.355, 1)"
},
{
"transform": "translate3d(0, 0, 0)"
}
],
"70": [
{
"animation-timing-function": "cubic-bezier(0.755, 0.05, 0.855, 0.06)"
},
{
"transform": "translate3d(0, -15px, 0) scaleY(1.05)"
}
],
"80": [
{
"transition-timing-function": "cubic-bezier(0.215, 0.61, 0.355, 1)"
},
{
"transform": "translate3d(0, 0, 0) scaleY(0.95)"
}
],
"90": [
{
"transform": "translate3d(0, -4px, 0) scaleY(1.02)"
}
],
"100": [
{
"animation-timing-function": "cubic-bezier(0.215, 0.61, 0.355, 1)"
},
{
"transform": "translate3d(0, 0, 0)"
}
]
}
}
2.获得了包含css属性的对象后,就需要写一个转换的映射关系,将每个css属性和对应的值解析为phaser中tween动画支持的参数,然后调用tween动画来实现
映射关系代码在这里
此处有几个小难点。一是很多动画的timingFunc是二次贝塞尔曲线,需要使用bezier-easing
这个库来计算,才能保证动画速率保真。二是有些属性想要转换比较困难,我还没有想怎么去做(主要是懒)。已知的有transform-origin
和skew
,因为phaser的实例中没有关于这两个属性的概念。所以要自己手动实现。
3.关于结束状态,是forwards
还是backwards
要注意。
使用
DEMO