View Full Version : Game Loop in Cocoa
robmcq
2005.09.27, 01:10 PM
Does anyone know the best way to handle a game loop in Cocoa? A game loop being the loop of code where all of my game objects are updated. I thought using an NSTimer would be the best way but am unsure at this point. I could also use the GLUT but would rather keep this Cocoa oriented as possible. Does anyone have any ideas on this issue?
Thanks
unknown
2005.09.27, 01:14 PM
An NSTimer is probably the best way,
have you timer call an animate function, and then it can optionally call [self setNeedsDisplay:YES] (if its an NSView subclass).
Malarkey
2005.09.27, 01:23 PM
I usually use NSTimer's since that's the easiest way for me to set up a game loop. The other option is deriving from NSApp and overridding some of it's functions.
The following discussion (http://www.cocoadev.com/index.pl?AnimationTimingAndCocoaDiscussion) over at CocoaDev.com might be of interest to you as well.
robmcq
2005.09.27, 01:44 PM
Now, the only thing beyond that is that I noticed some animation wierdness when I was using Aqua GUI widgets to control some openGL variables. The animation loop would cycle the colors of a cube I set up in open GL. I also had some sliders to the side of an NSOpenGLView that would control things like rotation around the cube and the light vector. The problem I encountered was that the animation would stop whenever I would hold onto the slider. It's as if the Timer gets preempted whenever there is a GUI event taking place (like a slider move). Is there any way to force the Timer to update the animation while the user is holding on to the slider?
Rob
Taxxodium
2005.09.27, 01:47 PM
For the few games I've written, I used an NSTimer. Set it's repeat time to something like 0.03.
The screensavers in OS X use an NSTimer.
While you could make your own runloop, I don't recommend it. Don't make it hard on yourself :)
unknown
2005.09.27, 01:50 PM
[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSEventTrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSModalPanelRunLoopMode];
Taxxodium
2005.09.27, 01:52 PM
Is there any way to force the Timer to update the animation while the user is holding on to the slider?
Yes and no, you can do updates while a user is moving the slider without a timer. Just give the slider an action like this:
[mySlider setAction:@selector(updateStuff:)];
then write the method
- (void)updateStuff:(id)sender {
//update what you want
}
unknown
2005.09.27, 01:53 PM
That would work too, :)
Make sure you use smileys in the code though :p
robmcq
2005.09.27, 02:01 PM
Cool. Thanks so much guys. I can't believe how quickly I got all of my questions answered. You have a great community here.
Rob
akb825
2005.09.27, 02:49 PM
Using NSTimer is the easiest and quickest way to do it, but if you're doing anything complicated, it can cause quite a few problems. For example, if it's going to take a long time to draw the graphics or process some information on slower machines, your game can ground to a halt since it's then also waiting even longer to update the next screen after it's been working to update the current one.
If you're doing something that could possibly slow down to that point either this project or another project, you can do a while (true) loop in which you do the following:
Grab the next NSEvent using [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:true]. See if that event exists (checking if it's not nil), and if it does, process that event like you normally would based on its type.
After that, you will need to check the framerate every once in a while. To do this, set a certain number of frames you want to check (set a counter etc.), and have a struct timeval object (I call mine time). Then have 4 longs: current seconds, current microseconds, last seconds, and last microseconds. At first, call gettimeofday(&time, NULL); to get the time, then store time.tv_sec and time.tv_usec in the current seconds and microseconds, respectively. Then, every time it is to check the framerate, set the current time values to the old time values, then call getttimeofday again and put the time.tv_sec and time.tv_usec in the current seconds and microseconds again. Take the number of frames between each time you are sampling the framerate and divide that by the (current seconds - old seconds) + (current microseconds - old microseconds)*1e-6, and that gives you the framerate. Take 1 over the framerate, and multiply all your animations by that number, and the animations will stay constant, no matter the framerate. (this is assuming all your animations use seconds as their units of time, otherwise you might have to multiply by the framerate you're assuming, such as 30)
This definitely is more complicated, but it's also a lot more versatile. It's definitely a method worth looking.
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.