Спрайт анимации застрял на первом кадре? - PullRequest
0 голосов
/ 05 апреля 2020

Работая с Phaser 3, я предварительно загрузил таблицу спрайтов и создал несколько анимаций ...

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 (который создается в другой сцене, на которую ссылается 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;

Но по какой-то причине они просто воспроизводят первый кадр анимации, а затем застревают там.

Кто-нибудь сталкивался с этим раньше? ? Пока я не смог найти никаких решений.

1 Ответ

1 голос
/ 07 апреля 2020

Анимации для каждого кадра работают на основе функции preUpdate, это не лучшая идея сделать что-то свое в этой функции без вызова super.preUpdate. Это первое, второе вместо preUpdate попробуйте использовать update функцию, и не забудьте вызвать super.update в ней. И в-третьих, попробуйте делать то, что вы хотите, без использования функций preUpdate и update. Если вам даже нужно использовать функцию 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
      }
    }
  }
}

...