Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions How to make random generator not repeat twice the same number ?

  • How to make random generator not repeat twice the same number ?

    Posted by Lionel Vicidomini on May 17, 2013 at 6:58 am

    Hello there,
    I know this is a common issue, but I can’t find a definitive answer to it. The closest I got was this thread
    https://forums.creativecow.net/readpost/227/16179
    where Dan states :

    “With After Effects, the issue is that an expression can’t directly control anything except the property to which it is applied. One thing you can do though is apply a slider control to one of the layers (let’s say the first one) and apply an expression to that which “publishes” the index of the layer that should currently be visible. The espression might look like this:

    holdTime = .5;
    n = 4;
    segment = Math.floor(time/holdTime);
    seedRandom(segment,true);
    Math.floor(random(n)) + 1;

    This provides a random number from 1 to 4 that gets recalculated every half second. It gets more complicated if you need to make sure the same number doesn’t repeat twice in a row or if you want the hold times to vary.

    Then you would apply an expression like this to each layer’s opacity property:

    idx = thisComp.layer(1).effect(“Slider Control”)(“Slider”);
    if (idx == index) 100 else 0″

    Unless I didn’t get it, I still don’t see how to make the generator not repeat itself. I understand I have to add some code to the first segment, but how ?

    Lionel Vicidomini replied 13 years, 3 months ago 3 Members · 5 Replies
  • 5 Replies
  • Declan Smith

    May 17, 2013 at 8:02 am

    Try this.

    This will create an array of consecutive numbers starting at zero going up to the length of your composition (in frames). The array is then randomly shuffled (shuffle routine courtesy of google) but with the random number seed being the same each time, so that each frame creates the same random sort order. The number returned from array is chosen by using the current frame number.

    To see this work, put it on the source property of a text object.

    You can use the numbers in the array as you wish, scale them whatever. Also, if you want them to hold for a number of frames, then just change how you extract the number from the array. i.e. if you want to hold a particular number for 5 frames, then change the last line to read something like:
    numarray(Math.floor(ttf/5))

    But the essence of the code below is that it generates a random number that doesn’t repeat.

    function shuffle(o){
    // Shuffle based on original code by Jonas Raoni Soares Silva
    //https://jsfromhell.com/array/shuffle [v1.0]
    seedRandom(1, timeless = true);
    for(var j, x, i = o.length; i; j = parseInt(random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
    }
    max=timeToFrames(t = thisComp.duration + thisComp.displayStartTime, fps = 1.0 / thisComp.frameDuration, isDuration = false);
    numarray=[];
    for (i = 0; i <max; i++) {
    numarray.push(i);
    }
    numarray=shuffle(numarray);
    ttf=timeToFrames(t = time + thisComp.displayStartTime, fps = 1.0 / thisComp.frameDuration, isDuration = false);
    numarray[ttf];

    Declan Smith
    https://www.madpanic.tv
    After Effects CS6/ FCS3 / Canon 7D / Canon XL2 / Reason / Cubase

    “it’s either binary or it’s not”

  • Lionel Vicidomini

    May 17, 2013 at 11:59 am

    Thanks for the answer.
    I understand some parts of the expression.
    As for the array, I understand that it is generated from the duration of the composition, i.e a 250 frames comp will give an array from 0 to 250.
    You say to scale the array, but how ?
    The expression works perfectly, except that I would like to specify myself the array, as simply as in the “random(minValOrArray, maxValOrArray)”, say from 1 to 15, without it being related to the duration of the comp.
    When I put an array in the numArray part of the expression, it doesn’t seem to work…

  • Declan Smith

    May 17, 2013 at 2:37 pm

    The expression as supplied generates random numbers that do not repeat. If you limit the numbers that you want the expression to return from 1-15, then by definition, you can only evaluate this 15 times before you will have to repeat a value.

    So I am now not entirely sure what problem you are trying to solve.

    If you want to limit the numbers that are generated to between 1-15 then you will need some additional mechanism to ensure they don’t repeat, i.e. holding the value for a number of frames, or changing the value based on a keyframe.

    In order to specify your own values, I have added both min and max values, just set these to what you want. The for loop creates the array. (currently I have set min=1 max=15)

    I have provided you two Options below.

    Option 1 – Expression will repeat every max frames.
    Just change the value of the interval (current set to 10)

    Option 2 – Expression will pick a value based on the keyframe index. In other words you add keyframes where you want the value to change. Note that your maximum number of keyframes is determined by your ‘max’ value you specified. Uncomment the lines specified

    function shuffle(o){
    // Shuffle based on original code by Jonas Raoni Soares Silva
    // https://jsfromhell.com/array/shuffle [v1.0]
    seedRandom(1, timeless = true);
    for(var j, x, i = o.length; i; j = parseInt(random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
    }
    //max=timeToFrames(t = thisComp.duration + thisComp.displayStartTime, fps = 1.0 / thisComp.frameDuration, isDuration = false);
    min=1
    max=3
    numarray=[];
    for (i = min; i &lt;=max; i++) {
    numarray.push(i);
    }
    numarray=shuffle(numarray);

    // Option 1 - Will change value every 'interval' number of frames (but will repeat every 'max' * 'interval' frames
    ttf=timeToFrames(t = time + thisComp.displayStartTime, fps = 1.0 / thisComp.frameDuration, isDuration = false);
    interval=10;
    numarray[Math.floor((ttf/interval) % max)];

    // Option 2 - Will select based on keyframe position (uncomment the next four lines
    //n = 0;
    //n = nearestKey(time).index;
    //if (key(n).time > time) n--;
    //numarray[n % max];

    Declan Smith
    https://www.madpanic.tv
    After Effects CS6/ FCS3 / Canon 7D / Canon XL2 / Reason / Cubase

    “it’s either binary or it’s not”

  • Xavier Gomez

    May 17, 2013 at 3:15 pm

    An alternative, built upon Dan Ebberts’ expression:

    holdTime = 0.5;
    n = 4;
    t0 = inPoint;
    t = time-t0;
    STEPS = 1 + Math.floor(t/holdTime);

    // initially generate a number in {0,1,..., n-1}
    seedRandom(0,true);
    idx = Math.floor(random(n));

    // if (t>= holdTime)add something non zero, step after step
    for(var step=1; step&lt; STEPS; step++){
    seedRandom(step, true);
    idx = (idx + Math.floor(random(n-1)+1)) % n;}

    //return
    idx + 1;

  • Lionel Vicidomini

    May 20, 2013 at 8:10 am

    Both expressions work fine.
    Actually, Xavier Gomez’s is what I was looking for, but Smith’s one can be very useful is other situation (the “shuffle” variable is very interesting)
    Thanks to both of you !

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy