Reactions
Up Reactions 2
Before attempting this project, please do the very easy 'Random Number' Project.

The Reactions project is in two parts - you can access the second part via the link above.

The 'Reactions' project described below allows the user to measure his or her reaction time to the nearest one hundredth of a second. Initially it uses command buttons, then, in part 2, keys are used instead. In part 1 you will learn:

bullethow to generate random numbers
bullethow to convert decimal numbers to integers
bulletloops
bulletcomments
bullethow to use the Select...Case code structure as an alternative to the If...Then structure

Make a new Standard EXE project and save it immediately (using File/Save Project, not Ctrl-S) into a new folder called Reactions, giving the form file and project file the same name as the folder.

Make the form quite small and add a single command button. Set properties as follows:

bulletForm:
caption = Reaction Timer by (YOUR NAME HERE)
bulletCommand Button:
name = cmdReact
caption = Click me to start     (make sure the caption is exactly correct)
font = size 14

Your form should look like this:

We must make sure that the user cannot anticipate the timing of the event that will trigger his or her reaction, so we will make the user wait for a random time between 3 and 7 seconds for the event to occur. Since you have already completed the Random Number project, you should understand that a random decimal number between 3 and 7 can be generated with 3 + 4 * rnd().

We could use a Timer control to make the computer wait for this time, but instead we will use the Timer() function. This is very different to the Timer control - it is a function that simply returns the number of seconds that have elapsed since midnight. For example, if you use the Timer() function at one minute past midnight then it will return the number 60. This function doesn't sound very useful, but it is useful in many programs, as we shall see...

First, double-click the command button and type this code:

Private Sub cmdReact_Click()
Print Timer()
End Sub

Run the program, click the button a few times, and notice how the numbers are large, as you would expect, and how they increase a little between clicks.

Now let's get the reaction timer going. Set the command button's BackColor property to bright red and change its Style property to graphical (so that we can see the BackColor)

Then change its code to

Private Sub cmdReact_Click()
waittime = 3 + 4 * Rnd()
endtime = Timer() + waittime
Do Until Timer() >= endtime
	' Do nothing
Loop
Print waittime
End Sub

When you run this program and click the command button it should make you wait a few seconds and then tell you how long you had to wait. Try to understand the code!

This is the first time we have used a loop in any of our programs. Loops are a very important part of any programming language - they allow a block of code to be repeated many times. In some cases the programmer knows in advance how many times the loop should be repeated, and would probably use a "For...Next" loop. In this case, we don not know how many times the loop will repeat, so we use a "Do...Loop". The program repeats all the lines of code between the Do  line and the Loop line until the condition in the Do line is met (the condition can also be put in the Loop line). In this case, the condition is that the Timer() function returns a number greater than or equal to endtime.  (The endtime was calculated by adding the starting time and the waittime, a random number between 3 and 7). The only code inside our loop is a line that actually does nothing, for it is a comment. A comment is any code on any line that comes after an apostrophe (unless the apostrophe is itself part of a text string, i.e. between double quotes). In the following line, the computer will ignore the code that comes after the second apostrophe:

MsgBox ("This ISN'T a comment") ' This IS a comment

Note how VB makes comments easy to spot by coloring them green. What is the point of including code that we know the computer will ignore? To make the program easier to understand for anyone trying to read the code (this includes us, in a few months time, when we have forgotten how the program works!). It is a very good habit to include plenty of comments in all your programs.

To help make our programs easier to read, we indent all the lines inside a loop by putting a tab character at the beginning of each line, just as we do for IF structures.

Now I'll give you all the code for a working reaction timer. Type this very carefully, or you will have some difficult debugging to do. Underneath is an explanation - note that this code uses a Select Case structure, which is an alternative to an IF structure.

Private Sub Form_Load()
Randomize
End Sub

Private Sub cmdReact_Click()
Static endtime
Select Case cmdReact.Caption
Case "Click me to start"
	cmdReact.Caption = "Wait"
	cmdReact.BackColor = vbYellow
	endtime = Timer() + 3 + 4 * Rnd()
	Do Until Timer() >= endtime
		DoEvents
	Loop
	cmdReact.Caption = "Click me NOW!"
	cmdReact.BackColor = vbGreen
Case "Click me NOW!"
	Print Timer() - endtime
	cmdReact.Caption = "Click me to start"
	cmdReact.BackColor = vbRed
End Select
End Sub

The most important feature of the above code is the Select Case structure. This works by examining a certain expression and then matching it to different possible 'cases' - it's a good alternative to an IF structure when there are more than two cases to test for (it would be very possible to write this code using an IF structure if we wanted to). In our program the Select Case line takes a look at the caption of the command button, which can have one of two values (there will be three later on). If the caption is "Click me to start" then this will match the first Case line, so the following lines of code will be activated, and so on. The Select Case structure ends with End Select, just like an IF structure ends with End If. Also, the code for the various cases should be indented, again like in an IF structure.

To understand the function of DoEvents in the above code, try temporarily removing it or making it into a comment by putting an apostrophe in front of it. Now the command button does not turn yellow when it should because the computer is so busy doing the loop that it has no time for anything else. DoEvents is an instruction to do anything that is waiting to be done (the re-drawing of the button with its new color, in this case). 

In the code above, you noticed that VB understands certain constants such as vbRed and vbYellow - it doesn't have built-in constants for all colors, but it does understand the primary colors (vbRed, vbGreen, vbBlue), the secondary colors (vbYellow, vbMagenta, vbCyan), and also vbWhite and vbBlack.

The Static Endtime line declares the variable endtime in a way that you haven't seen before. Since this variable occurs only in one procedure there is no need to declare it in the General Declarations area at the top of the code window, but if we don't declare it at all then it will forget its value between successive clicks of the command button. By making the variable into a static variable we make sure that the variable does not forget its own contents.

Your program should work quite well, but it has a weakness... it's quite easy to cheat by repeatedly clicking the button very fast while it displays the "Wait" caption. We must do something to catch the cheats! Add another Case, as shown below:

Private Sub cmdReact_Click()
Static endtime
Select Case cmdReact.Caption
Case "Click me to start"
	cmdReact.Caption = "Wait"
	cmdReact.BackColor = vbYellow
	endtime = Timer() + 3 + 4 * Rnd()
	Do Until (Timer() >= endtime)
		DoEvents
	Loop
	cmdReact.Caption = "Click me NOW!"
	cmdReact.BackColor = vbGreen
Case "Click me NOW!"
	Print Timer() - endtime
	cmdReact.Caption = "Click me to start"
	cmdReact.BackColor = vbRed
Case "Wait"
	Print "You cheated!"
End Select
End Sub

This new case is activated if the user clicks the button while it has the caption "Wait". This happens while the loop is still running so the 'Click me now message' still appears as normal.

Your program is working really well now (if you followed my instructions carefully!). Can you think of ways of making it even better... for EXTRA CREDIT... Here are some suggestions:

bullet

Add a few comments to the program to help you or anyone else understand how your program works.

bullet

You probably noticed that the form soon fills up with times, so you have to stop the program and start again. Can you think of a solution, so that the program does not have to be re-started? You may want to use the CLS statement. This statement (meaning 'CLear Screen') will remove all the text that has been printed on the form.

bullet

It's annoying to see so many decimal places in the times - can you make them all appear to 2 decimal places only (use the Help system to find out about the Format() function?

bullet

Can you include a label that displays the user's best time, or average time, or number of cheat attempts or...  ?

Many users would prefer to use the spacebar on the keyboard to control the reaction timer, rather than the command button. To see how to do this, click HERE to move to part 2 of this project.

Reactions 2

Previous Up Next