How do I add an animated sprite that moves from point to point in an image object class?

I’m pretty new to Phaser let alone Phaser 3 and I’m not completely sure how to make this work. But as the title suggests, how would I make a sprite animated from inside the enemy object class? I believe I have to keep it inside the enemy object since the enemy object is being called into my scene class and inside the enemy object class has my the functions in which the enemy will take damage and die.

And now my predicament, I’m not entirely sure if how to implement the animation inside the object class, especially when the object is moving from point to point until it hits the last point(and then is removed off the gameboard).

var Enemy = new Phaser.Class({
 
        Extends: Phaser.GameObjects.Image,
 
        initialize:
 
        function Enemy (scene)
        {
            Phaser.GameObjects.Image.call(this, scene, 0, 0, 'spider');
            this.follower = { t: 0, vec: new Phaser.Math.Vector2() };
 
        },

        startOnPath: function ()
        {
            // set the t parameter at the start of the path
            this.follower.t = 0;
            
            // get x and y of the given t point            
            path.getPoint(this.follower.t, this.follower.vec);
            
            // set the x and y of our enemy to the received from the previous step
            this.setPosition(this.follower.vec.x, this.follower.vec.y);

            // set HP for each enemy
            this.hp = ENEMY_LIFE;

        },

        receiveDamage: function(damage) {
            this.hp -= BULLET_DAMAGE;           
            
            // if hp drops below 0 we deactivate this enemy
            if(this.hp <= 0) {
                this.setActive(false);
                this.setVisible(false);
                addScore(10);
                addMoney(15);
                endOfRoundTextPopulate(); // when there are no more enemies on the board round over text will display
            }
        },


        update: function (time, delta)
        {
            // move the t point along the path, 0 is the start and 0 is the end
            this.follower.t += ENEMY_SPEED * delta;
            
            // get the new x and y coordinates in vec
            enemyPosition = path.getPoint(this.follower.t, this.follower.vec);
            
            // update enemy x and y to the newly obtained x and y
            moveToPoint = this.setPosition(this.follower.vec.x, this.follower.vec.y);
       
            // if we have reached the end of the path, remove the enemy
            if (this.follower.t >= 1)
            {
                this.setActive(false);
                this.setVisible(false);
            };
            // lose a life when an enemy gets to the end point
            if (enemyPosition === path.getPoint(860, 580)){
                PLAYER_LIFE -= 1;
                textLife.text = 'Life: ' + PLAYER_LIFE;
                endOfRoundTextPopulate(); // when there are no more enemies on the board round over text will display
            }
        }
 
});

I have a sprite sheet that animates the ‘spider’ image to go straight, right, left and down. For testing purposes, I broke up the sprite sheet just for the walking straight animation. I could place the animation on the game board via create() function in the mainScene itself with…

        this.anims.create({
            key: 'walkStraight',
            frames: [
                { key: 'spider'},
                { key: 'spider2'},
                { key: 'spider3'},
                { key: 'spider4'},
                { key: 'spider5'},
                { key: 'spider6', duration: 100}
            ],
            frameRate: 8,
            repeat: -1

        });

        this.add.sprite(100, 655, 'spider').play('walkStraight');

But this doesn’t exactly move it from point to point. I’ve looked at the animation examples for Phaser 3, but so far I’ve gained no ground.

Any help in getting pointed in the right direction would be appreciated.

I think you can just do:

this.follower.anims.play('walkStraight');

I tried putting it on the startOnPath function but it threw up an error.

    startOnPath: function ()
    {
        // set the t parameter at the start of the path
        this.follower.t = 0;
        
        // get x and y of the given t point            
        path.getPoint(this.follower.t, this.follower.vec);
        
        // set the x and y of our enemy to the received from the previous step
        this.setPosition(this.follower.vec.x, this.follower.vec.y);

        // set HP for each enemy
        this.hp = ENEMY_LIFE;

        // animate the spider
        this.anims.create({
            key: 'walkStraight',
                frames: [
                    { key: 'spider'},
                    { key: 'spider2'},
                    { key: 'spider3'},
                    { key: 'spider4'},
                    { key: 'spider5'},
                    { key: 'spider6', duration: 100}
                ],
                frameRate: 8,
            repeat: -1

        });
        this.follower.anims.play('walkStraight');

    },

Oh, I see what your saying. You don’t want to create animations inside of game objects. They should be created in a scene, if you have a boot or preload scene that would be the place. They only need to be created once. After that you will get an error saying that the key is already in the cache. That’s why I would create them during a scene that is only run once in the game( like boot or preload, etc). Unless of course your game is only one scene that never restarts in which case it doesn’t matter and you can just throw all the animation creates at the start of the scene’s create method or something.

Once the animation is created it can be accessed by any sprite in the game through this.anims (where this is called inside the sprites code if extended as you do above). If you aren’t extending then from the scene you would call sprite.anims (where sprite is the variable name or property it is assigned to).

The reason that you are getting that error is that you are calling the animation system from an image but images don’t receive a map to it (only sprites). But your follower is a sprite so once you have the animation created you should have no problem doing:

this.follower.anims.play('walkStraight');

Hope that makes sense.

1 Like

That’s the thing to do, you create your animations once in “function create ()” and you play them later with, for example, player.anims.play('left', true);. See this example.
If you want to move a sprite from a point to another, maybe you could start by coding the movement without the animations.

1 Like

I think I’m following. Just to make sure I’ll re-iterate based of how I understood it.

Since I only have 1 scene, I’ve loaded the sprites into the preload function.
Then create the animation in the create function of the scene.
And since I have extend my Phaser.GameObjects.Image into a Phaser.Class object then I should be able to call these sprites with a key of ‘walkStraight’. With …

