I am making a game and watch style game (remember Donkey Kong?) where all the enemies move at a set interval.
Eg. the barrels in donkey kong might move 1 step at precisely every 1 second. Accuracy is vital because the player needs to anticipate the movement and plan their jump.
I am using an NSTimer to run a function that essentially handles moving all the enemies forward one step. This was working great but then I noticed that every now and the enemies would briefly freeze, which wrecks the game. Reading the NSTimer documentation, it seems this is just the way it is when working with NSTimers.
What I tried:
I was originally using scheduledTimerWithTimeInterval but read another thread which suggested using timerWithTimeInterval along with
[[NSRunLoop currentRunLoop] addTimer:autoMoveTimer forMode:NSRunLoopCommonModes];
But I still noticed the freezing.
Instead of running the timer every second, I tried making it run much more often and then inside the function check the elapsed time with
NSTimeInterval elapsedTimeInterval;
elapsedTimeInterval = [gameTickerLastRan timeIntervalSinceNow];
if(elapsedTimeInterval<-gameSpeed){
NSLog(@"%f since ticker last ran",elapsedTimeInterval);
gameTickerLastRan=[NSDate date];
//do stuff in function
}
but still I noticed the freezing, even though the elapsed times being output seemed pretty accurate to me.
-1.006408 since ticker last ran
-1.006985 since ticker last ran
-1.007313 since ticker last ran
-1.007193 since ticker last ran
-1.006768 since ticker last ran
-1.007468 since ticker last ran
-1.007429 since ticker last ran
-1.006759 since ticker last ran
-1.007435 since ticker last ran
At the end of that function, after all the enemies had been moved on a step, I tried forcing the graphics to update with
[self performSelector:@selector(sweetNothings) withObject:nil afterDelay:0.0];
But this didn't help.
I briefly tried creating a dedicated thread for the timer but what I tried didn't work and I felt too out of my depth to experiment much with that.
The storyboard contains about 100 UIImageViews which are laid out like a frame by frame animation. I then turn these on and off using their hidden property to create the animation.
Can anyone suggest a rock solid way for me to run this function at a precise interval and get around the graphic freezing?
EDIT: I tried a CADisplayLink but it seems exactly the same - ie it is still freezing up for a second roughly every 10 seconds. This is what I have
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(gameTicker:)];
[displayLink setFrameInterval:1];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
and then in game ticker I have
CFTimeInterval elapsedTime = displayLink.timestamp - lastDrawTime;
NSLog(@"elapsed %f", elapsedTime);
if(elapsedTime>=gameSpeed){
//do stuff
lastDrawTime = displayLink.timestamp;
}
EDIT 2: Well I'm embarrassed to say that I just realised that it wasn't lag at all. I was removing elements while looping through an array forward, which was causing the illusion of lag. Thank you for pointing me to CADisplayLink anyway - looks very useful. Should I delete my question?