Rotate image by 30°/frame for progress busy indicator

The tween animations in Phaser3 are pretty good and they can be used for a lot of things. Recently I wanted to add a typical progress indicator to show that the CPU opponent is preparing his move in a turn-based game.

So I want to spin an image with 12 segments in a circle and rotate it by steps of exactly 30° each animation frame (= 360° / 12) so you get the typical progress busy indicator.

However, using tweens doesn’t seem to work because it rotates too smoothly. I’ve created a code example using this and this examples. You can copy&paste it into the Phaser3 sandbox

Two questions about this code example:

  1. Is it possible to use Tweens to rotate an image in controlled steps of 30 degrees?
  2. If not using Tweens what is the best way to get this effect in Phaser3?
class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        //  Create a CanvasTexture that is 128 x 128 in size.
        const canvasFrame = this.textures.createCanvas('dynamicFrames', 128, 128);
        let ctx = canvasFrame.context;

        let spinradius = 48;

        ctx.fillStyle = '#ffff00';

        for (let a = 0; a < 360; a += 30)
        {
            var xpos = 64 + (spinradius * Math.cos(Phaser.Math.DegToRad(a)));
            var ypos = 64 + (spinradius * Math.sin(Phaser.Math.DegToRad(a)));

            var dotradius = a * 0.02;

            ctx.beginPath();
            ctx.arc(xpos, ypos, Math.max(1, dotradius), 0, Math.PI * 2, false);
            ctx.closePath();
            ctx.fill();
        }

        //  Call this if running under WebGL, or you'll see nothing change
        canvasFrame.refresh();

        //  Display the whole of our freshly baked sprite sheet
        this.add.image(0, 0, 'dynamicFrames', '__BASE').setOrigin(0);

        this._busysprite1 = this.add.image(100, 240, 'dynamicFrames', '__BASE').setOrigin(0.5);
        this._busysprite2 = this.add.image(300, 240, 'dynamicFrames', '__BASE').setOrigin(0.5);


        this._tw1 = this.tweens.add({
            targets: this._busysprite1,
            angle: { from: 0.0, to: 360.0 },
            duration: 1000,
            repeat: -1
        });

        this._tw2 = this.tweens.add({
            targets: this._busysprite2,
            angle: { from: 0.0, to: 360.0 },
            duration: 300,
            repeat: -1
        });
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Yes, you can use a stepped ease:

this.add.tween({
    // ...
    ease: 'Stepped',
    easeParams: [12]
});
1 Like

Thanks, I changed my code to this and it worked :+1:

        this._tw1 = this.tweens.add({
            targets: this._busysprite1,
            props: { angle: 360 },
            ease: 'Stepped',
            easeParams: [12],
            duration: 1000,
            repeat: -1
        });

But how did you know these parameters existed? :thinking: I had looked in the docs here Tween, Tweens and TweenBuilderConfig but couldn’t find something that points to this.

Some experimentation I think … Stepped is Phaser.Math.Easing.Stepped(v, steps) and easeParams is any extra arguments. Back, Elastic, and Stepped have easeParams.