Trying to learn animating through code. Questions about Modulus Operator.

Need a little help in understanding how this code is working. So I have an:

array of sprites. Lets say I have 5.
timethreshold which is the time between sprites
timer = not entirely sure.
int state which is what sprite will be called in array.
spriterenderer.

I am not fully comprehending everything in the update function. How is it animating the sprites? I get the % is a modulus operator; 10 % 7 = 3. Does that mean that state is equal to 3 so it will grab the sprite at element 3 as example? If so wouldn’t the state have to return to zero at some point? What is the point of the timer? I know that Time.time will track the amount of time passed since game has been started but what is the importance of tracking it.

public class AnimateToby : MonoBehaviour
{
    public Sprite [] tobsprite;
    float timeThreshold = 0.1f;
    float timer;
    int state = 0;
    SpriteRenderer spriteRenderer;

    void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }
    // Start is called before the first frame update
    void Start()
    {
       
    }

    // Update is called once per frame
    void Update()
    {
        if(Time.time > timer)
        {
            spriteRenderer.sprite = tobsprite[state % tobsprite.Length];
            state++;
            timer = Time.time + timeThreshold;
        }
    }
}

I think in this case the best explanation how things work is to go through the algorithm.

Let’s say the tobsprite array has 4 sprites and initial state value is 0:

// state = 0, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 0 % 4 = 0, so this assigns the first sprite in the array
state++ // state = 1

// next Update loop iteration
// state = 1, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 1 % 4 = 1, second sprite
state++ // state = 2

// next Update loop iteration
// state = 2, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 2 % 4 = 2, third sprite
state++ // state = 3

// next Update loop iteration
// state = 3, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 3 % 4 = 3, fourth sprite
state++ // state = 4

// next Update loop iteration
// state = 4, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 4 % 4 = 0, first sprite again, so you can see it loops the array
state++ // state = 5

// next Update loop iteration
// state = 5, tobsprite.Length = 4
spriteRenderer.sprite = tobsprite[state % tobsprite.Length]; // 5 % 4 = 1, second sprite again and so on..
state++ // state = 6

the timer variable is for slowing down the rate of sprite changes, without that the renderer will display different sprite every frame which could be simply too fast and depending on the framerate.

The timer works like this, values of course may vary and are for explanation purpose:

// initial values
// timeThreshold = 0.1
// timer = 0
// state = 0

if (Time.time > timer) // Time.time = 0, timer = 0, 0 > 0 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.01, timer = 0, 0.01 > 0 => true (sprite does change)
timer = Time.time + timeThreshold; // timer = 0.01 + 0.1 = 0.11
state++ // state = 1

// next iteration
if (Time.time > timer) // Time.time = 0.02, timer = 0.11, 0.02 > 0.11 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.04, timer = 0.11, 0.04 > 0.11 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.07, timer = 0.11, 0.07 > 0.11 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.09, timer = 0.11, 0.09 > 0.11 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.11, timer = 0.11, 0.11 > 0.11 => false (sprite does not change)

// next iteration
if (Time.time > timer) // Time.time = 0.12, timer = 0.11, 0.12 > 0.11 => true (sprite does change again, about 0.1s has passed so it's time-dependent, not frame-dependent)
timer = Time.time + timeThreshold; // timer = 0.12 + 0.1 = 0.22
state++ // state = 2

// next iteration
if (Time.time > timer) // Time.time = 0.13, timer = 0.22, 0.13 > 0.22 => false (sprite does not change and so on..)

I hope it helps.

1 Like

Incredible. Thank you sooooo much.