Game Timing (Cocoa)

Fletch
Unregistered
 
Post: #1
I'm just starting to work on my first OpenGL game (a humbling little tetris clone or something). The problem is that there's one thing I don't know how to do yet, and that's to give the game some kind of heartbeat I can use to regulate animations/gameplay.

I'm looking for a simple way to make the game tick every millisecond or ten for my main loop. Can somebody help me out?

I'm using C in project builder, like the Nehe OS X examples.

Thanks!
Quote this message in a reply
Member
Posts: 104
Joined: 2002.04
Post: #2
Check out NSTimer. It has what you want.
Quote this message in a reply
kainsin
Unregistered
 
Post: #3
I wouldn't use a timer based animation method for 3D animation, especially OpenGL. Since OpenGL ( and other 3D rendering API's ) only draw on the scan lines, you are guaranteed to not draw more than the monitor can handle.

Instead, when you want to draw one frame of animation, check to see how much time has passed. You can use the Carbon function Microseconds to accomplish this:

Code:
void Microseconds( UnsignedWide *microseconds );

Or if you don't want to use Carbon functions and want to leave it ANSI compatible then try:

Code:
include <sys/time.h>

int32_t GetMicroseconds( void ) { // int32_t is just an 'int' on PPC systems but that may change.

timeval returnValue;

gettimeofday( &returnValue, NULL );

return returnValue.tv_usec;
}

What's the point of seeing just how long it's been since the last frame of animation? Well, if you want the object to move 1.0 units in 1 second, all you have to do is see how far it needs to have moved since the last frame of animation ( # of milliseconds ) and divide the amount you want it to move in one second by that amount.

Example:

Code:
#define kMillisecondsPerSecond 1000000   // 1 million, this is prolly defined elsewhere
unsigned long lastFrameTime, currentFrameTime;

currentFrameTime = Milliseconds();

float distanceAlongXAxis = kXAxisMovementPerSecond /
    ( ( currentFrameTime - lastFrameTime ) * kMillisecondsPerSecond );

// Do this for y-axis ( and z-axis if 3D ) as well.

Now you may think that this will run too fast on faster machines, but this is not the case. Since this will only move the object a percentage of it's total movement in one second depending on how long the last frame has taken to draw, faster machines will only yield smoother animations. Hence the desired "high frame rates".

Side Note: You may want to check to make sure that currentFrameTime != lastFrameTime otherwise you'll end up having a divide-by-zero error. But if you have a computer set up to render anything even remotely difficult in zero-milliseconds then you are indeed 'The Man'.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
Two things:

gettimeofday is not ANSI, but POSIX.

tv_usec wraps back to 0 from 999999 every second, so you really want:

Code:
double getCurrentTime()
{
    struct timeval time;
    gettimeofday(&time, NULL);
        
    return (double)(time.tv_sec) + (double)(time.tv_usec) * 0.000001;
}

which returns the time as a double, where 1.0 is one second.
Quote this message in a reply
Fletch
Unregistered
 
Post: #5
I see,

That's great. I'll try these out and see how well it works for me. Thanks for all the help!
Quote this message in a reply
Feanor
Unregistered
 
Post: #6
Sorry to be contradictory, kainsin, but while you certainly want to be careful with your animation stepping, in a Tetris-style game, I don't imagine it's going to be necessary to have accurate timing of frame-drawing, since the frames will probably be drawn very, very fast.

There is no visibility culling, little or no depth sorting, probably no multi-pass rendering or anything else complicated, and on the order of a hundred polygons or less (more if the entire user-interface is done with OpenGL). The frame-rate unthrottled would probably be 100 or 200 fps or something. Most Tetris games don't even bother to animate the blocks smoothly, though -- they happily skip them forward exactly the size of a block, so only updating the screen when the animation steps are done would be perfectly acceptable.

You could probably set the speed of the game by the speed of the timer and leave it at that. Initially every half or two-thirds of a second between steps, and then a bit faster for each successive level of difficulty.

Now, if we're going to have smooth sliding left, right and down, and smooth rotations, that's a whole different thing :o).

FÎanor
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #7
You do still have to be a little careful, particularly if you're targeting OS9, but on either 9 or X it's possible to lose significant amounts of time to other processes, so you always have to be prepared to miss a frame.

What you choose to do in that situation, of course, is your own decision to make. For tetris, I'd probably be inclined to ignore it Smile
Quote this message in a reply
Fletch
Unregistered
 
Post: #8
Hm...

Correct me if I'm wrong, there might be something I'm not getting, but wouldn't it make the most sense in most cases just to have a loop that looks like this (in glorious Pseudocode Wink )

Code:
speed = 5;
now = some measure of time;
heartbeat =now + speed.

while (game is playing) {
    renderTheScene();
    if (now = heartbeat)
      {
           doCycleOfGameCode();
           heartbeat = now + speed;
       }
}


Wouldn't that work in Quake and in Tetris?
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  blocking function for timing purposes unknown 6 4,034 Feb 20, 2006 11:03 AM
Last Post: Skorche
  Drawing fps/Event timing using Carbon Nickolei 11 6,235 Jul 8, 2002 01:02 AM
Last Post: Jens