Thread: How to build a timer that counts the seconds elapsed?

  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    158

    How to build a timer that counts the seconds elapsed?

    I'm doing this game for a school, project and one of the extras to have a better grade is a timer. I need to count the time (in seconds) elapsed while i'm running the game until I win it. Meaning, I start the game, the timer starts counting the seconds, I win the game, the timer stops and I need to return the number of seconds elapsed.

    One way to do this would be: get the system time at start and at the end, then calculate the seconds. However, I would like to have the timer on screen, chaging within each second. Is it possible without much code? How?

    I'll hear any other suggestion too...

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    SetTimer - if on Windows
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Fear the Reaper...
    Join Date
    Aug 2005
    Location
    Toronto, Ontario, Canada
    Posts
    625
    Instead of checking the timer at the start and end, in the game loop, just correct the timer on screen every time one second (or about one second) elapsed.
    Teacher: "You connect with Internet Explorer, but what is your browser? You know, Yahoo, Webcrawler...?" It's great to see the educational system moving in the right direction

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    It's relatively simple to do with any timing function. This example uses the standard C function time(), but clock() (also standard), SDL_GetTicks(), or any other timing function would work.
    Code:
    #include <stdio.h>
    #include <time.h>
    
    void loop(void) {
        time_t start, end;
        double elapsed;
    
        time(&start);  /* start the timer */
    
        do {
            time(&end);
    
            elapsed = difftime(end, start);
            /* For most data types one could simply use
                elapsed = end - start;
                but for time_t one needs to use difftime(). */
    
            printf("Time elapsed: &#37;f\n", elapsed);
        } while(elapsed < 10);  /* run for ten seconds */
    }
    With some thought, you can even implement pausing the game. Take the time the game was paused for and add that to the start time.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Registered User
    Join Date
    Mar 2006
    Posts
    158
    I forgot to tell I'm on linux...

    But I don't see how can I update the timer every second if my game has user input... I'm using ncurses by the way. And I'm using the getch() function to read input. When the code reaches a line with getch(), it won't continue without pressing any key, so, how can I update a timer every second with that restriction?

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    As you're beginning to see, it's a PITA when the timer is put with a program that does a lot of other things.

    But Wait! There's more! (says the Ronco wizard, Ron Popeil), because the timer won't look right UNLESS you check it about 3 or 4 times per second. Basically because the OS is busy doing other things - but it looks jerky and you can miss seconds if you don't check it at least 3 times per second.

    Every function and every loop in every function, that takes more than 1/3rd of a second, will need to have a little bit of timer code in them, to keep the clock right. Time is relentless and a 1/3rd of a second is not very long!

    But it's doable.

    IMO the start time & end time variables should be a global variables, because nearly every function will need access to them.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    IMO the start time & end time variables should be a global variables, because nearly every function will need access to them.
    Not really. You'd probably only need to access them perhaps three or four times: starting the timer, querying the timer, displaying the timer, and possibly pausing the timer.

    But I don't see how can I update the timer every second if my game has user input... I'm using ncurses by the way. And I'm using the getch() function to read input. When the code reaches a line with getch(), it won't continue without pressing any key, so, how can I update a timer every second with that restriction?
    kbhit(), or some equivalent. kbhit() returns true if there is a key in the input buffer, just waiting to be read. You'd use something like this:
    Code:
    void loop(void) {
        while(!quit) {
            paint_screen();
            if(kbhit()) process_key(getch());
        }
    }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    The easiest way (assuming you are on Win32) -

    Code:
    char szString[64];
    DWORD dwStartTime;
    DWORD dwElapseTime;
    RECT Rect; // rectangle of the client area
    HDC hdc; // DC of the client area
    
    dwStartTime = GetTickCount();
    while(TRUE){
    
         /* game code goes here */
    
         dwElapsedTime = (GetTickCount() - dwStartTime) / 1000;
         sprintf((char*)&szString[0] , "Time : %d\0" , dwElapsedTime);
         DrawText(hdc , (char*)&szString[0] , -1 , &Rect , DT_TOP | DT_CENTER );
    
         }

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    (char*)&szString[0]
    Why cast something if it's already of the type you are casting it to?

    Come to think of it, why not just use this?
    Code:
    szString
    I don't see why one would want to use non-standard timing functions if you can get away with the standard ones, especially if you only want second precision.

    [edit] Also, the "\0" is unnessesary, since the compiler automatically NULL-terminates string literals.

    And see below. [/edit]
    Last edited by dwks; 05-24-2007 at 04:43 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Hey guys: OP writes: "forgot to tell I'm on linux..."

    Window's code is irrelevant, in this case.

  11. #11
    Registered User
    Join Date
    Mar 2006
    Posts
    158
    I'm still confused and I don't understand how would I implement this on my code... For instance, I don't use the getch() directly, I have a custom function to read input with getch() to fit my needs. On another piece of code, I have while loop that will read the directional keys (to move the cursor in a matrix).

    The function I'm using is this:
    Code:
    void getInput(int l, int c, string str, int limit, bool pwd) {
    	int i = 0;
    	int ch = 0;
    	
    	// Activates the cursor and changes the input color
    	
    	curs_set(1);
    	attron(COLOR_PAIR(6));
    	
    	// Loops until the user presses the Return key
    	
    	while(ch != '\n') {
    		ch = mvgetch(l, c);
    
    		if(ch != '\n' && ch != '\t') {
    			// Did the user pressed the backspace key?
    			
    			if(i > 0 && (ch == KEY_BACKSPACE || ch == 127)) {
    				move(l, --c);
    				
    				attroff(COLOR_PAIR(6));
    				mvprintw(l, c, " ");
    				attron(COLOR_PAIR(6));
    				
    				refresh();
    					
    				i--;
    			} else {
    				// Is the char invalid or the user went over the limit?
    				
    				if(i < limit && (isalnum(ch) || isspace(ch))) {
    					str[i++] = (char)ch;
    					
    					// Hide input? (password)
    					
    					if(pwd) mvprintw(l, c++, "*");
    					else mvprintw(l, c++, "%c", ch);
    					
    					refresh();
    				}
    			}
    		}
    	}
    	
    	// Deactivates the cursor and removes the input color
    	
    	curs_set(0);
    	attroff(COLOR_PAIR(6));
    	
    	// Terminates the string and/or removes the line termination
    	
    	if(str[i-1] == '\n') {
    		str[i-1] = '\0';
    	} else {
    		str[i] = '\0';
    	}
    }
    And I use it like this:
    Code:
    char buffer[10];
    
    getInput(0, 0, buffer, sizeof(buffer)-1, FALSE);
    Could you provide me with the simplest and full example of how you would put a timer on screen updating everysecond and using getInput() to read user input? For instance, inside this loop:
    Code:
    do {
    	getInput(0, 0, buffer, sizeof(buffer)-1, FALSE);
    } while(buffer[0] != 'q');

  12. #12
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Perhaps using time.h and the built-in clock() function? You need to have a variable as a starting point then another for the current time. The time elapsed is equal to the difference between these. This would work on practically any OS as far as I know.
    High elevation is the best elevation. The higher, the better the view!
    My computer: XP Pro SP3, 3.4 GHz i7-2600K CPU (OC'd to 4 GHz), 4 GB DDR3 RAM, X-Fi Platinum sound, GeForce 460, 1920x1440 resolution, 1250 GB HDD space, Visual C++ 2008 Express

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    You need to put your line of code to display the current timer seconds, inside the body of any loop which might require more than about 1/3rd of a second.

    So in your getinput() function:
    Code:
    	// Loops until the user presses the Return key
    	
    	while(ch != '\n') {
    		show_time();  /* where show_time is your function to display the timer. */ 
                    ch = mvgetch(l, c);
    
    		if(ch != '\n' && ch != '\t') {
    			// Did the user pressed the backspace key?
    			
    			if(i > 0 && (ch == KEY_BACKSPACE || ch == 127)) {
    				move(l, --c);
    				
    				attroff(COLOR_PAIR(6));
    				mvprintw(l, c, " ");
    				attron(COLOR_PAIR(6));
    				
    				refresh();
    					
    				i--;
    			} else {
    				// Is the char invalid or the user went over the limit?
    				
    				if(i < limit && (isalnum(ch) || isspace(ch))) {
    					str[i++] = (char)ch;
    					
    					// Hide input? (password)
    					
    					if(pwd) mvprintw(l, c++, "*");
    					else mvprintw(l, c++, "&#37;c", ch);
    					
    					refresh();
    				}
    			 }
    		}
                    /* If any part of the program in the if or the else code above, 
                       takes longer than 1/3rd of a second, then you'll need to add your call to show_time() or just the code from it,                 
                       inside that block of code. That may need to INCLUDE an added call to it, put right inside the mvgetch() function! 
               
                       Practical experimentation is essential. Now you know what a PITA second by second timers are, IMO. Using the OS to 
                       work them for you, or working them in a separate thread, may help considerably lessen this pain.
                    */                  
    
    	}
    Last edited by Adak; 05-25-2007 at 03:04 PM.

  14. #14
    Registered User
    Join Date
    Mar 2006
    Posts
    158
    But I don't get how that would work... The show_timer() function is called and the timer will be shown, let's say 5seconds. In the next line the function mvgetch() will be called, which is waiting for user input, if I only press a key after 5 seconds, the timer will go from 5seconds to 10seconds, and what I want is the timer to be updated every second while i'm waiting for user input, that's my problem.

    If I'm waiting for user input, the code is "halted" in the getch() call, how can I update the timer if the code does not move from that line until I press a key? That's what I don't get and I don't see how all of your help would solve that... Maybe I'm too dumb, but I can't see it.

  15. #15
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Looking at the second message posted by dwks, in mvgetch(), you would need something like:
    Code:
    if (kbhit())
    {
       ch = getch();
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. PlaySound
    By cangel in forum C++ Programming
    Replies: 16
    Last Post: 10-08-2009, 05:29 PM
  2. calculate elapsed seconds
    By George2 in forum C# Programming
    Replies: 11
    Last Post: 04-21-2008, 01:18 AM
  3. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 05:49 PM
  4. Boom, Headoshot!!
    By mrafcho001 in forum A Brief History of Cprogramming.com
    Replies: 50
    Last Post: 07-21-2005, 08:28 PM