this.follower.anims.play(‘walkStraight’);

is that correct?

So I’m making a tower defense game and the enemy the turret and the bullet is all in it’s own phaser.class object.

var Enemy = new Phaser.Class({

    Extends: Phaser.GameObjects.Image,

var Turret = new Phaser.Class({

    Extends: Phaser.GameObjects.Image,

var Bullet = new Phaser.Class({

    Extends: Phaser.GameObjects.Image,

So the update function in my scene aligns with all three of those objects since I’m not doing any input and just allowing the objects to interact with themselves. The enemy class update function is where the enemy is getting it’s x, y vec move positions and is how this image object moves from point to point. Thus my predicament of how do I integrate an animation with the Enemy class object so that the animation can take place when the enemy begins to spawn.

just for reference here’s my main scene. (I’ve kinda stripped it down a bit so that it’s easier to read)

var mainScene = new Phaser.Class({

Extends: Phaser.Scene,

initialize:

function mainScene()
{
Phaser.Scene.call(this, ‘mainScene’);
},

preload: function() {
// load the game assets – enemy and turret atlas
this.load.image(‘enemy’, ‘assets/img/enemySprite.png’);
this.load.image(‘turret’, ‘assets/img/turretSprite.png’);
this.load.image(‘bg’, ‘assets/img/grass-background.png’);
this.load.image(‘laserBullet’, ‘assets/img/beam.png’);

  // enemy moving sprites
  this.load.path = 'assets/img/';
  this.load.image('spider', 'spider04_05.png');
  this.load.image('spider2', 'spider04_06.png');
  this.load.image('spider3', 'spider04_07.png');
  this.load.image('spider4', 'spider04_08.png');
  this.load.image('spider5', 'spider04_09.png');
  this.load.image('spider6', 'spider04_10.png');

},

create: function(){
// this graphics element is only for visualization,
// its not related to our path
let background = this.add.tileSprite(0, 0, this.width, this.height, ‘bg’);
let graphics = this.add.graphics();
drawGrid(graphics);

  // the path for our enemies
  // parameters are the start x and y of our path
  path = this.add.path(100, 655);
  path.lineTo(100, 138); // first turn
  path.lineTo(700, 138); // second turn
  path.lineTo(700, 300); // third turn
  path.lineTo(220, 300); // fourth turn
  path.lineTo(220, 580); // fifth turn
  path.lineTo(860, 580); // end
  
  graphics.lineStyle(0, 0x7575a3, 1);
  // visualize the path
  path.draw(graphics);

  // draw a circle around the towers for firing radius

  // create the animation
    this.anims.create({
        key: 'walkStraight',
            frames: [
                { key: 'spider'},
                { key: 'spider2'},
                { key: 'spider3'},
                { key: 'spider4'},
                { key: 'spider5'},
                { key: 'spider6', duration: 100}
            ],
            frameRate: 8,
        repeat: -1

    });


  // create enemies
  enemies = this.physics.add.group({ classType: Enemy, runChildUpdate: true });
  this.nextEnemy = 0;

  // user input
  turrets = this.add.group({ classType: Turret, runChildUpdate: true });
  this.input.on('pointerdown', placeTurret);

  // create bullets
  bullets = this.physics.add.group({ classType: Bullet, runChildUpdate: true });

  // bullets need to overlap with the enemy
  this.physics.add.overlap(enemies, bullets, damageEnemy);

  // Display the message box where the text will be held
  this.add.sprite(GAME_WIDTH -350, 437, 'blueBox');

  // Display title
  this.add.sprite(GAME_WIDTH -400, 40, 'title');

},

update: function(time, delta) {
if(!startGame){
console.log(‘Place a turret to start’);
}
else if(startGame) {
// if its time for the next enemy
if (time > this.nextEnemy && CURRENT_LVL_QTY < ENEMY_MAX_QTY) {
var enemy = enemies.get();
if (enemy) {
enemy.setActive(true);
enemy.setVisible(true);

  	            // place the enemy at the start of the path
  	            enemy.startOnPath();
  	            
  	            this.nextEnemy = time + SPAWN_TIME;
  	            ROUND_OVER_COUNTER ++;
  	            CURRENT_LVL_QTY ++;
  	        }

  	    } 
  }

}

});

I think you might have it but I want to make sure you know you need to assign the sprite to the follower property of the enemy class first before you can call the animation system on it from inside the enemy class.

Are there going to be multiple enemies, each with a follower? If so you will want a pool of follower sprites, probably assigned to a property on the scene so its accessible inside the enemy class( something like this.followers). Then inside the enemy class constructor method you would do this.follower = this.scene.followers.get();

Then you can do what you wanted in the startOnPath function and call the walkStraight animation on the follower sprite.

Hope that makes sense.

I think you need Sprites in place of Images.

From the API :
“The main difference between a Sprite and an Image Game Object is that you cannot animate Images.
As such, Sprites take a fraction longer to process and have a larger API footprint due to the Animation
Component. If you do not require animation then you can safely use Images to replace Sprites in all cases.”

Phaser.GameObjects. Image
Phaser.GameObjects. Sprite

This actually did the trick! I changed it from

Extends: Phaser.GameObjects.Image

to

Extends: Phaser.GameObjects.Sprite

I was able to then add

this.follower.anims.play(‘walkStraight’);

in my startOnPath function and it animated. Now I’m just trying to figure out how to get it to turn right after it gets to the first turn.

Glad to help !
You can rotate sprites with setAngle(), or flip them by changing flipX and flipY properties. I’m sure you will find everything among the examples and the API.