Best way to set up your main loop?

Nibbie
Posts: 3
Joined: 2008.09
Post: #1
Hi, i've been programming with C++ for a while, and little Objective-C, and and done a lot of work with Opengl, anyways now I want to make an actual game but I would like to have a main loop that will update as fast as possible, instead of using something like NSTimer and it would be nice to keep it in main(), and stick to as much c/c++ as possible, do I even need a Nib file? anyways heres an example of the way I'd like to set it up:

Code:
void main( int argc, const char ** argv ) {
    // Init game
    Game * game = new Game();
    game->Init();            // This would initialize various game things, as well as creating the window etc
    
    while ( game-IsPlaying() ) {
        // Check for events    
        for each event {
            if event is key press {
                game->keyDown( event->key );
            }
            else if event is mouse clicked {
                game->mouseclicked( event->mousePos )
            }
            etc
        }
        game->Update();
        game->Render();
    }
    delete game;
    // whatever else needs to be deleted
    return 0;
}

for the events I was thinking of using something like this:

Code:
while ( event = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES] ) {
    switch ( [event type] ) {

Is it possible to start the events without using NSApplicationMain() or something?
Can you do something like this in carbon? from what I read it looked like you had to register functions to be called on the events which doesn't really fit this design. Is there a better / more preferred way to go about doing this? Any tips / suggestions are welcome, thanks Smile
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
Just use a standard Cocoa event loop with a timer. There's no reason not to.

The way you want it is all backward.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #3
The old skool way of looping constantly simply makes no sense nowadays.

Riraito Wrote:I would like to have a main loop that will update as fast as possible

You don't want that because it is terribly inefficient.

You want your update to be called no more and no less often than what your physics integration expects. Typically that will be somewhere between 60 and 120 Hz.

More importantly, you don't want your rendering to be called any more or any less than (an exact multiple of) the screen refresh , which is typically near 60 Hz for LCDs. You need to synch to VBL to achieve this. You can try to setup a timer to match the system's VBL, but I've seen my best results by setting a timer for 1 kHz (essentially over-revved) and synching to VBL, which will automatically block your drawing to time it with the display refresh and block out the extraneous draws.

Further, you want update and drawing happening separately from each other -- Check out ThemsAllTook's tutorial for a little more info on this concept.

It makes no sense to draw more times than the monitor can display (except to test FPS during development), and it makes even less sense to update your physics any more than is enough to do the job.
Quote this message in a reply
Nibbie
Posts: 3
Joined: 2008.09
Post: #4
AnotherJake Wrote:More importantly, you don't want your rendering to be called any more or any less than (an exact multiple of) the screen refresh , which is typically near 60 Hz for LCDs. You need to synch to VBL to achieve this. You can try to setup a timer to match the system's VBL, but I've seen my best results by setting a timer for 1 kHz (essentially over-revved) and synching to VBL, which will automatically block your drawing to time it with the display refresh and block out the extraneous draws.

This makes sense, but how do you sync it, is there a function or something to wait for it, or how exactly do you do that?

AnotherJake Wrote:Further, you want update and drawing happening separately from each other --

Yeah I guess I wasn't very specific about that, but I had intended to do that inside game->Update, but I'm curious wouldn't you want your game to update at least as fast as your frames are or it would effectively lower your framerate? say you are only updating every 33ms ( about 2 frames at 60fps ), then wouldn't 60fps only look like 30 fps?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
Code:
GLint vsync = 1;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &vsync);

And of course, there's an NSOpenGLContext mirror of that functionality.

With vsync turned on, CGLFlushDrawable() and -[NSOpenGLContext flushBuffer] will block until the screen is ready. Roughly. That limits your refresh rate to the screen's rate.

Obviously, you want your physics running at a constant rate which is unlikely to have anything to do with the screen refresh rate, so you need to disassociate the two somehow; ThemsAllTook's tutorial describes the easiest way.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #6
Riraito Wrote:This makes sense, but how do you sync it, is there a function or something to wait for it, or how exactly do you do that?

Yes, easy:

Code:
GLint    vblSynch = 1;
[[self openGLContext] setValues:&vblSynch forParameter:NSOpenGLCPSwapInterval];

[edit] rats, beat by OSC by mere seconds... [/edit]

Riraito Wrote:Yeah I guess I wasn't very specific about that, but I had intended to do that inside game->Update, but I'm curious wouldn't you want your game to update at least as fast as your frames are or it would effectively lower your framerate? say you are only updating every 33ms ( about 2 frames at 60fps ), then wouldn't 60fps only look like 30 fps?

Yes, that's correct, you can effectively lower your frame rate -- and it rarely looks good. There are a few things to consider with this.

First, I should say that the happy medium I've found is 110 ticks per second for some unknown reason. Others pick different values (120, 85, etc.). It's arbitrary, but usually within limits (like I said, 60 to 120 Hz seems best). I think Carmack was saying once that he does 60 ticks per second with Doom 3. Which also makes sense because the flip side of the argument is that there is no sense updating physics faster than it can be displayed.

I seem to recall somewhere that 110 Hz is where humans stop experiencing any motion sickness due to the rate. Of course, that has nothing to do with a 60 Hz LCD since that lowers it, but 110 also seems to have a fairly happy beat frequency with other display refresh rates, from what I've seen.

Generally speaking, physics integration is going to prefer 60 Hz or higher. I've tried 30 Hz updates and even lower in testing, just to see what the effect would be, but clearly, at least as high a rate as your display refresh and even higher is preferable.

And yet another issue to consider is network synchronization if you want to do multiplayer. A solid update rate being as close to identical across players is going to make for a more fair game according to what I've read from Carmack and the Epic guys like Sweeny. Obviously many people have different refresh rates for their displays, so decoupling update rate from rendering rate is important in this respect as well.

Keeping update decoupled from drawing is also very handy for multi-threaded programming to take advantage of multiple processors.

There is a thread a short while back where I slapped together a quick Pong thingy which demonstrates how I usually do it single-threaded : http://www.idevgames.com/forum/showthread.php?t=15317
Quote this message in a reply
Nibbie
Posts: 3
Joined: 2008.09
Post: #7
ok, sounds good, thanks for the help Grin
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Main loop in Carbon/C++ DaveF 2 2,441 Aug 6, 2006 05:37 AM
Last Post: DaveF