Room escape tutorial


Part 3 - Randomly Generated codes, and context sensitive text

In this part of the tutorial, we will finish creating our game. I will show you how to create a code-lock with a randomly generated code, as well as how to add some dynamic text which will allow you to give additional information and clues to the player.

First we are going to generate our “secret” code, which will change each time you play the game. I do this using an Array. An array is similar to a variable in that it can be used to store data, however it can be used to store LOTS of data, each piece in a separate compartment which can be accessed individually.

On the first frame of the game, I added the following code:

_global.code_array = new Array();

for (i=0; i<4; i++) {
            _global.code_array.push(Math.round(Math.random()*9));
}

What this does is creates a new array, and then it generates four random numbers (from 0-9), which are each added to the array separately. In the picture I used a trace to check that the array was working correctly.

Now that we have our code, the next thing we need to do is to be able to display it.
On a new layer (which spanned all the frames of my game), I created a new movie clip called “big_code”. On this, I drew a larger piece of paper (a big version of the little piece of paper that I hid in the vase).


On top of the paper, I placed a dynamic text box, which I ensured was big enough for 4 digits. I named the text box “note”. Under “character embedding…” I ensured that ONLY “numerals [0-9]” was highlighted. This is so that the commas (,) in the array will not be displayed. You could add code to remove them, however this is an easier way to get around it for now. [Note – when embedding fonts in a text box, any characters which are not specifically added, will not display in the final swf. Also, if you are having problems with none of your text showing, check to make sure you are not using any Bold or Italic fonts, these can cause issues when embedded]

Then in the main timeline for my game, on the first frame that the big_code appears, I placed the following code:

big_code.note.text = _global.code_array;

When you test your game, your note should now display a random 4 digit code each time.

I then added a “onClipEvent(load){this._visible = false;}” to the big note, and added some code to the small inventory note to make the big note visible when clicked 9 (_global.big_note_vis is a new variable I created on the first frame, like in the previous tutorial):

onClipEvent (load) {
            this.tabEnabled = false;
            this._visible = false;

}

on (release) {
            if (_global.big_note_vis == 0) {
                        _level0.big_code._visible = true;
                        _global.big_note_vis = 1;
            } else {
                        _level0.big_code._visible = false;
                        _global.big_note_vis = 0;
            }
}

So now it is time to add the last part of our puzzle – a wall mounted safe with a 4 digit code lock. In my game, I am hiding this behind the painting on the wall. The painting can be removed by dragging the hammer over onto it – check the last tutorial for details on how to do this, it is very similar to those examples so I won’t cover it in any detail.

I created a new frame in my main timeline called “safe”, and on this I drew a closeup of the wall where the picture is. I then created a new movieclip into which I started drawing my safe.

This basically consists of a square grey/black background, a panel near the top where I can display the digits, and plenty of space underneath for all the buttons and the “hatch”. In the display panel, I created a new dynamic text box called “display”. I used the font DS-Digital, and set the letter spacing to 11, and embedded the numerals, plus the characters “* e r o k”.

For the buttons, I simply created a single moveclip with 12 frames, 1 for each button. I used the numbers 1-9 plus 0, a “cancel” button, and an “ok” button. (ensure you put a “stop();” command in the first frame of this movie clip to ensure your buttons don’t animate unless you tell them to!).

Back on the safe moveclip, I arranged 12 copies of the button movieclip into a grid, until I was happy with them (Use the align and distribute tools to help you with this). I then gave each button a different name eg b1, b2, b3, bu (undo), bk (ok), etc…

On my main safe timeline, I created a sliding panel, behind which I placed a copy of the key. I animated this panel to open over 30 frames, the frame 1 being with the panel totally closed (ensure that the layer the key is on is empty on the first frame, or else you would be able to “click” on the key and take it, whilst the door was still closed), and frame 30 having the safe fully open.

Add the following new variables to the first frame of our main timeline:
_global.safe_open = 0;
_global.safe_array = new Array();

I then added the following actionscript to frame 1 of my safe movieclip (it’s a big one, I added comments throughout to explain what each part of the code does!):

stop();
if (_global.safe_open == 1) {
            gotoAndStop(25);
}
// Sets up our text box formatting, this is purely cosmetic, but it
// looks better if the digits of the   
// numbers are spread out.

var format:TextFormat = new TextFormat();
format.letterSpacing = 10;

// Checks whether any numbers have been entered into the keypad. If
// they have, it displays them,
// otherwise the default value of the text box displays (****). This
// line runs as soon as the
// movieclip loads, so when you come back to the safe, it remembers how you left it.

if (_global.safe_array.length != 0) {
            display.text = _global.safe_array;
            display.setTextFormat(format);
}
// This for loop saves us a lot of work, and makes the code a lot more
// compact. It runs from    
// 0, up to 11, and repeats the same actions with only the value of
// "i" changing each time.

