Jump to content

don't you think AnimationManager shoud be shareable


Kent Wood
 Share

Recommended Posts

Hello everyone

i was wonder is there a  way to make the AnimationManager instance shareable.

so that when i create a new instance of my sprite,i don't need to add animations once a Sprite instance create .

//this is the current way
class Player extends Phaser.Sprite
{

contractor(game)
{
super(game,0,0,'player');
this.animations.add('walk',[0,1,2,3]);
this.animations.add('run',[4,5,6,7]);
}
}

that's a waste of memory,and if i create a lot sprite instances same time,a big JAM would happen

so, i wanna this way

var animationManager=new Phaser.AnimationManager();
//add animations
animationManager.add('walk',[0,1,2,3]);
animationManager.add('run',[4,5,6,7]);

//then i create 2 players

var playerA=new Player(game)
playerA.animations=animationManager;

var playerB=new Player(game)
playerB.animations=animationManager;

//////////////even thought that animationManger instance shoud be a static variable and declare inside of the Player class///////////////

class Player extends Phaser.Sprite
{
static animationManager;
contractor(game)
{
super(game,0,0,'player');
if(Player.animationManager==null)
{
 //register animations here
}
this.animations=Player.animationManager;
}

}

 

Link to comment
Share on other sites

Did you run the profiler to see if this was a problem? How many sprites are you creating that you saw the problem? How many animations do these sprites have?

