# Rotate image by 30°/frame for progress busy indicator

**URL:** <https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609>\
**Category:** Phaser 3\
**Created:** [August 3, 2024, 11:59am UTC](https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609 "2024-08-03T11:59:12Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![BdR](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/bdr/32/2621_2.png) [@BdR](https://phaser.discourse.group/u/BdR)\
**Post date:** [August 3, 2024, 11:59am UTC](https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609/1 "2024-08-03T11:59:12Z")

</div>

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](https://www.google.com/search?q=spinning+progress+indicator&udm=2).

However, using tweens doesn’t seem to work because it rotates too smoothly. I’ve created a code example using [this](https://labs.phaser.io/view.html?src=src%5Canimation%5Ccreate%20animation%20from%20canvas%20texture.js) and [this](https://labs.phaser.io/view.html?src=src%5Cgame%20objects%5Csprites%5Csprite%20rotation.js) examples. You can copy&paste it into the [Phaser3 sandbox](https://labs.phaser.io/edit.html)

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?

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

```

---

<div class="post-metadata">

**Author:** ![samme](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/samme/32/5275_2.png) [@samme](https://phaser.discourse.group/u/samme)\
**Post date:** [August 3, 2024, 2:23pm UTC](https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609/2 "2024-08-03T14:23:52Z")

</div>

Yes, you can use a stepped ease:

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

```

> **[Stepped ease tween Phaser Sandbox Entry](https://phaser.io/sandbox/sqstjbHD)**
>
> 360° in 12 steps

---

<div class="post-metadata">

**Author:** ![BdR](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/bdr/32/2621_2.png) [@BdR](https://phaser.discourse.group/u/BdR)\
**Post date:** [August 3, 2024, 4:02pm UTC](https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609/3 "2024-08-03T16:02:14Z")

</div>

Thanks, I changed my code to this and it worked 👍

```javascript
        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? 🤔 I had looked in the docs here [Tween](https://newdocs.phaser.io/docs/3.80.0/Phaser.Tweens.Tween), [Tweens](https://newdocs.phaser.io/docs/3.80.0/Phaser.Tweens) and [TweenBuilderConfig](https://newdocs.phaser.io/docs/3.80.0/Phaser.Types.Tweens.TweenBuilderConfig) but couldn’t find something that points to this.

---

<div class="post-metadata">

**Author:** ![samme](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/samme/32/5275_2.png) [@samme](https://phaser.discourse.group/u/samme)\
**Post date:** [August 3, 2024, 7:50pm UTC](https://phaser.discourse.group/t/rotate-image-by-30-frame-for-progress-busy-indicator/14609/4 "2024-08-03T19:50:29Z")

</div>

Some experimentation I think … `Stepped` is [Phaser.Math.Easing.Stepped(v, steps)](https://newdocs.phaser.io/docs/3.80.0/Phaser.Math.Easing#Stepped) and `easeParams` is any extra arguments. `Back`, `Elastic`, and `Stepped` have `easeParams`.
