Phaser3 アニメーション

phaser

Phaser3 アニメーション

前回の記事

https://mijinc0.github.io/blog/post/20200821_phaser3_loading_scene/

基本

作成。作成したアニメーションは指定のキーでキャッシュに貯められる。

// this === Phaser.Scene

const anim = this.anims.create({
  key: 'test',
  frames: this.anims.generateFrameNumbers('spritesheetKey', {start: 0, end: 4}),
  frameRate: 1,
  repeat: 0,
});

再生。再生にはアニメーションオブジェクト(Phaser.Animations.Animationインスタンス)を指定する方法と、 キャッシュに登録されたキーで指定する方法があるが、アニメーションオブジェクトを指定しても内部でキーを取り出して キャッシュに登録されたアニメーションを取得しようとするので、やっていることは同じである。

これは言い換えれば、 キャッシュに登録されていないアニメーションオブジェクトをplay関数に渡してもアニメーションは再生されない ということである。

// this === Phaser.Scene

const sprite = this.add.sprite(100, 100, 'spritesheetKey');

const anim = this.anims.create({
  key: 'test',
  frames: this.anims.generateFrameNumbers('spritesheetKey', {start: 0, end: 4}),
  frameRate: 1,
  repeat: 0,
});

// 以下、再生

// キャッシュに登録したキーで指定
sprite.anims.play('test');

// アニメーションオブジェクトで指定
sprite.anims.play(animA);

つまり、以下のようなのはダメ。

// this === Phaser.Scene
const sprite = this.add.sprite(100, 100, 'spritesheetKey');

const anim = new Phaser.Animations.Animation(this.anims, 'test', {
  frames: this.anims.generateFrameNumbers('spritesheetKey', {start: 0, end: 4}),
  frameRate: 1,
  repeat: 0,
});

// 上記の方法ではキャッシュにアニメーションオブジェクトが登録されないのでダメ。
sprite.anims.play(anim);

GameObjects.Components.Animationplay関数とAnimationManagercreate関数の中身を覗いてみれば分かる。

https://github.com/photonstorm/phaser/blob/v3.22.0/src/gameobjects/components/Animation.js#L512

https://github.com/photonstorm/phaser/blob/acac51bf39c41d17eafb895a9004aeabfb2486da/src/animations/AnimationManager.js#L365

大事なのは以下の部分。

GameObjects.Components.Animation.play

if (key instanceof BaseAnimation)
{
    key = key.key;
}

// 上記urlより抜粋

AnimationManager.create

anim = new Animation(this, key, config);

this.anims.set(key, anim);

this.emit(Events.ADD_ANIMATION, key, anim);

// 上記urlより抜粋

ということで、普通に紹介されている方法でアニメーションは取り扱うように。

如何にしてアニメーションはupdateされるか

アニメーションは如何にしてupdateされるか、結論から言うと以下のようになっている。

  1. scene.addでspriteが追加されると、sceneのUpdateListにspriteが追加される
  2. 毎フレームactiveなsceneのUpdateListがupdateされる(sceneUpdate)
  3. UpdateListはupdateされると、登録されたオブジェクトのpreUpdateを順にcallする
  4. spriteのpreUpdateにはthis.anims.update(time, delta)が仕込まれている
  5. GameObjects.Components.Animationはupdateされると、現在の状態に応じてspriteに必要なテクスチャをセットする

ざっくり書くと以上のような流れでアニメーションは再生される。

以下、参考になる部分

https://github.com/photonstorm/phaser/blob/979ef9c71d024bde87f029219daf7203abc71e55/src/gameobjects/UpdateList.js#L145
https://github.com/photonstorm/phaser/blob/05c4a3304f393e51e468dc1734037f63347ac9cd/src/gameobjects/sprite/Sprite.js#L131
https://github.com/photonstorm/phaser/blob/v3.22.0/src/gameobjects/components/Animation.js#L971

如何にしてアニメーションは開始されるか

アニメーションの再生の起点となるのがGameObjects.Components.Animationplay関数。これは普段スプライトアニメーションを再生する時に使う関数。基本の部分で説明した関数。

これを呼ぶと、AnimatioManagerからキャッシュに登録されたアニメーションオブジェクトを取得すると同時に、 アニメーションオブジェクトの設定をGameObjects.Components.Animationの設定に反映する ということをする。これが意外と大事。

(ここまでの話で一旦参照になる部分)

https://github.com/photonstorm/phaser/blob/v3.22.0/src/gameobjects/components/Animation.js#L512
https://github.com/photonstorm/phaser/blob/v3.22.0/src/gameobjects/components/Animation.js#L583
https://github.com/photonstorm/phaser/blob/v3.22.0/src/gameobjects/components/Animation.js#L410
https://github.com/photonstorm/phaser/blob/v3.22.0/src/animations/AnimationManager.js#L437
https://github.com/photonstorm/phaser/blob/v3.22.0/src/animations/Animation.js#L480

キャッシュに登録されたアニメーションオブジェクトの設定は、再生開始時にGameObjects.Components.Animationに設定を写す。設定を映されたGameObjects.Components.Animationは自身の設定に従ってアニメーションを再生する。より感覚的に言えば キャッシュに登録されたアニメーションオブジェクト内の設定はデフォルトの設定、後からアニメーションの設定を変えたければplay関数実行後にGameObjects.Components.Animation(つまりsprite.anims)の設定を変更する事 、ということである。

以下が具体的な説明。

// this === Phaser.Scene

const sprite = this.add.sprite(100, 100, 'spritesheetKey');

// 作成時の設定はデフォルトの設定になる
const anim = this.anims.create({
  key: 'test',
  frames: this.anims.generateFrameNumbers('spritesheetKey', {start: 0, end: 4}),
  frameRate: 1,
  repeat: 0,
});

// ここでデフォルトの設定がsprite.animsに写る
sprite.anims.play('test');
// 後から設定を変えたければplay関数語に設定を変更すること
sprite.anims.repeat = 1;