Several years ago, I wrote a tutorial for my previous lab on how to create Web-based experiments in Flash. Over the next number of months, I'll be posting that tutorial chapter by chapter.
This and the following two chapters will go over how to produce a basic change-detection experiment. Necessary materials and the finished example are included.
1. How is a Flash program structured?
If you have ever done any programming, you will find the layout of a Flash program rather odd. This is because it is designed for animations.
A Flash program is structured around frames. Frames are what they sound like – a frame in a movie. A frame may contain images. It also has attached code. That code is linked to that frame and that frame only, although subroutines written in one frame’s code can be called by another frame.
Moreover, a frame can contain movie clips. Movie clips is a very confusing name for these structures. What you need to know about them for the moment is that they can have their own timeline and their own attached code.
2. Exploring Flash
Note: This tutorial was written for Flash MX with Actionscript 2.0. I believe everything will work as it should in newer versions of Flash, but if you have any problems, please leave a comment or email me.
Open a new Flash document. The main window contains two parts. At the top, there is a timeline. This timeline shows all the frames in your program. Currently, the first frame should be highlighted and have a circle in it. The other frames should all be faded in appearance. They are just placeholders and will not appear in a movie. The circle in the first frame indicates that it is a keyframe, which will be discussed below.
At the bottom of the Timeline, you will see the letters “12.0 fps”. This is the speed of the movie: 12 frames per second. 12 fps is standard. You can go faster or slower as you wish. However, this is a ballpark figure – actual speed depends on many factors. Supposedly there are ways to improve the accuracy of the timing, but I have never tried or tested any of them. It is also worth noting that there does seem to be a maximum speed. As the fps increases, the actual speed when running does not necessarily increase. Also, at high speeds, the program will run faster when run locally (i.e., on your desktop) than when run through the Internet.
The central, larger part, is the stage. This shows you what is actually displayed in a particular frame (unless those images are dynamically created, which will be discussed below).
There are several popup windows you will want to have at your disposal. Make sure they are checked off under the “Window” menu item. These are:
Properties. The property inspector allows you to modify anything that is selected on the stage or in the timeline. Click on the stage itself, and you will see several options in the properties window. The most important one is the stage size. Default is usually 550 x 400. In general, it is better to keep your stage small, since you do not know how large the screen of your participants will be.
Select Window->Development Panels->Actions to bring up the Actions window. This window contains all the code that is linked to whatever you currently have selected, be in frame, movie clip or component. Note that the search function only searches that code. Currently, there is no way to search through all the code in a given program.
Select Window->Library to open the library. The library contains any components used in your program. This will be important later.
3. Displaying stimuli.
First, change the fps to 4. This will make the math simpler.
Now, we will create a background layer.
Choose Insert->Timeline->Layer to add a new layer.
In the Timeline, select Layer 1. Using the drawing tools, draw a rectangle of any size. In the properties window, click the “fill” icon. In the popup window, click on the color wheel. In the new “colors” window, select the “sliders” button. Below that, change “Gray Scale Slider” to “RGB Slider”. This allows you to type in exact RGB values. Type in 145 for Red, Green, and Blue. Click “OK”. Now, in the properties window, change the width and height of the rectangle so that it matches the size of the stage. Make sure the X and Y coordinates are 0. Now, you can change the foreground layer without affecting the background, and visa versa. In this example, the background is a neutral gray, but it could be much more complicated and even dynamic. To lock the background so you don’t accidentally edit it, do the following. In the timeline, just after the words “Layer 1”, you should see a couple diamonds. One is under the “Eye” column. One is under the “lock” column. Click the diamond under the “Lock” column. This locks the layer. (The “Eye” diamond toggles the visibility of the layer.)
Now we want to add some stimuli. Make sure you have Frame1 and Layer 2 selected. Go to File->Import->Import To Stage and import Stim1.pic. If asked to import via QuickTime, click OK.
Click on the image. Go to the properties inspector and change the X coordinate to 75 and the Y coordinate to 50. This will center the 400 x 300 image on a 550 x 400 stage.
Now, click on the 2nd frame of Layer 2. Go to Insert->Timeline->Blank Keyframe. (Inserting a non-blank Keyframe would make a new keyframe that contains the same images as the current one.) The second frame should now be a keyframe.
Now, click on the 3rd frame of Layer 2. Go to Insert->Timeline->Frame. Now, there should be a box around frames 2 and 3. You’ve now made frame 3 active, but it is not a keyframe. This means it cannot be modified independently of the keyframe in frame 2. Now click Insert->Timeline->Blank Keyframe. Notice that this converted your frame to a keyframe. It did not actually “insert” anything.
Notice also that our background does not appear when we select frames 2 or 3. This is because Layer 1 only has a single frame. You will need to expand Layer 1. Click on frame 3 of layer one and click on Insert->Timeline->Frame. Now the background should appear on all 3 frames.
Now, import Stim2 to the 3rd frame of Layer 2. Center it as before.
Now, test your “experiment” by clicking Control->Test Movie. The movie, you will notice, loops. As soon as it gets to the end, it goes back to the beginning. This won’t happen when it is run from a website, but it is still annoying. Let’s add some code to prevent this.
Close the test window and click on the 3rd frame of Layer 2. Now go to the “Actions” window and type:
stop();
This ActionScript pauses the timeline in the current frame. However, code that appears after the “stop” command will still be executed.
Now test the experiment. You probably will have trouble seeing the first stimulus. This is because Flash starts playing even before the program is fully loaded. In the future, we will add a “loader” to fix this problem. For now, however, just add several blank frames to the beginning of the experiment.
Test the experiment. It is now a basic change-detection experiment. It has several problems, however, the first of which is that there is no way for the participant to respond.
4. Getting responses.
There are two ways to input responses: with the mouse and with the keyboard. Because the experiment is on the Web, the more natural method seems to be using the mouse. However, to get accurate reaction times, keyboard entry is probably preferred. That will be discussed below, under “Getting Reaction Time”.
Select the final frame of Layer 2. In the same floating window as the one that shows the library, expand the “components” window. Drag the “button” component onto the final frame of Layer 2. Put it somewhere that it will not interfere with the image itself. In the property inspector, change the label to “Same”. The “button” component should now be in the program library. Drag a new instance of the button component onto the stage and change the label to “Different.”
Select the “same” button. In the Actions window, add the following ActionScript:
on (release){
_root.correct = 0;
_root.gotoAndPlay('feedback');
}
This subroutine will execute when the user clicks on the button and then releases the mouse button. Then, it sets a variable called “correct” to 0, since the stimuli in fact are not the same. This variable is attached to the main program, which is why it is prefixed by “_root.”. Similarly, the command “gotoAndPlay(‘feedback’)” is attached to the main program, since the frame “feedback” is part of the main program. “gotoAndPlay” does what it sounds like: it tells Flash to go to the frame called “feedback” and start playing from that point. The “AndPlay” part is important, because currently we’ve told Flash to pause playing.
To the “different” button, add:
on (release){
_root.correct = 1;
_root.gotoAndPlay('feedback');
}
Of course, there isn’t any frame called “feedback.” Add a blank keyframe to the end of the experiment. In the property inspector, name it “feedback”. In the center of that frame, draw a text box. In the property inspector, make sure it is dynamic text, not static text. Under “var”, type “feedback_text”.
In the Actions window for the “feedback” frame, add the following code:
stop();
if (correct==1){
feedback_text='Correct';
}else{
feedback_text='Incorrect';
}
Notice that we don’t need to use _root. This code is already attached to the “root”. Also notice the use of the double equals sign. If you accidentally type:
If (correct=1){
The variable “correct” will actually be set to 1.
Play this experiment. If you respond “Same,” you should be told that this response was incorrect. If you respond “Different,” you should be told that this response is correct. You may want to compare your work to the
demo.
Note: Here and elsewhere, if you'd like the original .fla file to look at, please email me at gameswithwords@gmail.com
Our experiment has only one trial. You could add trials manually by adding new frames. This isn’t very efficient, and it also doesn’t allow for any randomization. In the next part, we’ll add these aspects.
5. Creating a dynamic experiment.
To dynamically choose which stimuli appear, we will need to convert them to symbols.
Go to the frame with Stim1. Right-click on the copy on the stage and select “Convert to Symbol”. In the dialogue, name the symbol “Stim1”. Make it a Movie Clip. Under “Linkage”, first select “Export for ActionScript”, then change the Identifier to “Stim1”. This is the name you will use to refer to this Movie Clip in the code.
Now double-click on Stim1. The Timeline will now show Stim1’s timeline (remember that movie clips have their own timeline). All our movie clips will consist of a single frame, but remember that you have the option to make a movie clip more dynamic. In the property inspector, change the X coordinate of Stim1 to “–200” and the Y coordinate to “-150”. This centers the 400 x 300 image (in the future, you can see what happens if you skip this step). Now go to Edit->Edit Document.
Repeat this process for Stim2. Drag Stim3 onto the stage somewhere and repeat the process. Now, delete the images of Stim1, Stim2 and Stim3 from whatever frames they appear in.
Name the frame where Stim1 was originally presented “stim”. Name the frame where Stim2 was originally presented “probe”.
In the frame “stim”, the ActionScript should read as follows:
stimulus=random(3)+1;
_root.attachMovie("Stim"+stimulus,"Stimulus",1);
setProperty(eval("Stimulus"), _x, 275);
setProperty(eval("Stimulus"), _y, 200);
First, a random number from 0 to 2 is chosen, to which we add 1. _root.attachMovie attaches a movie clip to the frame. The first argument (“Stim”+stimulus) names the movie clip. Notice that possible values are “Stim1”, “Stim2” and “Stim3” – our three stimuli! The second argument is a name for this instance. The final argument determines which movie clip level the movie clip is assigned to. If there is already a movie clip on level 1, this will overwrite it. Bugs in Flash very often result from overwriting a movie clip in this fashion.
Next, we position the movie clip in the center of the screen (275, 200) by setting the X and Y parameters. Note that if the movie clip image itself is not centered (as we did above), the outcome will be different. For instance, if the origin of the movie clip is it’s upper left corner, then you would need to place this instance at (75,50) in order to center the instance on the stage.
In the next frame, add the following code:
removeMovieClip("Stimulus");
This removes the movie clip we just added. Note that it removes it using the name we assigned it in the previous frame.
In the “Probe” frame, change the code to the following:
stop();
probe = random(3)+1;
if (stimulus==probe){
match=1;
}else{
match=0;
}
_root.attachMovie("Stim"+probe,"Probe",1);
setProperty(eval("Probe"), _x, 275);
setProperty(eval("Probe"), _y, 200);
Now, the probe is chosen randomly from the 3 stimuli. When the stimulus and the probe match, this is noted. Notice that the stimulus and probe will match 1/3 of the time. 2/3 of the time, they do not. This is done here to simplify the programming, any ratio can be implemented.
We also have to change the code for our response buttons. It is no longer the case that “different” is always correct and “same” is always wrong. Modify the code for the “Same” button as follows:
on (release){
if (_root.match==1){
_root.correct = 1;
}else{
_root.correct = 0;
}
_root.gotoAndPlay('feedback');
}
Modify the code for the “Different” button similarly.
Finally, add this code to the top of the Feedback frame:
removeMovieClip("Probe");
Test the experiment. There is still only one trial, but the stimuli should now be chosen randomly.
Writing a loop so that there are multiple trials is fairly straight-forward. First, add a blank keyframe to the beginning on Layer 2. Add the following code:
total_trials = 5;
current_trial = 1;
This initializes two variables. total_trials sets the total number of trials. current_trial tracks how many trials have been completed.
Now, name the second keyframe of Layer 2 “Next_Trial”.
Remove the stop() command from “feedback” and add 2 frames. Convert the final one to a keyframe (don’t change it to a blank keyframe – we want the feedback_text to continue to display on this final frame). Add this code to that new keyframe:
if (current_trial==total_trials){
gotoAndPlay('finish');
}else{
current_trial += 1;
trace(current_trial);
gotoAndPlay('Next_Trial');
}
This code does pretty much what it says. Now we need to add a final frame to Layer 2 and call it “finish”. Draw a textbox on the stage and write, “Thank you for participating.”
Your program should now look like
this.
We are still not recording any data. That will be discussed in a future chapter.