DEV Community

Cover image for Project: Random Number Generator But Excluding The Previous Entry
Kat
Kat

Posted on

Project: Random Number Generator But Excluding The Previous Entry

Contents

Introduction

Sometimes you just need a random number. But not that random. I find that, when having numbers flash randomly on the screen for a video effect, that it works best when there are no repeats in the sequence. This can happen from time to time, especially if your range isn't that large, when using the random() function. While it is perfectly understandable for what the function does, it still makes our animation look a little staggered.

So I set myself the challenge of writing an expression that excludes the previous number from the random generation, and thought about how this could be applied to projects in the future.

Here's what I did.

random()

Let's start at the beginning. If you need a random number in After Effects, using the random(minVal, maxVal) function is a great place to start. By inputting a minimum and maximum value into the function, After Effects will generate a random number from within those bounds every frame.

random(1, 11)
Enter fullscreen mode Exit fullscreen mode

image showing the number the random function produced

That's a lot of decimal places! Since I just want integers, I use Math.floor to round the numbers down. Because the range of the random function is 1 to 11, this method will produce a random number between 1 and 10, since the top of the range is not included.

Math.floor(random(1, 11))
Enter fullscreen mode Exit fullscreen mode

Image showing the number of the random function wrapped inside the math.floor function

Much better. However I want to control how often the number changes, not on every frame. To do that, we need to use the seedRandom(seed, timeless?) function. This function requires 2 arguments, the seed, and whether or not timeless mode is set to true or false. By default, timeless is set to false, meaning that the random function will generate a new number each frame. However, if we set this to true, the random function will only generate a number once.

seedRandom(0, timeless = true);
Math.floor(random(1, 11))
Enter fullscreen mode Exit fullscreen mode

Now that the number only generates once, I can manipulate the seed number using a simple for loop to control how often the number generates. If you're unfamiliar with for loops I've written up an article about them in depth here.

Here is my basic loop:

let counter = 0;
let num = 0;

for (i = 0; time >= i; i++) {
    seedRandom(counter, timeless = true);
    num = Math.floor(random(1, 11));
    counter++
}

num
Enter fullscreen mode Exit fullscreen mode

First, I set up the variables counter to track the changes in time, and num, to store my random number. The loop is set to add 1 to i whenever time >= i, meaning the loop updates every second the timeline is active. Everytime the loop refreshes, seedRandom is updated by the change in counter's value, producing a new random number when num is called at the end of the expression.

GIF of numbers changing every second

By adjusting i in the for loop, we can control how often the number changes per second. For instance, if we were to change the argument to time >= i/2, the number will change twice every second instead of once.

Now that we have an expression which allows us to generate a new random number at an interval of our choosing, it needs to be amended to ensure we never have any duplicate entries one after another.

Creating An Array

In order for After Effects to be able to compare numbers, the numbers need to be saved somewhere for After Effects to review. So I decided to save my random numbers to an array as they are generated over time.

let counter = 0;
let num = 0;
let allNum = [];

for (i = 0; time >= i/2; i++) {
    seedRandom(counter, timeless = true);
    num = Math.floor(random(1, 11));
    allNum.push(num);
    counter++
}

allNum
Enter fullscreen mode Exit fullscreen mode

I create the variable allNum outside of my for loop, and then push() the number currently inside of our num variable to the array. This saves each number as it is generated across the timeline.

By calling allNum at the end, we are able to see all the numbers in our array by the end of our timeline:

Image of all numbers in the random array

As you can see, this is less than ideal with a set of double 7s and triple 1s in our sequence. If we called num and played our timeline, the doubles could make it look as if our timeline had frozen or stopped animating. Therefore, we need to ensure that our expression takes into account the previous entry of this array, and excludes it from being added again in such quick succession.

while Loop

I found the answer to this was to add a while loop within the existing for loop.

A while loop allows you to specify a command while certain criteria is true. In this case, we want it to be active while the current value of num matches the previous value, listed in our allNum array.

while (num == allNum[counter - 1]) num = Math.floor(random(1, 11));
Enter fullscreen mode Exit fullscreen mode

While the current value of num matches the previous entry inside of allNum, the while loop will generate a new random number using a new iteration of Math.floor(random(1, 11)). This loop remains active as long as the numbers stay the same. Therefore, until a different number is generated, the while loop will prevent the same number from being added to the allNum array.

The while loop is inserted into our for loop like so:

let counter = 0;
let num = 0;
let allNum = [];

for (i = 0; time >= i/2; i++) {
    seedRandom(counter, timeless = true);
    num = Math.floor(random(1, 11));
    while (num == allNum[counter - 1]) num = Math.floor(random(1, 11));
    allNum.push(num);
    counter++
}

allNum
Enter fullscreen mode Exit fullscreen mode

It is added after num has attempted to generate a new number with the update to seedRandom, but before it is pushed to the array so it can be re-generated if necessary.

With this amend, our array now looks like this:

Image of updated array

As you can see, we no longer have double 7s or triple 1s in our sequence.

Therefore, if we call num at the end of our expression instead of allNum, we will have a random number between 1 and 10, excluding the previous entry generated, twice every second. Hooray!

GIF of random number generator in action

Applying It To Things Other Than Numbers

While random numbers are all well and good, there are other uses for this expression too. For instance, what if we wanted to randomise words on the screen instead, without duplicate repeats?

All we need to do is add another array.


var ranText = ["Banana", "Apple", "Pear", "Peach", "Pulm", "Orange", "Mango", "Lychee", "Pinapple", "Dragonfruit"];
Enter fullscreen mode Exit fullscreen mode

Here is an array housing the text we want randomised. There are 10 entries, matching the range of the number generator we made previously.

By calling an entry of our new array using our num variable, we can call the entry whose index matches that number:


//Text
var ranText = ["Banana", "Apple", "Pear", "Peach", "Pulm", "Orange", "Mango", "Lychee", "Pinapple", "Dragonfruit"];

//variables
let counter = 0;
let num = 0;
let allNum = [];

//For loop
for (i = 0; time >= i/2; i++) {
    seedRandom(counter, timeless = true);
    num = Math.floor(random(1, 11));
    while (num == allNum[counter - 1]) num = Math.floor(random(1, 11));
    allNum.push(num);
    counter++
}

//return
ranText[num - 1]
Enter fullscreen mode Exit fullscreen mode

GIF of random text generator

Useful! Just remember to make sure that your num variable at the end includes -1, to account for the array index starting at 0.

Instead of using an array, it is possible to connect your expression to data inside of a .csv file. I go into how this is possible in my kinetic text breakdown here, should you want to make a template that is constantly updatable.

However you can use it in other ways too. Images can be randomly displayed as well, by connecting this expression to a slider controlling the frames of a precomp.

Conclusion

In conclusion, it is possible to add a little bit more control over random numbers in order to make them look a little more aesthetically pleasing to the eye.

What did you think of this method? Is there an easier way? Did this help you with your project in any way? Please leave a comment and let me know.

Top comments (0)