Phaser3.50 examples Animation 笔记

Table of Contents

这里记录的是 Phaser3.50 示例中的 Animation 部分 api 的用法。详情还是看 Phaser api 文档比较好。

Animation

60 fps Animation Test

class FpsAnimationTest extends Phaser.Scene {
  constructor() {
    super()
  }

  preload() {
    this.load.baseURL = globalConfig.baseUrl
    this.load.atlas('walker', 'assets/animations/walker.png', 'assets/animations/walker.json')
    this.load.image('sky', 'assets/skies/ms3-sky.png')
    this.load.image('trees', 'assets/skies/ms3-trees.png')
  }

  create() {
    this.bg = this.add.tileSprite(0, 38, 800, 296, 'sky')
      .setOrigin(0, 0)
    this.trees = this.add.tileSprite(0, 280, 800, 320, 'trees')
      .setOrigin(0, 0)
    
    const animConfig = {
      key: 'walk',
      frames: 'walker',
      frameRate: 60,
      repeat: -1
    }
    this.anims.create(animConfig)

    const sprite = this.add.sprite(400, 484, 'walker', 'frame_0000')
    sprite.play('walk')
  }

  update() {
    this.bg.tilePositionX -= 2
    this.trees.tilePositionX -= 6
  }
}

const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  backgroundColor: '#304858',
  parent: 'demo',
  scene: [FpsAnimationTest]
}

const game = new Phaser.Game(config)

this.add.tileSprite(x, y, width, height, texture [, frame])

创建瓦片精灵游戏对象(TileSprite Game Object)并添加到场景。宽高如果设置为 0,会默认使用纹理帧自身宽高。TileSprite 是可以移动的。移动后的空缺会自动平铺填充。比如 update 里设置 tilePositionX ,TileSprite 对象内部会对精灵图进行偏移,空缺部分会自动填充。TileSprite 可以用来制作动态背景。

this.anims.create(config)

创建动画并添加到动画管理器。动画是全局的,不属于具体的场景。每个场景都可以调用。

配置项说明
key动画的名称。
frames动画帧数据来源。
frameRate动画帧率。如果没有指定持续时间(duration)则默认 24。
duration动画持续时间。毫秒。默认根据帧率计算。
repeat重复次数。-1 无限制。默认 0

sprite.play(key [, ignoreIfPlaying] [, startFrame])

播放指定动画。

参数说明
key动画名称。
ignoreIfPlaying如果动画已经播放,忽略这次调用。默认 false
startFrame开始帧。默认 0

Add Animation Event

class AddAnimationEvent extends Phaser.Scene {
  constructor() {
    super()
  }

  preload() {
    this.load.baseURL = globalConfig.baseUrl
    this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json')
    this.y = 160
  }

  create() {
    this.add.text(400, 32, '点击创建动画', { color: '#00ff00' })
      .setOrigin(0.5, 0)
    // 每当往动画管理器里添加一个动画的时候都会调用下面的函数
    this.anims.on(Phaser.Animations.Events.ADD_ANIMATION, this.addAnimation, this)

    this.i = 0
    
    this.input.on('pointerup', function() {
      switch(this.i) {
        case 0:
          this.anims.create({
            key: 'diamond',
            frames: this.anims.generateFrameNames(
              'gems',
              {
                prefix: 'diamond_',
                end: 15,
                zeroPad: 4
              }
            ),
            repeat: -1
          })
          break
        case 1:
          this.anims.create({
            key: 'prism',
            frames: this.anims.generateFrameNames(
              'gems',
              {
                prefix: 'prism_',
                end: 6,
                zeroPad: 4
              }
            ),
            repeat: -1
          })
          break
        case 2:
          this.anims.create({
            key: 'ruby',
            frames: this.anims.generateFrameNames(
              'gems',
              {
                prefix: 'ruby_',
                end: 6,
                zeroPad: 4
              }
            ),
            repeat: -1
          })
          break
        case 3:
          this.anims.create({
            key: 'square',
            frames: this.anims.generateFrameNames(
              'gems',
              {
                prefix: 'square_',
                end: 14,
                zeroPad: 4
              }
            ),
            repeat: -1
          })
          break
      }
      this.i++
    }, this)
  }

  addAnimation(key) {
    this.add.sprite(400, this.y, 'gems')
      .play(key)
    this.y += 100
  }
}

this.anims.on(event, fn [, context])

添加动画事件。可用事件在 Phaser.Animations.Events 部分。

this.anims.generateFrameNames(key [, config])

根据纹理键名和配置对象生成动画帧对象。config 部分配置项如下:

配置项说明
prefix名称前缀
end最后帧数字
zeroPad帧数字长度。不足的左侧补零

比如有名为 gems 的纹理集包含 ruby_0001, ruby_0002 等帧,可以通过 this.anims.generateFrameNames(‘gems’, { prefix: ‘ruby_’, end: 6, zeroPad: 4 }) 来生产配置。

