Field of Science

Questions about the tutorial?

Hi folks -- anyone who is trying to use the Web Experiment Tutorial, please do write in (gameswithwords at gmail) or comment with questions. This tutorial was written for Flash MX, and though I actually still run programs that were based in MX and they work fine, there may be adjustments necessary for people using the latest versions of Flash. I'd be interested in hearing if you run into any such difficulties.

Web Experiment Tutorial: Chapter 4, Flash: Finishing Touches


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.

1. Getting Reaction Time.

For some experiments, you may wish to record reaction time. Reaction time will not be very accurate in a Web-based experiment. A priming experiment, for instance, would probably not be ideal. However, for larger reaction time effects, this methodology should be sufficient.

You could get a reaction time mouse click in the following manner:

In the “probe” frame, add the following code right after the code that displays the probe:

start_time =new Date().getTime();

Add this code to the “same” and “different” buttons, just before the gotoAndPlay statement:

_root.RT = new Date().getTime() - _root.start_time;

The variable “RT” will now contains the number of milliseconds that passed between the probe display and the mouse release. We could change it to the onset of the mouse click by changing the subroutines in the “same” and “different” buttons to on (click).

However, responding with the mouse is slow, and you would probably prefer using key presses. This is more complicated. Do not try to understand the following method. It frankly makes no sense. Just try to learn how to use it.

First, make an empty text box containing a single space. Convert it to a movie clip named “keyTrap”.

Select “keyTrap” and attach the following code:

onClipEvent(keyDown) {
ResponseKey=Key.getCode();
responseTime=new Date().getTime();
_root.RT=responseTime - _root.start_time;
switch (ResponseKey) {
case 83:
//S
if (_root.match==1){
_root.correct = 1;
}else{
_root.correct = 0;
}
break;
case 68:
//D
if (_root.match==1){
_root.correct = 0;
}else{
_root.correct = 1;
}
break;
}
_root.gotoAndPlay("feedback");
}

The onClipEvent(keyDown) subroutine executes when any key is pressed.

Key.getCode retrieves the ASCII key code for the key that was pressed. The table for a standard keyboard is reproduced below.

The only other novel piece of code here is the switch statement. Switch statements in Flash have the following form:

Switch (VARIABLE) {
case VALUE-OF-VARIABLE:
CODE
break;
Case ANOTHER-VALUE
CODE
break;
}

Without the “break” command, Flash will execute the next line. Consider the following code:

Switch (number){
case 1:
trace(‘1’);
case 2:
trace(‘2’);
case 3
trace(‘3’);
}

This code will count to 3 starting with the value of “number”. If “number” = 1, then it will count: 1, 2, 3. If number=3, it will only count: 3.

(the “trace” command outputs to the output window. This can be seen when running a .fla program within Flash. The code does nothing when running off a website.)

You should also delete the “same” and “different” buttons. Now, you can respond by pressing “s” for “same” and “d” for “different”. Your program should now look like this.


ASCII codes for a standard keyboard:
A 65

B 66

C 67

D 68

E 69

F 70

G 71

H 72

I 73

J 74

K 75

L 76

M 77

N 78

O 79

P 80

Q 81

R 82

S 83

T 84

U 85

V 86

W 87

X 88

Y 89

Z 90

0 48

1 49

2 50

3 51

4 52

5 53

6 54

7 55

8 56

9 57


2. The Loader Bar

Ideally, you would like your program to load completely before it starts executing. If it is a large program, this may mean that participants have to wait. It’s a good idea to let them know how long they will be waiting.

This is where a loader bar comes in. I actually don’t understand how loader bars work, so I suggest simply copying the first frame of Part4.fla, including all attached code. This should work. Note that when it finishes loading, it goes to and plays a frame called “Initialize.” You will want to adjust this accordingly.

There are many resources online that discuss loader bars. However, most of them involve loading one Flash file inside of another one.

3. Arrays

As in other programming languages, you will frequently want to make use of arrays. One purpose for arrays is determining the order of all the stimuli before beginning the experiment.

Now that you’ve added a loader bar, your second frame (the one called “Initialize” in Part4.fla) should contain the code

total_trials = 5;
current_trial = 1;

Change it to the following code:

