Page 1 of 1

Reaction Timer

Posted: Sun Oct 08, 2006 7:39 pm
by georgej
For my first post as a beginner to PureBasic, I would firstly like to thank the PB community for the helpful comments and lines of code on the forums. I have learnt so much from reading and trying to understand the code.

Rather than ask lots of questions, I have studied first and below is my rather simple effort at a reaction timer. It was done as a learning exercise in gadget interaction and how to get a thread to work, rather than a precision timer. It may look very simple to most, but it took me a long while to figure out the thread part. I have commented the code as I understand it. It does work but now I am left with a question, am I on the right track with PureBasic coding?

Code: Select all

; -------------------------------------------
; Title:    Reaction Timer
; Version:  1.1
; PB Ver:   4.00
;
; Author:   George Jopling
;
; About:
; A simple reaction timer for novelty use.
; 
; Use this code in any way you see fit.
; -------------------------------------------

;- Window Constants

Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants

Enumeration
  #Spin_Random
  #Button_Start
  #Text_Seconds
  #Text_Label_Spin
  #Text_Label_Seconds
  #Text_Status
EndEnumeration

Procedure timer() 
  SetGadgetText(#Text_Status, "[ Random delay started.  Get ready... ]") 
  
  StartDelay.b=(GetGadgetState(#Spin_Random)) ;Obtain value of Spin Gadget. 
  RandomStart.w = Random(StartDelay) ;Use Spin Gadget number as maximum for randomising start delay. 
  If RandomStart = 0 ;0 is a valid output of Random().  Add 1 if random result is 0. 
    RandomStart = RandomStart + 1
  EndIf 
  Delay(RandomStart*1000) ;Convert random delay number into milliseconds, as required by Delay().
  
  key.w = GetKeyState_( #VK_SPACE) ;API keyboard call. 
  If key & $8000 ;Check to see if the Space bar is being pressed when Delay() expires;
     DisableGadget(#Button_Start, 0)
     DisableGadget(#Spin_Random, 0) 
     SetGadgetText(#Text_Status, "[ Cheat! ]") ;Display a cheat message if it is.
    
  Else ;Space bar was not being pressed, continue with main reaction timer. 
    SetGadgetText(#Text_Status, "[ Go!  Press the Space bar Now! ]") 
    Beep_(500,50) ;API function to make sound from the computer speaker. 
    StartTime.d = ElapsedMilliseconds() ;Obtain a time reference point when the reaction timer started.
  
  Repeat ;Generate loop checking to see if the Space bar has been pressed.  Update displays accordingly. 
    key.w = GetKeyState_( #VK_SPACE) ;API keyboard call. 
    If key & $8000 ;Check to see if the Space bar has been pressed.
      DisableGadget(#Button_Start, 0)
      DisableGadget(#Spin_Random, 0) 
      SetGadgetText(#Text_Status, "[ Another go? ]")
      Break ;Break out of loop straight away if the Space bar has been pressed.
      
    Else ;If Space bar has not been pressed, update timer display etc.
      Delay(1) ;1 millisecond delay.  Essential to prevent 100 per cent processor usage.
      DisplayTime.f = ElapsedMilliseconds()-StartTime ;Obtain further time reference point and compare against start. 
      DisplayTimeSeconds.s = StrF(DisplayTime/1000, 3) ;Format display to 3 decimal places.
      SetGadgetText(#Text_Seconds,DisplayTimeSeconds) ;Display it.
    EndIf
    
  Until DisplayTime =  10000 ;Loop until maximum wait time for Space bar press (10 seconds). End loop if reached. 
    If DisplayTime = 10000 ;If it is the maximimum wait time, update accordingly.
    SetGadgetText(#Text_Status, "[ Slowcoach!  Another go? ]")
    DisableGadget(#Button_Start, 0)
    DisableGadget(#Spin_Random, 0)  
    EndIf
  EndIf
  
EndProcedure

Procedure Open_Window_0() ;Open the main window and display gadgets. 
  If OpenWindow(#Window_0, 410, 283, 264, 192, "Reaction Timer",  #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_WindowCentered )
    
    If CreateGadgetList(WindowID(#Window_0))
      SpinGadget(#Spin_Random, 170, 25, 55, 25, 1, 60) ;Set the spin gadget minimum value at 1 and maximum at 60.
      SetGadgetState (#Spin_Random,10) : SetGadgetText(#Spin_Random,"10") ;Set the spin gadget default at 10.
      ButtonGadget(#Button_Start, 85, 150, 80, 25, "Start Timer")
      TextGadget(#Text_Seconds, 120, 105, 105, 20, "0.000", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_Label_Spin, 30, 30, 125, 25, "Random Delay Maximum", #PB_Text_Center)
      TextGadget(#Text_Label_Seconds, 35, 105, 60, 25, "Seconds")
      TextGadget(#Text_Status, 35, 70, 190, 20, "[ Click Start Timer button. ]") 
    EndIf
    
  EndIf
EndProcedure

Procedure Event_Loop() ;Loop for events. Check to see what they are and process accordingly. 
  Repeat 
    Event = WaitWindowEvent()
    Select Event 
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Spin_Random ;Process gadget event.
            If GetGadgetState(#Spin_Random)<>Val(GetGadgetText(#Spin_Random)) ;Have gadget contents changed.
              If EventType()=#PB_EventType_Change ;Has a value been typed into gadget.
                SetGadgetState(#Spin_Random,Val(GetGadgetText(#Spin_Random))) ;Set gadget to current value.
              Else 
                SetGadgetText(#Spin_Random,Str(GetGadgetState(#Spin_Random))) ;Put value of button change into gadget.
              EndIf 
            EndIf 
            
          Case #Button_Start ;Start button pressed
            SetGadgetText(#Text_Seconds, "0.000")           
            DisableGadget(#Button_Start, 1) 
            DisableGadget(#Spin_Random, 1) 
            ThreadTimer=CreateThread(@timer(),"") ;Create a thread for the timing processes and display updates.  
        EndSelect  
    EndSelect 
  Until Event = #PB_Event_CloseWindow ;Exit the program if the close window button is clicked.
EndProcedure

Open_Window_0() ;Call the Open Window procedure to initialise the program and display on screen.
Event_Loop() ;Call the Event Loop to check for events and process them.

Posted: Sun Oct 08, 2006 8:03 pm
by Trond
You should post the code enclosed in code tags so the indentation is preserved.

Apart from that it seems to be well done. Your variables and gadget constants are sanely named.

Code: Select all

StartDelay.b=Val(Str(GetGadgetState(#Spin_Random)))
...
SetGadgetText(#Text_Status,"[ Slowcoach!  Another go? ]")
Personally I would have used a few more spaces like this:

Code: Select all

StartDelay.b = Val(Str(GetGadgetState(#Spin_Random)))
...
SetGadgetText(#Text_Status, "[ Slowcoach!  Another go? ]")
And have a look at this:

Code: Select all

StartDelay.b = Val(Str(GetGadgetState(#Spin_Random)))
Str() converts an integer to a string. Val() converts a string to an integer. So basically you're converting unnecessarily. You could have written it like this:

Code: Select all

StartDelay.b = GetGadgetState(#Spin_Random)
But overall, very well done for one of your first programs. I particularly like that you disable the button when it shouldn't be clicked. (I'm obsessive with these sort of details.)

Posted: Sun Oct 08, 2006 9:20 pm
by georgej
Thank you Trond.

I have edited my post to enclose the code in tags as you suggested.

Posted: Sun Oct 08, 2006 9:53 pm
by netmaestro
(I'm obsessive with these sort of details.)
No... really? You hide it so well... :lol:

Posted: Mon Oct 09, 2006 5:40 pm
by thefool
One huge mistake: If you press (and hold) spacebar before the beep you get a nice score ;)

Suggestion:
Make it check if the spacebar is pressed before and stop the game writing "Cheater!"

Posted: Mon Oct 09, 2006 6:47 pm
by dracflamloc
I would recommend in general for coding, even inside of procedures you should add extra lines and comments to 'section off' the code a bit more and make it more readable

Posted: Mon Oct 09, 2006 9:01 pm
by thefool
dracflamloc wrote:I would recommend in general for coding, even inside of procedures you should add extra lines and comments to 'section off' the code a bit more and make it more readable
Yeah. its way too compact.

Posted: Mon Oct 09, 2006 9:19 pm
by georgej
Thank you for taking the time to give your comments and feedback. It is appreciated. I have amended the code.

Posted: Mon Oct 09, 2006 10:58 pm
by thefool
georgej wrote:Thank you for taking the time to give your comments and feedback. It is appreciated. I have amended the code.
works great!