Add Frames To Existing Animation

class AddFramesToExistingAnimation extends Phaser.Scene {
  constructor() {
    super()
  }

  preload() {
    this.load.baseURL = globalConfig.baseUrl
    this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json')
    this.y = 160
  }

  create() {
    this.add.text(400, 32, '点击添加动画帧', { color: '#00ff00' })
      .setOrigin(0.5, 0)

    this.anims.create({
      key: 'diamond',
      frames: this.anims.generateFrameNames(
        'gems',
        {
          prefix: 'diamond_',
          end: 15,
          zeroPad: 4
        }
      ),
      repeat: -1
    })
    
    const group = this.add.group({
      key: 'gems',
      frame: 'diamond_0000',
      frameQuantity: 6 * 6
    })

    Phaser.Actions.GridAlign(
      group.getChildren(),
      {
        width: 6,
        height: 6,
        cellWidth: 64,
        cellHeight: 64,
        x: 240,
        y: 160
      }
    )

    group.playAnimation('diamond')
    
    this.input.once('pointerup', function() {
      const diamond = this.anims.get('diamond')

      // 添加新的动画帧到当前动画
      const newFrames = this.anims.generateFrameNames(
        'gems',
        {
          prefix: 'square_',
          end: 14,
          zeroPad: 4
        }
      )
      diamond.addFrame(newFrames)
    }, this)
  }
}

group.playAnimation(key [, startFrame])

每一个游戏对象都(按照指定帧数)播放指定的动画。

this.input.once(event, fn [, context])

一次事件监听。

this.anims.get(key)

返回指定动画。

diamond.addFrame(config)

根据帧配置对象数组追加动画帧。

AnimationProgress

class AnimationProgress extends Phaser.Scene {
  constructor() {
    super()
  }

  preload() {
    this.load.baseURL = globalConfig.baseUrl
    this.load.atlas('gems', 'assets/animations/diamond.png', 'assets/animations/diamond.json')
  }

  create() {
    this.anims.create({
      key: 'diamond',
      frames: this.anims.generateFrameNames(
        'gems',
        {
          prefix: 'diamond_',
          end: 15,
          zeroPad: 4
        }
      ),
      frameRate: 16,
      yoyo: true,
      repeat: -1,
      repeatDelay: 300
    })

    this.gem = this.add.sprite(400, 480, 'gems')
      .play('diamond')
      .setScale(4)
    
    this.debug = this.add.graphics()
  }

  update() {
    this.debug.clear()

    const size = 672

    this.debug.fillStyle(0x2d2d2d)
    this.debug.fillRect(64, 64, size, 48)

    this.debug.fillStyle(0x2dff2d)
    this.debug.fillRect(64, 64, size * this.gem.anims.getProgress(), 48)
  }
}

this.debug.fillRect(x, y, width, height)

this.gem.anims.getProgress()

this.gem 是精灵游戏对象,.anims 是该对象的动画控制器,.getProgress() 可以获取动画进度(0 ~ 1)。该方法不考虑 repeat 非零和 yoyo 为 true 的情况。如果 repeat 非零,想获取全局进度,需要使用 getTotalProgress() 方法。

Aesprite Animation

const config = {
  type: Phaser.AUTO,
  parent: 'demo',
  width: 800,
  height: 600,
  pixelArt: true,
  scene: {
    preload,
    create
  }
}

const game = new Phaser.Game(config)

function preload() {
  this.load.baseURL = globalConfig.baseUrl + 'assets/animations/aseprite/'
  this.load.aseprite('paladin', 'paladin.png', 'paladin.json')
}

function create() {
  const tags = this.anims.createFromAseprite('paladin')
  const sprite = this.add.sprite(500, 300).play({
    key: 'Magnum Break',
    repeat: -1
  }).setScale(6)

  for (let i = 0; i < tags.length; i++) {
    const label = this.add.text(32, 32 + i * 16, tags[i].key, { color: '#00ff00' })
    label.setInteractive()
  }

  this.input.on('gameobjectdown', function(pointer, obj) {
    console.log(obj)
    sprite.play({
      key: obj.text,
      repeat: -1
    })
  })

  this.input.on('gameobjectover', function(pointer, obj) {
    obj.setColor('#ff00ff')
  })

  this.input.on('gameobjectout', function(pointer, obj) {
    obj.setColor('#00ff00')
  })
}

3.24 文档里暂无关于 aseprite 的 api。可能要等 3.25 的文档。

游戏配置项里的 pixelArt

控制缩放模糊算法。如果为 true,则为线性过滤模式,图片放大会表现出锐利的像素风。否则会模糊。

label.setInteractive([shape] [, callback] [, dropZone])

将此游戏对象添加到 Input 管理器中,并支持相关事件。如果不传参数,默认事件区域为游戏对象的矩形包围框。如果是图形对象(Graphics)或者位图文字对象(BitmapText),必须提供 shape 参数和 callback 参数。