total_trials = 5;
current_trial = 0;
var Stimuli = new Array();
for (i=0; i < total_trials+1; i++){
Stimuli[i]=random(3)+1;
}
var Match = new Array();
Match[0] = 0;
Match[1] = 1;
Match[2] = 0;
Match[3] = 1;
Match[4] = 0;
Match[5] = 1;

The first change is that current_trial is set to 0. This is because the first cell in a Flash array is labeled “0”.

Next, we create an array called “Stimuli”. Using a for loop, we randomly set each cell of “Stimuli” to a number between 1 and 3. There are 6 cells, one for each trial. This way, on trial N, the program cal look to the value of Stimuli[N] in order to choose the stimulus.

You will also want to change the first line of the “stim” frame from

stimulus=random(3)+1;

to

stimulus=Stimuli[current_trial];

Notice that we named the array “Stimuli”. If we named is “Stimulus,” it would then share the same name as the one we assigned to the stimulus movie clip. This causes some of the other code associated with the movie clip to malfunction. So that is something to avoid.

This new code so far does not change how the experiment runs, other than that all the stimuli are chosen in the beginning. This is probably not very useful, but serves as an example.

Next, we create an array called “Match”. We assign half the cells the value 0 and half the value 1. Change the code on the “Probe” frame to the following:

stop();
match=Match[current_trial];
if (match==1){
probe=stimulus;
}else{
ok=1;
while (ok==1){
probe=random(3)+1;
if (probe==stimulus){
}else{
break;
}
}
}
_root.attachMovie("Stim"+probe,"Probe",2);
setProperty(eval("Probe"), _x, 275);
setProperty(eval("Probe"), _y, 200);
start_time =new Date().getTime();

What has changed? Before, we randomly chose a probe, and then set match to 0 if the probe and stimulus did not match and to 1 if they did. Now, we look to the appropriate cell of the Match array. If, on trial N, Match[N] == 1, we set the probe equal to the stimulus. Otherwise, they differ.

The only new code concept is the “while” loop. While loops execute all the code within the {} brackets as while the code within the () parentheses remains true OR until the program executes a BREAK statement. In this case, ok always equals 1, so the while loop will run until it executes the BREAK statement – which can only happen if the probe and stimulus do not match, which is what we want.

The purpose of this code is to make sure that 50% of trials are “Match” trials and 50% are “No Match” trials. However, the pattern is fairly simple, and subjects may catch on quickly. We would like to randomize the order of the trials.

Add the following code to the bottom of the Initialize frame:

var Trials = new Array();
for (i=0; i < total_trials+1; i++){
Trials=i;
}
shuffle(Trials);

function shuffle(a) {
var i = a.length;
while (i) {
var p = random(i);
var t = a[--i];
a[i] = a[p];
a[p] = t;
}
}

First, we create an array called “Trials” and set it to the values 0 through 5. Then we execute a function called “shuffle”, with “Trials” as the argument.

Finally, we define the function “shuffle”. Although this seems out of order, it will work fine. You should be able to parse the code on your own, but basically it uses a simple shuffling algorithm to randomize the order of the cells in Trials. Instead of Trials equaling [0 1 2 3 4 5] it may now equal [3 0 4 5 1 2] or any other random permutation of those values.

How does this help? We need to change one other things. Change the second line of the “probe” frame to:

match=Match[Trials[current_trial]];

I will let you convince yourself that the program will still use each value of “Match” exactly once during the experiment, but rather than running through each cell of Match in order, the order is now randomized.

For consistency, you may wish to make a similar change to the first line of the “stim” frame.

4. Surveys/Demographics

You may want to ask your subjects a few questions. This could in theory be done by using buttons as in the examples above, but it’s less than ideal.

There are several more ways of collecting information from participants. Three include radio buttons, combo boxes and input boxes.

Radio buttons are a group of linked buttons, only one of which can be selected at any one time. Look at the “Demographics” frame of Part4.fla. The first and third questions are both examples of radio buttons.

To set up rradio buttons, first drag a radio button from the Flash components window (or from your file’s library, if it already contains radio buttons). Make as many copies as you need.

Select one of the radio buttons. In the properties inspector, choose “parameters”. There are several you will want to change. “Data” contains the value of that button when selected. In Part4, the “Female” button’s data is “female”, while the “Male” button’s data is “male”. This will be more clear shortly. “groupName” is the name of the group. Radio buttons that share the same groupName are automatically part of the same group. One one can be selected at a time. “Label” is the text that is displayed to the subject. Try changing this and its function will be clear.

