精灵动画卡在第一帧?

Sprite animation stuck on first frame?

使用 Phaser 3,我预加载了一个 spritesheet 并创建了一些动画...

import {Scene} from 'phaser';

class BootScene extends Scene {
  constructor() {
    super("scene-boot");
  }

  preload() {
    this.load.spritesheet('px-hero', 'assets/sprites/px-hero.png', {
      frameWidth: 16,
      frameHeight: 16
    });
    // ...
  }

  create() {
    // ...
    this.anims.create({
      key: 'px-hero-idle',
      frames: this.anims.generateFrameNumbers('px-hero', {
        start: 0,
        end: 2
      }),
      frameRate: 10,
      repeat: -1
    });

    this.anims.create({
      key: 'px-hero-run',
      frames: this.anims.generateFrameNumbers('px-hero', {
        start: 3,
        end: 6
      }),
      frameRate: 10,
      repeat: -1
    });
    // ...
  }
}

export default BootScene;

然后在我的 Sprite class 中(正在 BootScene 链接到的另一个场景中实例化),我正在尝试播放动画...

import {GameObjects} from 'phaser';
const {Sprite} = GameObjects;

class PxHero extends Sprite {
  constructor(config) {
    super(config.scene, config.x, config.y, "px-hero");

    // Add self to scene's physics
    config.scene.physics.world.enable(this);
    config.scene.add.existing(this);

    this.scene = config.scene;

    this.keys = this.scene.input.keyboard.addKeys('W,S,A,D');

    this.speed = 100;
    this.jumpHeight = 300;
  }

  preUpdate(time, delta) {
    const {W, S, A, D} = this.keys;
    const {speed, jumpHeight, body} = this;
    const touchingGround = body.blocked.down;

    if (A.isDown) {
      this.body.setVelocityX(-speed);
      this.setFlipX(true);
    }
    else if (D.isDown) {
      this.body.setVelocityX(speed);
      this.setFlipX(false);
    }
    else {
      this.body.setVelocityX(0);
    }

    if (W.isDown && touchingGround) {
      this.body.setVelocityY(-jumpHeight);
    }

    // Animations
    if (touchingGround) {
      if (body.velocity.x !== 0) {
        this.anims.play('px-hero-run', true); // here
      }
      else {
        this.anims.play('px-hero-idle', true); // and here
      }
    }
  }
}

export default PxHero;

但由于某些原因,他们只播放了动画的第一帧,然后卡在那里。

有人遇到过这种情况吗?到目前为止,我还没有找到任何解决方案。

每帧动画基于 preUpdate 函数工作,在不调用 super.preUpdate 的情况下在该函数中执行您的操作并不是最好的主意。那是第一,第二代替preUpdate尝试使用update函数,并且不要忘记在其中调用super.update。 第三,尝试在不使用 preUpdateupdate 函数的情况下做您想做的事。如果你甚至需要使用 update 函数,你可以通过将场景中的侦听器设置为 update (Phaser.Scenes.Events.UPDATE) 事件来实现。这将使您的代码更加清晰易懂,并且您永远不会错误地损害 Phaser 的主要功能。

您的代码中发生的情况如下,在每一帧渲染中,您的游戏都会检查并决定从头开始 运行 动画,这就是为什么您只看到第一帧的原因,只是因为当它尝试向您展示下一帧,您告诉他再次开始播放动画)

export default class PxHero extends Phaser.GameObjects.Sprite{
  constructor(config) {
    super(config.scene, config.x, config.y, "px-hero");
    // Add self to scene's physics
    // ## you've `this` here too
    this.scene.add.existing(this);
    this.scene.physics.world.enable(this);
    this.prepare();
    this.setListeners();
  }

  prepare(){
    this.keys = this.scene.input.keyboard.addKeys('W,S,A,D');
    this.speed = 100;
    this.jumpHeight = 300;
  }

   setListeners(){
    this.scene.events.on(Phaser.Scenes.Events.UPDATE, this.handleMovement, this)
   }

  handleMovement() {
    const {W, S, A, D} = this.keys;
    const {speed, jumpHeight, body} = this;
    const touchingGround = body.blocked.down;
    switch(true){
     case A.isDown:
      this.body.setVelocityX(-speed);
      this.setFlipX(true);
     break;
     case D.isDown:
      this.body.setVelocityX(speed);
      this.setFlipX(false);
     break;
     case S.isDown:
      this.body.setVelocityX(0);
     break;
     case W.isDown && touchingGround:
      this.body.setVelocityY(-jumpHeight);
     break;
    }
    // Animations
    if (touchingGround) {
      if (body.velocity.x !== 0) {
        (!this.anims.isPlaying || this.anims.key !== 'px-her-run') && 
        this.anims.play('px-hero-run', true); // here
      }
      else {
        (!this.anims.isPlaying || this.anims.key !== 'px-her-idle') && 
        this.anims.play('px-hero-idle', true); // and here
      }
    }
  }
}