How to Jump Randomly to Frame Labels without Repeats

ActionScript 2.0 Flash

One of the more popular entries of this blog describes How to Jump to a Random Frame Label.  The ActionScript 2.0 involved is very straightforward, weighing in at a mere 5 lines.  Its sole purpose is to choose a random label once at the beginning, then go to it (then stop).  In the Comments section, a visitor named Heather asked for a variation in which the movie starts at a random label, then proceeds to the remaining labels in order, looping around to the beginning, if necessary, to hit each label once.  I offered some suggested code, and eventually a number of other visitors asked for yet another variation:  how to jump randomly to a whole series of labels — without repeats.  That takes a bit more code, but it’s certainly doable.  Let’s take a look. 

An answer, short and sweet

This bulk of this code goes in frame 1, then one of its functions gets called at the end of each span of frames represented by a label.  Here’s the code for frame 1:

function shuffle(arr:Array):Void {
  var len:Number = arr.length - 1;
  for (var i:Number = len; i >= 0; i--) {
    var p:Number = Math.floor(Math.random() * (i + 1));
    var t:Object = arr[i];
    arr[i] = arr[p];
    arr[p] = t;
  }
}

var labels:Array = ["a", "b", "c", "d", "e"];
shuffle(labels);

var currentLabel:Number = 0;
function gotoNextLabel():Void {
  if (currentLabel < labels.length) {
    gotoAndPlay(labels[currentLabel]);
    currentLabel++;
  } else {
    stop();
  }
}
gotoNextLabel();

Gulp!  That’s a lot of code, huh?  We’ll step through it in the “How it works” section, but for the time being, just know that the labels array holds your frame labels (here, “a”, “b”, “c”, and so on — but you’ll use meaningful labels) and that you’ll obviously need corresponding frame labels in the timeline that holds this ActionScript.  If your equivalent of label “a” spans from frames 2 through 100, you’ll put a new keyframe in your scripts layer at frame 100 with the following small function call in it:

gotoNextLabel();

If your equivalent of label “b” follows, spanning from 101 to 150, you’ll put a new keyframe in your scripts layer at frame 150 and call that gotoNextLabel() function again.  Do this at the end of each span.  The end result is that the playhead will visit each and every span at random without repeats.

How it works

The ActionScript above is visually organized into three sections, just for clarity.  The first section (the custom shuffle() function) isn’t my own code, but a time-tested algorithm made popular on the Adobe forums by long-time contributor kglad.  There are a number of variations on it, and a complete discussion would probably make a good blog entry of its own, but for the time being, let the shuffle() function be a magic stone in your pocket:  it shuffles whatever array is passed to it, and it works.

The second section is comprised of two lines:

var labels:Array = ["a", "b", "c", "d", "e"];
 shuffle(labels);

In this variation on the “jump to a random frame” theme, the labels array is declared outside of any function, which makes it available to all code in this timeline.  It’s pretty clear to see what these two lines do.  The first declares an Array instance named labels and sets it to a series of arbitrary frame labels.  The second shuffles that array.  After shuffle() is called, the array might look like any one of the following sample shufflings …

b,e,a,d,c
a,e,b,c,d
b,c,e,d,a
d,c,a,e,b
e,a,c,d,b

… which is great, because that means the final section of code is pretty easy.  First, an arbitrarily named variable, currentLabel, is declared and set to zero.

var currentLabel:Number = 0;

Why zero?  Because arrays start their counting at zero rather than one.  We’re going to be starting at the first element in the array, sending the playhead to that frame label, then stepping through the remaining array elements in turn.  This is accomplished by a custom gotoNextLabel() function.

function gotoNextLabel():Void {
  if (currentLabel < labels.length) {

So far, the currentLabel variable (currently 0) is checked against the Array.length property of the labels instance.  Have we reached the end of the array?  Not yet, so the following occurs:

    gotoAndPlay(labels[currentLabel]);
    currentLabel++;

The playhead is sent to the frame label represented by labels[0] (the first element), and currentLabel is incremented by one (the ++ operator).  This will happen every time the gotoNextLabel() function is called, and eventually, the value of currentLabel will no longer be smaller than the value of labels.length.  When that happens …

  } else {
    stop();
  }
}

The playhead stops.  All spans of the timeline will have been visited, and the movie will rest comfortable in the final frame of its final randomly chosen span.  To start the whole thing off, this last line of code calls the very function just described:

gotoNextLabel();

As noted earlier, you’ll have to repeat this gotoNextLabel() call in the last frame of each span of frame labels.

Have fun with it!

Leave a Reply