for (i=0; i<12; i++) {

            // Here I assign the target movieclip to a variable (t).
            // The reason for this? Because typing the
            // letter "t" is a lot easier than typing "this["b"+i]"
            // each time we want to access its properties.
            // the ["b"+i] part is really useful. The names of all my
            // button movieclips start with a b, followed
            // by a number. This code allows me to dynamically
            // reference them, so as the value of i changes,
            // the movie clip that is being targetted also changes.
            // Note: When using this form of referencing, you do not
            // put a dot (".") between the parent movieclip
            // and the clip you are targetting. Also, you must always
            // have a parent before the brackets. If there
            // isn't one, just use "this", as I have done.

            t = this["b"+i];

            // Changes the frame that the target displays to i
            t.gotoAndStop(i);

            // Stores the value of i to a variable inside the
            // movieclip itself. This is necessary for the
            // onRelease Function...

            t.val = i;

            t.onRelease = function() {

                        // Prevents the buttons from working when the
                        // safe has been opened.

                        if (_global.safe_open == 0) {

                                    // Checks the number of digits in
                                    // our array. If less than 4,
                                    // allows you to enter more                                                 // digits.

                                    if (_global.safe_array.length<4) {

                                           // Adds the value of
                                           // the button (stored
                                           // in t.val earlier)
                                           // to the array.
                  
                                           _global.safe_array.push(this.val);

                                           // Updates the text of the
                                           // display box to the new
                                           // value of the array, and
                                           // formats it.

                                           display.text = _global.safe_array;
                                           display.setTextFormat(format);
                                    }
                        }
            };
            if (i == 0) {

                        // Manually sets button 0 to stop on frame 10 - this
                        // is because there is no frame 0!

                        this["b"+i].gotoAndStop(10);
            }
            if (i == 10) {

                        // Manually sets the "reset" button to stop on frame
                        //
11
                        bu.gotoAndStop(11);
                        bu.onRelease = function() {
                                    if (_global.safe_open == 0) {

                                                // Resets the array (clears
                                                // it), and updates the
                                                // display text to its default
                                                // value.

                                             _global.safe_array = new Array();
                                             display.text = "****";
                                             display.setTextFormat(format);
                                    }
                        };
            }
            if (i == 11) {

                        //Manually sets the "ok" button to 12
                        bk.gotoAndStop(12);
                        bk.onRelease = function() {
                                    if (_global.safe_open == 0) {

                                            // To determine whether the
                                            // code value, and the numbers
                                            // entered into the safe are
                                            // correct,
                                            // you have to compare them.
                                            // However, to compare two
                                            // arrays, you first have to
                                            // convert them
                                            // into strings - you can't
                                            // compare arrays directly.
                                            // This is easy enough. I
                                            // convert them
                                            // to strings, then store them
                                            // as two new variables, s and
                                            // c.

                                            s = _global.safe_array.toString();
                                            c = _global.code_array.toString();

                                            // So, if s (the safe array)
                                            // matches c (the code array)

                                            if (s == c) {

                                                // Performs the actions that
                                                // take place when the code
                                                // is opened

                                                display.text = "ok";
                                                display.setTextFormat(format);
                                                this._parent.gotoAndPlay(2);
                                                _global.safe_open = 1;
                                                } else {

                                                // Performs the actions that
                                                // show the code is incorrect

                                                display.text = "err";
                                                display.setTextFormat(format);
                                                }
                                    }
                        };
            }
}

I added code to the key in the safe that allowed me to pick it up (again see part 2 of the tutorial series), and drag it onto the door in order to open it. On the animation of the door opening, on the last frame I created an movieclip with an alpha of 0, which takes you to the game complete screen when clicked.

Now we are going to add some context sensitive text, which will help you add more story and back ground information to your game.

On the main timeline, create a new layer on top of your inventory. On this, draw a text box. Make sure that the text box is big enough to fit enough text in, but won’t overlap with the rest of your inventory. Set the behaviour to “single line”, and ensure that you embed all capital letters, lowercase, numerals and punctuation. I named this text box “context”.
I then converted the text box into a movieclip TWICE ( so it is a clip, embedded in a second clip). The outermost clip is called “ct”, the inner most is called “fader”.

Inside CT, I then created a 60 frame animation of fader. On the first frame, fader has its alpha set to 0. On the second frame, the alpha is 100. On frame 45 I set a keyframe of 100 alpha, and then on frame 60 one of 0 alpha. This creates an effect where the text box will fade out after about 2 seconds. If this seems too quick or too long for your game, feel free to adjust the animation slightly. It is a nice effect though, and will ensure that the any messages won’t stay on the screen for so long that the player isn’t sure about which object is creating the message.

Now that we have our text box, in order to display anything in it, we simply use two lines of code:

ct.fader.context.text = "Insert message text here";
ct.gotoAndPlay(2);

Remember to always point to these locations correctly, the exact method of doing so will differ depending on where you are calling the message from. For example on my inventory items, I use the following method:

on (rollOver) {
            this._parent.ct.fader.context.text = "A hammer.";
            this._parent.ct.gotoAndPlay(2);
}

On the piece of paper that appears when you smash the vase, I used it like this:

on (release) {
            this._visible = false;
            _global.note = 1;
            _root.inv_code._visible = true;
            _root.ct.fader.context.text = "I found a piece of paper.";
            _root.ct.gotoAndPlay(2);
}

 

So, using all the information from this tutorial, you should now be able to come up with something that is starting to resemble a fully functioning game. Here is how my game is looking now:

Tutorial by John Feltham
powerabuse.co.uk

If you have any questions regarding this tutorial, or would like any of the topics explained in a little more detail, feel free to post on my forum.