Jump to content

Using a simple spritesheet animation without key


strivinglife
 Share

Recommended Posts

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

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

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

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);

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...