So I'm amidst my first iOS game and am struggling with how to go about the best way to integrate object movement.
The game relies heavily on fast moving objects and constant, fast user input changes. As such, I'm trying to have object integration and the constraint solver run as quickly and accurately as possible (to minimize user input change in between successive game loop calls).
More specifically, I'm unsure of the capabilities of the NSTimer class and CACurrentMediaTime() function. It's hard to test empirically because I'm not sure which have the larger error. For example, using an NSTimer with a repeating interval of 0.008 (~2updates/screen refresh) and calling CACurrentMediaTime() on successive calls, I find the time interval between calls varies from 0.0075 - 0.009. Hard to say which is responsible for the (small) inconsistency. So for determining the time step should I be:
Assume NSTimer is accurate enough to use the NSTimer time interval as the game loop time step
Use CACurrentMediaTime() to determine the time interval between successive game loop calls.
Student and new to all of this - please be nice :) Any advice is greatly appreciated. Thanks for your time.
NSTimer
is not a real-time timer. It's not even close, nor does it mean to be. If you're looking at anything faster than about half a second, NSTimer
is the wrong tool. I wouldn't even recommend it for things under a second. For multi-second things, and particularly multi-minute things, when you don't really care exactly when it fires, it's great. I use it all the time.
CACurrentMediaTime()
is not a timer. It's a wrapper around the most accurate time function in the system: mach_absolute_time()
. So if you really care what time it is right now, and you'd like that in a human-understandable number, CACurrentMediaTime()
is your function. mach_absolute_time()
will give you a really accurate number, but it's based on the Mach absolute time unit which doesn't actually map to anything pesky humans think in (and every CPU has a different scale). That's why we have CACurrentMediaTime()
to make our lives easier.
OK, so NSTimer
isn't for real-time, and CACurrentMediaTime()
isn't a timer. What's a game programmer to do?
Grand Central Dispatch includes some one of the best "make this run at about this time" systems we have. It's a Dispatch Source. I say "about this time" because GCD still isn't really "real time" in the way that RTOS guys mean it. But it's realtime enough for game developers. Look for Creating a Timer in the Concurrency Programming Guide. Also take a look at dispatch_after()
, which is good for one-shot "run this after a delay."
Remember, anything that runs on your main thread (the UI thread, where all the drawing is done), is going to share time with everything else on that thread. So often you're going to need to do calculations on a background thread while you handle drawing and user interaction on the main thread. This is the kind of thing that GCD dispatch_queues are designed to help you with. On the other hand, remember that many iOS devices are single-core. So "background thread" is a bit of a misnomer. Only one thing can really run at a time on the CPU. That's why moving things to the GPU is so important (see below).
You may also want to seriously look at systems like cocos2d, which is a very good game engine. It takes care of a lot of these kinds of details for you and lets you focus on the game part.
Staying in Apple frameworks, you should also take a look at Core Animation. If you're moving things around on the screen with timers, you shouldn't be doing that. Core Animation is how you move things around on the screen. It takes care of a lot of details for you, faster and using much less battery than you'd do on your own, and it moves a lot of the work to the GPU (as I mentioned above). It's a bit more designed for UI elements than games, but it can definitely be used to build simple games.
And of course there's GLKit, but that's a whole different thing....
According to the NSTimer documentation the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds.
which is probably why your seeing a variation in the time interval.
What I would suggest doing is change your update interval to 0.016 sec since there is no reason for your game state to update more often than the screen can draw it. Then you can use a CADisplayLink to handle the timing. This should be very accurate since its using the displays refresh rate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With