A combo box is slightly more complicated to set up. Again, drag a combo box onto your stage. In the properties inspector, change it’s name to age_box. Now, in the code attached to this frame, add the following:

ageData = new Array(101);
ageData[0]="Select";
for (i=1; i<101; i++) {
ageData[i]=i;
}
age_box.setDataProvider(ageData);

This creates an array with the values [‘Select’ 1 2 3 4 … 99 100]. This array is then assigned as the values of the combo box. If you test this frame, you will see that the default for the combo box is the first value (“Select”), and by scrolling you can choose any number from 1 to 100.

The third question is again made of two radio buttons, which have the values of “yes” and “no”. There is one interesting technique used here. The question “Do you have normal or corrected to normal vision?” is actually complicated, and not everybody understands it. However, including the entire explanation involves adding a lot of text, decreasing the chances that the subjects will actually read it.

So I added an invisible button underneath the text “(Click for explanation)”. The text is a dynamic text box called “explain”. The button contains the following code:

on (release){
_root.explain = "If your vision is normal when wearing glasses or contacts, answer 'yes'.";
}

Thus, if the participant clicks in the vicinity of the text box (to be accurate, if they click the invisible button), the text box’s text changes to a brief explanation.

Finally, we have an example of an input box. You create an input box the same as a static or dynamic text box, but in the properties inspector, you choose “input text” instead of “static text” or “dynamic text”. You should type “Initials” into the var box in the property inspector in order to name the data contained in this box, just as you would for a dynamic text box.

You can also type in a default value. Since I want 3 initials, I typed in “XXX”.

Finally, you need a way for subjects to submit their responses, and you need a way of recording that information.

I have included a button called “continue1_btn”, labeled “Continue”. Now, let’s look at the full code for this frame:

stop();

ageData = new Array(101);
ageData[0]="Select";
for (i=1; i<101; i++) {
ageData[i]=i;
}
age_box.setDataProvider(ageData);

demoBtn = new Object();

demoBtn.click = function(evt) {
age = age_box.getSelectedItem();
sex = sex_group.getValue();
normal_vision = vision_group.getValue();
initials = Initials;
good_form = 1;
if (sex == undefined) {
good_form = 0;
}
if (age == "Select") {
good_form = 0;
}
if (normal_vision == undefined) {
good_form = 0;
}
if (initials == "XXX"){
good_form = 0;
}
if (good_form == 1) {
gotoAndPlay("Instructions");
}else{
warning="Please finish all questions before continuing.";
}
}

continue1_btn.addEventListener("click", demoBtn);

The first part we have already gone over. Then we define a new object called “demoBtn”. Then we write an event handler to handle the event that the demoBtn is clicked. It first retrieves the data from the page. “age” is set to the value of the age_box. The value is literally whatever the subject selected. If they selected “74”, then the value is “74”. Then, “sex” is set to the value of the sex_group. Recall that using the property inspector, we set the “data” assigned to one radio button to “female” and the other to “male”. Thus, if “Female” is selected, the value of “sex” will be “female”. “normal_vision” is set by a similar process. Finally, “initials” is set to the value of whatever is typed into the input text box named “Initials”.

It’s important to make sure that the participants filled everything out. We make a dummy variable called “good_form” and set it to 1. Then we check each variable in turn. If it is undefined (in the case of radio buttons) or still set to its default values (in the case of the input text box or the combo box), we set “good_form” to 0.

Finally, if “good_form” = =1, we go on to the next frame. If it does not, we don’t. However, if nothing happens when the subject clicks “continue”, they may not realize it’s because they still have stuff to fill out. They may think the program is broken. So in the case that good_form == 0, we set a dynamic text box to “Please finish all questions before continuing.” That dynamic text box is at the bottom of the screen and is called “warning”. Notice that it must be set as “multiline” in the property inspector; otherwise, not all the text will be visible.


----
The working version of Part4 in .swf form can be found here.

Games with Words in Taiwan

I've been in Taiwan for two weeks, and further posts of the Tutorial will probably wait until I get back next week.