参数说明
shape响应事件的区域。默认矩形。
callback事件回调。如果提供了 shape 参数,此参数也许提供。
dropZone是否作为 drop 目标。默认 false。

Chained Animation

lancelot.anims.getName()

3.24 文档暂无。获取当前动画名称。

lancelot.playAfterRepeat(key [, repeatCount])

3.50 新增的方法。完成指定次数的当前动画后开始指定的动画。如果当前没有动画,立即开始指定的动画。

参数说明
key指定的动画。
repeatCount当前动画重复次数。默认 1.

lancelot.chain([key])

当前动画完成后开始指定的系列动画。

Create Animation From Canvas

this.textures.createCanvas(key [, width] [, height])

使用空白 canvas 创建纹理。宽高默认 256。

canvasFrame.add(name, sourceIndex, x, y, width, height)

给纹理(Phaser.Textures.Texture)加帧。

参数说明
key帧名称
sourceIndex属于纹理中的哪一个纹理资源(TextureSource)
x帧的横坐标
y帧的纵坐标
width帧宽
height帧高

Create Animation From Sprite Sheet

this.add.grid([x] [, y] [, width] [, height] [, cellWidth] [, cellHeight] [, fillColor] [, fillAlpha] [, outlineFillColor] [, outlineFillAlpha])

创建网格对象。

参数说明
x左上角横坐标。默认 0
y左上角纵坐标.默认 0
width网格宽度。默认 128
height网格高度。默认 128
cellWidth网格单元宽度。默认 32
cellHeight网格单元高度。默认 32
fillColor网格单元填充颜色。可选
fillAlpha网格单元填充透明度。可选
outlineFillColor网格单元之间线条颜色。可选
outlineFillAlpha网格单元之间线条颜色透明度。可选

Animation Create Animation On Sprite

Phaser.GameObjects.Sprite.anims.create()

直接在精灵对象上创建动画,此时创建的动画只属于这个精灵,不能全局调用。

Animation Cubes

Phaser.GameObjects.Group.children

群组的 children 属性是一个 Phaser.Structs.Set 类。该类有 iterate、each 等遍历方法。entries 属性为游戏对象合集。size 表示游戏对象数量。详情见 Phaser.Structs.Set 部分

this.anims.staggerPlay(key, children [, stagger])

对拥有动画组件的游戏对象适应给定的动画。每个动画按照 stagger 进行延迟播放。

参数说明
key动画名称
children游戏对象数组

Animation Export

获取动画的 json 字符串。

// 获取某个动画的 json 字符串
console.log(JSON.stringify(this.anims.get(key)))
// 这个返回的是一个对象
console.log(this.anims.get(key).toJSON())
// json 字符串
console.log(JSON.stringify(this.anims.toJSON(key)))
// 所有动画的 json 字符串
console.log(JSON.stringify(this.anims))

From Animation JSON

this.load.animation(key [, url] [, dataKey] [, xhrSettings])

添加动画配置 json 文件到当前加载队列。文件加载完成后会自动传给全局动画管理器的 fromJSON 方法。这个过程会在所有文件加载完毕后发生。

Mixed Animation

this.anims.addMix(animA, animB, delay)

从动画 animA 到动画 animB 时延迟 delay 毫秒。

Multi Atalas Animation

this.load.multiatlas(key [, atlasURL] [, path] [, baseURL] [, atlasXhrSettings])

加载多个纹理图集。纹理图集的图片地址在图集 json 文件中指定。path 是加载指定图片时的路径。

Pause All Animations

Phaser.GameObjects.Sprite.setDepth(value)

设置层级。也就是 z-index。

Phaser.GameObjects.Sprite.playAfterDelay(config, delay)

延迟指定时间后播放指定动画。

配置项说明
key动画的名称。
repeatDelay重复延迟。

this.anims.pauseAll()、this.anims.resumeAll()

暂停所有动画、继续所以动画。

Pause Animation Instances

// ……
const square = this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
// ……
square.pause()
square.resume()

Phaser.Animations.Animation.pause()、Phaser.Animations.Animation.resume()

暂停此类型动画的实例、继续此类型动画的实例。

Play After Delay

Phaser.GameObjects.Sprite.anims.playAfterDelay(key, delay)

Reverse Animation

Phaser.GameObjects.Sprite.playReverse(key)

this.anims.reverse()

Phaser.GameObjects.Text.setText(value)

设置文本。字符串数组会自动添加 \n 换行。

Show Animation Play Through

Phaser.GameObjects.Sprite.anims.restart()

重新开始动画。

Tween Timescale

this.tweens.add(config)

config 里有个 timeScale 的配置。{ from: 0.5, to: 2 }。但 3.24 文档里未找到说明,3.50-beta-11 的代码里也未发现。