The reason I ask is because unless you have (I'd guess) tens of thousands of sprites, each with many animations, the amount of memory taken by each one having their own AnimationManager instance is probably smaller than one of the image files you'll use to draw those sprites. Unless you've measured otherwise, I don't think you need to worry about this.

Link to comment
Share on other sites

suppose i have a star spritesheet  (like the attachment show. also inclde the frames jsonarray)

i import it and create a animation dictionary from these code


//in main.ts
//load sprite sheet and jsonarray

 this.game.load.atlasJSONArray('star','./assets/stars.png',null,'./assets/stars.json')


//in Star.ts
//just record all the frame data in a static variable
//that is a table, which has each color as the key,and the frame as that color's animation frames

if(Star.starsFramesAni==null)
        {
            var starsFrameData:Phaser.FrameData=this.game.cache.getFrameData('star');
            var starsFramesAni:any={};
            starsFrameData.getFrames().forEach((value,index)=>{
                var key=value.name.match(/(.+?)0\d+/)[1];
                if(starsFramesAni[key]==null)
                    starsFramesAni[key]=[];
                else
                    starsFramesAni[key].push(index);
            })
            Star.starsFramesAni=starsFramesAni;
        }

//for each star instance,i should find thouth that animation table,and add the frames to this star instance
        var self=this;
        Object.keys(Star.starsFramesAni).forEach(key=>{
            self.animations.add(key,Star.starsFramesAni[key]);
        })
//so that,at last,i can play this specific color's animation

 this.animations.play(color,5,true);

if it is only star,program can handle that,even though it is still a little jam.

but when i try to make the star be a particle, like a star explosion effect.the program is totally crashed,

just because i have to add anmations again in each star particle instance

that's why i think the animation should be shared or just seprated from the sprite.

define somewhere,sprite just reference to the animations instance,and use it. no need to add it in each sprite constrator

 

stars.png

stars.json

Link to comment
Share on other sites

@Kent Wood can you post a working example?

There may be ways to share an AnimationManager instance, but you'd be sharing everything: all the sprites would play or stop the same sequence simultaneously. It doesn't sound like that's what you want.

Whether for Sprites or Particles, you need to add animations only once per object, probably during the create phase.

Link to comment
Share on other sites

thanks guys,at last i found the problem is i run "makeParticles" too frequently and incorrect, particles are born more and more, made a memory leak.

the effect i want make is i need my star has an explosion when it get touched, and the star has its own color, there is no way to change the particle instance to play definely animation, so i just make it once one color star reached and do it again when get another color star.

at last, i write a custom emitter extends from Phaser.Particles.Arcade.Emitter,and also,i modified Phaser.Particles.Arcade.Emitter,and add 2 methods -- beforeParticleEmit and afterParticleEmit, when one star particle emmited, i just change its color at first. coz used the exisit particle, no memory wasted

my code like this

 

ExpandEmitter.js

/**
 * override emitParticle,add 2 methods,beforeParticleEmit and afterParticleEmit
 */

Phaser.Particles.Arcade.Emitter.prototype.emitParticle = function (x, y, key, frame) {

    if (x === undefined) { x = null; }
    if (y === undefined) { y = null; }

    var particle = this.getFirstExists(false);

    if (particle === null)
    {
        return false;
    }

    var rnd = this.game.rnd;

    if (key !== undefined && frame !== undefined)
    {
        particle.loadTexture(key, frame);
    }
    else if (key !== undefined)
    {
        particle.loadTexture(key);
    }

    var emitX = this.emitX;
    var emitY = this.emitY;

    if (x !== null)
    {
        emitX = x;
    }
    else if (this.width > 1)
    {
        emitX = rnd.between(this.left, this.right);
    }

    if (y !== null)
    {
        emitY = y;
    }
    else if (this.height > 1)
    {
        emitY = rnd.between(this.top, this.bottom);
    }

    particle.reset(emitX, emitY);

    particle.angle = 0;
    particle.lifespan = this.lifespan;

    if (this.particleBringToTop)
    {
        this.bringToTop(particle);
    }
    else if (this.particleSendToBack)
    {
        this.sendToBack(particle);
    }

    if (this.autoScale)
    {
        particle.setScaleData(this.scaleData);
    }
    else if (this.minParticleScale !== 1 || this.maxParticleScale !== 1)
    {
        particle.scale.set(rnd.realInRange(this.minParticleScale, this.maxParticleScale));
    }
    else if ((this._minParticleScale.x !== this._maxParticleScale.x) || (this._minParticleScale.y !== this._maxParticleScale.y))
    {
        particle.scale.set(rnd.realInRange(this._minParticleScale.x, this._maxParticleScale.x), rnd.realInRange(this._minParticleScale.y, this._maxParticleScale.y));
    }

    if (frame === undefined)
    {
        if (Array.isArray(this._frames))
        {
            particle.frame = this.game.rnd.pick(this._frames);
        }
        else
        {
            particle.frame = this._frames;
        }
    }

    if (this.autoAlpha)
    {
        particle.setAlphaData(this.alphaData);
    }
    else
    {
        particle.alpha = rnd.realInRange(this.minParticleAlpha, this.maxParticleAlpha);
    }

    particle.blendMode = this.blendMode;

    var body = particle.body;

    body.updateBounds();

    body.bounce.copyFrom(this.bounce);
    body.drag.copyFrom(this.particleDrag);

    body.velocity.x = rnd.between(this.minParticleSpeed.x, this.maxParticleSpeed.x);
    body.velocity.y = rnd.between(this.minParticleSpeed.y, this.maxParticleSpeed.y);
    body.angularVelocity = rnd.between(this.minRotation, this.maxRotation);

    body.gravity.y = this.gravity;
    body.angularDrag = this.angularDrag;

    //add this line,for child Emitter class to override
    this.beforeParticleEmit(particle);

    particle.onEmit();

    //add this line,for child Emitter class to override
    this.afterParticleEmit(particle);

    return true;
};

//add these 2 methods
Phaser.Particles.Arcade.Emitter.prototype.beforeParticleEmit=function(particle)
{

}

Phaser.Particles.Arcade.Emitter.prototype.afterParticleEmit=function(particle)
{

}

(i strongly recommend to add these 2 methods in the offcial code)

 

Star.ts


class StarEmitter extends Phaser.Particles.Arcade.Emitter {
    currentColor = 'blue';

    //override start method,support color change
    start(explode?, lifespan?, frequency?, quantity?, forceQuantity?, color?) {

        if (color != undefined) {
            this.currentColor = color;
        }

        return super.start(explode, lifespan, frequency, quantity, forceQuantity);
    };

    beforeParticleEmit(particle) {
        //just add these lines,in order to call changeColor for normal StarParticle. (no need to do with RandomStarParticle instances)
        if (particle instanceof StarParticle) {
            if (!(particle instanceof RandomStarParticle)) {
                particle.changeColor(this.currentColor);
            }
        }
    }
}


export class StarParticle extends Phaser.Particle {
    constructor(game: Phaser.Game, x: number, y: number, key?: any, frame?: any) {
        super(game, x, y, 'star');
        this.anchor = new Phaser.Point(0.5, 0.5);

        var self = this;
        Star.colors.forEach(key => {
            self.animations.add(key, Star.starsFramesAni[key]);
        })
        this.visible = false;
    }

    changeColor(color) {
        this.animations.play(color, 5, true);
        this.visible = true;
    }
}

export class RandomStarParticle extends StarParticle {
    constructor(game: Phaser.Game, x: number, y: number, key?: any, frame?: any) {

        super(game, x, y);
        this.changeColor(Star.colors[game.rnd.integerInRange(0, 7)]);
    }
}


export class Star extends Phaser.Sprite {
    static starsFramesAni: any;
    static colors: any = ['blue', 'cyan', 'green', 'orange', 'purple', 'red', 'yellow'];

    static getColorIndex(color) {
        return Star.colors.indexOf(color);
    }

    color: string;

    constructor(game: any, x?: number, y?: number, color?: string) {
        super(game, x, y, 'star');

        if (color == null)
            color = Star.colors[this.game.rnd.integerInRange(0, 7)];
        this.anchor = new Phaser.Point(0.5, 0.5);
        this.color = color;

        //do some staff like "Phaser.Animation.generateFrameNames(key,0,7,'',4)", but cached the frames in a static variable
        if (Star.starsFramesAni == null) {
            var starsFrameData: Phaser.FrameData = this.game.cache.getFrameData('star');
            var starsFramesAni: any = {};
            starsFrameData.getFrames().forEach((value, index) => {
                var key = value.name.match(/(.+?)0\d+/)[1];
                if (starsFramesAni[key] == null)
                    starsFramesAni[key] = [];
                else
                    starsFramesAni[key].push(index);
            })
            Star.starsFramesAni = starsFramesAni;
        }

        //add animations for each star instance, ofcourse, load frames from the cache above
        var self = this;
        Star.colors.forEach(key => {
            self.animations.add(key, Star.starsFramesAni[key]);
        })

        this.animations.play(color, 5, true);


        //define one only particle emitter, for star explosion, there are many stars,but just one emitter,if some star need a explosion,just move the emitter location to that star
        if (Star.exploEmitter == null) {
            Star.exploEmitter = new StarEmitter(this.game, 0, 0, 400);
            this.game.add.existing(Star.exploEmitter);
            //use the custome particle class
            Star.exploEmitter.particleClass = StarParticle;
            //make particle instance inside the emitter
            Star.exploEmitter.makeParticles();
            Star.exploEmitter.setAlpha(1, 0.1, 2000, Phaser.Easing.Cubic.In);
            Star.exploEmitter.setScale(1, 0, 1, 0, 1000, Phaser.Easing.Cubic.In);
            Star.exploEmitter.gravity = 500;
        }
    }


    static exploEmitter: StarEmitter;

    explosion() {
        Star.exploEmitter.x = this.body.x;
        Star.exploEmitter.y = this.body.y;
        //make an explosion,and set a color,'coz i just override the start method
        Star.exploEmitter.start(true, 2000, null, 10, true, this.color);
        this.destroy();
    }

    update() {
        if ((this.y - 300) > this.game.camera.view.bottom) {
            this.destroy();
        }
    }

}

 

and check the demo effect

http://d2z4fez41b07b4.cloudfront.net/game/index.html

 

20161216114410.png

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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