I had an excellent two-day visit to Prof. Su Yi-ching's lab at Tsing Hua University (Qinghua for you pinyin-readers), where I was able to collect an absurd amount of data due to the generosity of Prof. Su and her students (over 110 participants in two written studies, plus three in an eye-tracking study). I also had a great time at Prof. Lee Chia-Ying's very lively lab at Academia Sinica, where I got to observe a kid ERP experiment (something I've never actually seen, though I'm in the process of planning one of my own) and also test several more participants in the eye-tracking study. I also visited Prof. Chueng Hintat at National Taiwan University. I was mildly surprised to discover I actually can discuss my research in Mandarin when necessary, though with most people it was possible to use English (thankfully).

I wasn't at all sure how this trip was going to go when I planned it, as at the time I didn't actually know any psycholinguists in Taiwan. It turns out that there's actually a pretty substantial group of developmental psycholinguists working on interesting problems. Su and Cheung are both in the process of releasing much-needed new child corpora, with Su focusing on (if I remember correctly) optional infinitives (to the extent such can be recognized in a language with no inflectional morphology) and lexical tone, and Cheung focusing on argument structure alternations. Lee's lab is producing some really well-considered studies of character-reading (for instance, looking at how phonetic and semantic radicals are processed). I also heard of several other faculty doing exciting work but whom I didn't have time to visit.

And, of course, I got a lot of data, which is good since Harvard partly funded this trip on the expectation I would run some experiments. The experiments I was running are all similar to the Pronoun Sleuth project -- that is, looking at factors that affect what people think a pronoun means, and trying to replicate some of my findings in English.

Class Notes: Why linguistic judgments are fuzzy

Buried towards the end of a 1991 paper by Fisher, Gleitman & Gleitman is a strikingly useful -- and I think, correct -- observation on the limits of grammaticality studies. In the context of a broader argument that people learn the meanings of verbs partly from the syntactic frames the verbs appear in ("syntactic bootstrapping"), they argue that exactly this "feature" of verb learning makes it sometimes hard to decide if a particular verb is grammatical in a certain context.

Consider the present progressive in English. Classically, the present progressive can only be used for ongoing activities (1-3), not completed activities (4) or states that aren't typically activities (5):

(1) Sarah is eating the carrot.
(2) Sarah is running to the store.
(3) Sarah is looking at the moon.
(4) *Sarah is breaking the vase.
(5) *Sarah is seeing the moon.

However, a lot of people's judgments about (4) and (5) are iffy. They don't sound nearly so ungrammatical as (6).

(6) The boys carrot eats.

The idea is that people are influenced by the syntactic frame the verb appears in and reinterpret the verb. That is, if you think of "breaking" as something that happens in an instant, it isn't an activity and you can't say (4). However, if you imagine a long, drawn-out process in which Sarah methodically destroys a vase, "break" is now an activity, and (4) is fine. Similarly, "see" usually describes an end-state of some process, but you can re-imagine it as an activity (maybe Sarah observes the moon regularly as part of her profession).

I run into this constantly in my study of verbs of psychological state. Influenced by a paper by Liina Pylkkanen's 1991 "On stativity and causation," I've been pursuing the argument that certain psych verbs can't appear in certain syntactic frames. For instance, "love" and "hate" can't appear in the present progressive. In a sense, this seems right; (7) and (8) are somewhat more odd than (9) and (10).

(7) *John is loving the Red Sox.
(8) *John is hating the Yankees.
(9) John is frightening the squirrels.
(10) John is angering the chickens.

Unfortunately, one can usually find a way of reinterpreting "love" and "hate" such that they are activities  and then (7) and (8) don't sound so bad. This has made testing the hypothesis difficult. In addition, English appears to be changing to allow more psych verbs in the present progressive (darn you, McDonalds).


-------
Fisher, C., Gleitman, L. R., & Gleitman, H. (1991). On the semantic content of subcategorization frames. Cognitive Psychology, 23, 331-392.

Class Notes: This field confuses the hell out of me. I want to start from scratch.

I have now read 44 papers in the course of this semester's Language Acquisition seminar. The only firm conclusion I have come to is that language is so complicated that nobody could ever possibly learn one.



---
(The title of this post comes from the caption of a doodle of a mid-century Harvard psychologist, now enshrined in a display case on the 9th floor of William James Hall. Based on the time period, I think the doodler was either George Miller or Roger Brown, but I can't recall for sure.)