Phaser3 ES6+ 入门教程(4)——动画

虽然,我们也可以在update()函数中,或使用其它方式写动画,但是Phaser中也提供了处理两类动画的方法。
Phaser3中,有补间动画(Tween)和逐帧动画(Animation)两种,使用这两类动画,我们可以很容地做出一些动态效果。

补间动画与逐帧动画的区别

我们知道,动画是由一段连续的静态图片快速播放组成的,其中的每一张图片叫做一帧。
补间动画,就是在一段时间内,将一个或者多个GameObject的某个属性(例如不透明度)从一个状态有一定规律地变成新的状态,例如从透明变成不透明,但是如果只有起始状态和结束状态两帧的话,那么看起来就是突然变化,没有过渡效果,会很突兀,而补间动画则是有过渡效果的,可以看成是两个状态之间有一些帧,在这些帧中,被改变的属性的值按照规律发生变化,例如一个Alpha从0变为1,中间可能会有0.1、0.2、0.3等值。所以叫做补间动画,自动补充中间的帧。
逐帧动画,就是每一帧都是不同的图片,没有规律可循。
简而言之,就是补间动画是在一段时间内动态调整显示物体的属性,从而形成动画的效果,逐帧动画就是每段时间显示一张静态的图片。

补间动画

补间动画,需要在场景类中使用Phaser.Scene.tweens属性中的方法进行添加,补间动画默认是会在添加后立刻播放的,不需要调用任何函数,当然也可以传入paused属性用来表示创建先不播放。
添加补间动画用的是add()方法,里面需要传入一个配置,大多数GameObject及其属性都可以成为补间动画的配置内容。
例如:

class Hello extends Phaser.GameObjects.Text{
  constructor(scene){
    super(scene);
    this.tweens.add({
      target:this,
      props:{
        alpha:0.5
      }
    })
  }
}

上面这个动画就是说每个Hello类的实例都会在1秒(为什么是1秒,因为默认是1秒,详见下文)中按照一定的算法将透明度从1慢慢地渐变到0.5.
在配置中,targets是必须传入的,其它都可选,该属性代表在该补间动画中要改变属性的GameObject(s),它可以是一个GameObject或者一个GameObject数组,也就是可以只改变一个GameObject,也可以改变多个GameObject。
其中,props属性设置在当前补间动画中,target需要改变的属性的状态,里面可以有多个属性,它们会同时发生变化。对于里面属性的键,就是target这个GameObject要改变的属性,它的值有多种写法,如果是一个数字,就代表在这个动画中,该属性从当前的最初状态,上述代码会将alpha从1变为0.5,过度到该属性这个值的这么一个状态,也可以写成:

alpha:{from:1,to:0.5}
// 或者
alpha:"-=0.5"

对于props中的属性,我们可以省略props,直接写在传入的大括号里面。
我们可以在配置中传入delay和duration属性,它们分别代表在动画开始前的延迟(也就是要等待多少毫秒之后再开始播放动画,默认是0,即不等待)和动画的时长(以毫秒为单位,默认是1000毫秒,即1秒)。
repeat属性代表动画是否要重复,默认是0,即不重复,也就是只播放1次,-1代表循环播放,1代表重复1次,即实际播放2次,2和以上同理。
然后,还有一个很重要的属性,ease代表过渡效果,也就是我们上面所说的补间动画的规律。默认值是Power0、除此之外,还有Linear、Cubic、Elastic、Bounce、Back等内置的规律可以选择,也可以自己写一个函数,各种效果自己查字典尝试吧。
另外,还有一个属性yoyo,默认是false,这个属性就是说动画要不要倒着来一遍,默认是动画结束后不会回到初始状态的,如果把该属性设置为true,则会动态地回到初始状态。至于为什么叫悠悠球呢?我估计大概是因为悠悠球它是会回到初始状态的。其它属性请看文档。
对于duration指的是播放一次的所用时间,所以如果设置为1000毫秒的话并且设置yoyo为true的话,可以视为播放2次,即1次是正着放,1次是倒着放,那么从最初状态回到最初状态应该是2000毫秒,即2秒。
补间动画可以设置paused属性,表示创建该动画后是否立刻播放,默认为true。

逐帧动画

逐帧动画,我们先要有一些图片,假设相对于HTML文件的路径分别是./images/img1.png./images/img2.png,那么我们在创建动画之前,需要先加载用到的图片,在场景类的相应方法中,

this.load.add("img1","./images/img1.png");
this.load.add("img2","./images/img2.png");

然后就可以通过使用Phaser.Scene.anims属性中的相关方法来进行动画的创建等处理。

this.anims.create({
key:"ani", // 动画名称
frames:[{frame:0,key:"img1",duration:1000},{"img2",duration:1000,frame:1}]
});

其中的key指的是动画的名称,不是需要用到的图片的名称,frames是该动画中的所有关键帧。
在每一个关键帧中,frame指的是关键帧位于第几帧,key是指该帧所用的图像的键,duration指该帧持续多少毫秒。
由于在创建动画时是不会设置显示坐标的,因此我们在播放动画时必须指定一个有动画属性的GameObject,它就会在该GameObject的位置进行播放,sprite是一个不错的选择,它也可以不传入纹理(下文就称之为空精灵了)。
一个例子,假设上面已经创建好了动画,在场景类中可以这么写:

let p=this.add.sprite(0,0).setOrigin(0,0); // 创建一个空精灵,其实setOrigin也不是必须的,只是为了看清楚效果可以这么设置一下
this.anims.play("ani",[p]);

相信大家已经猜到了,这样播放动画的话,动画中图片大小也会跟随空精灵缩放。
逐帧动画也有duration、delay等属性,不过逐帧动画默认是创建后不自动播放的。

精灵表

有时,一些动画的关键帧会按照一定的大小放在一张图片中,这样的图片就叫做精灵表(Sprite Sheet)(有时也称为纹理图集,但是在Phaser中这两个是不一样的)。
精灵表是指其中的每一张图片都具有相同的大小,这样我们就可以给其中的每一张图片一个从0开始算的唯一一个数字,这个数字就可以代表这张小图片;纹理图集是用帧名来代表一张小图片的。以下暂时只讲精灵表。
我们可以在场景类中通过类似于如下代码加载一张精灵表,

this.load.spritesheet("player","assets/player.png",{frameWidth:32,frameHeight:32});

这个函数共有4个参数,后面三个都是可选的。
上面的第一个参数就是随便取的一个键名,第二个参数是精灵表图片的路径,第三个参数就是帧的配置,第四个参数是xhr设置。
主要是第三个参数,精灵表中所谓的帧(Frame),其实也就是指里面的一张小图片,这里我们需要设置我们的精灵表图片中的每一张小图片的大小(也就是帧的宽度和高度,以px为单位)
一张精灵表就是一张图片,我们可以将其划分成若干张大小相同的图片,我们使用其中的帧就没有必要向上面那样写很多图片的键了,我们可以直接用一个函数去生成frames。
相关的函数有两个:this.anims.generateFrameNumbers和this.anims.generateFrameNames,顾名思义,精灵表是用数字来表示的,因此自然选择前者,而后者就是用于处理纹理图集的。
对于精灵表,我们只需要在frames属性中调用该函数即可,
该函数的第一个参数是精灵表的键名,第二个参数是一些配置,比如说start和end就是代表从第几帧到第几帧,默认是全部帧,帧是从0开始、从左往右、从上往下数的。

你可能感兴趣的:(Phaser3 ES6+ 入门教程(4)——动画)