strivinglife Posted June 6, 2018 Share Posted June 6, 2018 In Phaser 2 I was able to load a spritesheet and then define a simple animation that would loop through the spritesheet frames. // Defined in the preloader state. this.load.path = 'assets/avatar/'; for (let i = 1; i < 8; i++) { this.game.load.spritesheet('avatar_1_' + i, 'base/avatar_1_' + i +'.png', 16, 24); } // Use the spritesheet when adding the sprite. this.hero = this.game.add.sprite(x, y, 'avatar_1_' + style); // Define an animation and start playing it. this.hero.animations.add('stand'); this.hero.animations.play('stand', 5, true); With Phaser 3 I'm trying to understand how to convert this to the new animations model. // Still loading the spritesheets in the preloader. this.load.path = 'assets/avatar/'; for (let i = 1; i < 8; i++) { this.load.spritesheet('avatar_1_' + i, 'base/avatar_1_' + i +'.png', { frameWidth: 16, frameHeight: 24 }); } // This doesn't appear to have changed much either. this.body = this.scene.add.sprite(x, y, this.asset); // Now I've tried just creating the animation: this.anims.create({ key: 'stand', frameRate: 5, repeat: -1 }); // And then using it on the sprite, but it's complaining about that it: // Cannot read property 'frame' of undefined this.body.anims.play('stand'); Is it still possible to define an animation that just loops through the sprite's spritesheet's frames? If not, do I need to define an animation for every spritesheet I'm using? (Such as in the official Phaser 3 tutorial, https://phaser.io/tutorials/making-your-first-phaser-3-game/part5) Thanks! Link to comment Share on other sites More sharing options...
squilibob Posted June 6, 2018 Share Posted June 6, 2018 I would guess that you need to define which frames to use in your animation this.anims.create({ key: 'stand', frames: this.anims.generateFrameNumbers(this.asset, { start: 0, end: 10, first: 10 }), frameRate: 5, repeat: -1 }); Link to comment Share on other sites More sharing options...
strivinglife Posted June 6, 2018 Author Share Posted June 6, 2018 So, I'm using TypeScript and `this.asset` doesn't appear to be valid. If that's pseudo-code, then I think the issue is that each animated item would have a different asset to pull from. Link to comment Share on other sites More sharing options...
rich Posted June 7, 2018 Share Posted June 7, 2018 Just call generateFrameNumbers without passing anything but the key of the sprite sheet: frames: this.anims.generateFrameNumbers('spriteSheetKey') Link to comment Share on other sites More sharing options...
strivinglife Posted June 7, 2018 Author Share Posted June 7, 2018 That makes sense, but each actual Sprite may have a different spritesheet. So I've got my monsters definition (Character doesn't add anything of importance, but extends Phaser.GameObjects.Group, in case it matters), where you can supply the style of monster asset to use. // TypeScript import Character from "./Character"; export default class Monster extends Character { constructor(scene: Phaser.Scene, x: number, y: number, style: string) { super(scene); // The base doesn't actually move at all. var characterBase = this.scene.add.sprite(x, y, 'avatar_1_1'); this.asset = 'monsters_' + style; this.body = this.scene.add.sprite(x, y, this.asset); } } A preloader scene is adding these as: // Load monsters. this.load.path = 'assets/monsters/'; for (let i = 1; i <= 13; i++) { for (let j = 1; j <= 19; j++) { this.load.spritesheet('monsters_' + i + '_' + j, 'monsters_' + i + '_' + j + '.png', { frameWidth: 16, frameHeight: 24 }); } } (Spritesheets are all just two frames.) So I guess that means doing this (the 3.9.0 TS defs don't have a `generateFrameNumbers()` yet for what you've provided, hence the null)? for (let i = 1; i <= 13; i++) { for (let j = 1; j <= 19; j++) { this.anims.create({ key: 'stand', frames: this.anims.generateFrameNumbers('monsters_' + i + '_' + j, null), frameRate: 5, repeat: -1 }); } } That gets me the following, which is what I was expecting to see. Quote Invalid Animation Key, or Key already in use: stand So now I'm thinking each sprite needs to have a 'stand' set (`key: 'stand_monsters_' + i + '_' + j`)? Or am I misunderstanding and there's an easier way to write the code? Since you're on the thread, rich, here's more of what I'm trying to convert to Phaser 3, in case it helps with animation usage. // TypeScript - Phaser 2 import { MonsterRarity } from "../Enums"; import Character from "./Character"; export default class Monster extends Character { private monsterBody: Phaser.Sprite; private asset: string; public experience: number; public rarity: MonsterRarity; constructor(game: Phaser.Game, x: number, y: number, style: string) { super(game); // The base doesn't actually move at all. var monsterBase = this.game.add.sprite(x, y, 'avatar_1_1'); monsterBase.anchor.setTo(0.5); this.monsterBody = this.game.add.sprite(x, y, 'monsters_' + style); this.monsterBody.anchor.setTo(0.5); this.monsterBody.animations.add('stand'); this.monsterBody.animations.play('stand', 5, true); this.monsterBody.inputEnabled = true; this.monsterBody.events.onInputDown.add(this.logInfo, this); this.add(monsterBase); this.add(this.monsterBody); // Add this to the game immediately. game.add.existing(this); } logInfo() { console.log(this.monsterBody.key); } } Link to comment Share on other sites More sharing options...
strivinglife Posted June 13, 2018 Author Share Posted June 13, 2018 For what it's worth, doing the following did work: // TypeScript // Creating the animations. for (let i = 1; i <= 13; i++) { for (let j = 1; j <= 19; j++) { this.anims.create({ key: 'stand_monsters_' + i + '_' + j, frames: this.anims.generateFrameNumbers('monsters_' + i + '_' + j, null), frameRate: 5, repeat: -1 }); } } // Calling this when creating the custom objects. this.body.anims.play('stand_monsters_' + style); Is there a recommended best practice on where to setup the animations? Since they're global, that would suggest creating them somewhere that might get called once. For my setup with multiple scenes (with the called order as below), I'm thinking in the Preloader.create() function, instead of where I have it now, instead MainGame.create(). this.scene.add(Boot.Name, Boot); this.scene.add(Preloader.Name, Preloader); this.scene.add(MainMenuScene.Name, MainMenuScene); this.scene.add(MainGame.Name, MainGame); squilibob 1 Link to comment Share on other sites More sharing options...
Recommended Posts