我想将游戏逻辑和渲染分成两个不同的循环,因为我不希望fps控制游戏速度。我尝试通过为渲染创建CADisplayLink以及为游戏逻辑创建NSTimer来实现此目的。但后来发生了一件奇怪的事情:
有时候(15个应用程序中有1个)游戏以非常低的fps(大约5-10)运行,但其余时间它完全平滑。如果我删除游戏逻辑的NSTimer并将两个循环结合起来,则fps一直很高,但这显然不是一个可接受的解决方案。所以看起来有时两个计时器“相互推迟”或类似的东西,但我并不完全理解runloops的内部工作。
以下是我创建计时器和displaylink的方法:
NSTimer *gameTimer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1.0 / 60.0 target:self selector:@selector(gameTimerFired:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
[gameTimer release];
CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
[aDisplayLink setFrameInterval:animationFrameInterval];
[aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.displayLink = aDisplayLink;
你能告诉我导致fps问题的原因以及解决方法吗?
或者你能推荐任何其他解决方案来分离渲染和游戏逻辑循环吗?
答案 0 :(得分:3)
您可以使用gameTimer或CADisplayLink通过测量自上次循环后经过的时间并使用它来增强游戏逻辑来实现此循环。
所以..
NSDate *oldTime = [[NSDate date] retain];
-(void)updateGame {
NSDate *curTime = [NSDate date];
NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:oldTime] * 1000.0;
[oldTime release];
oldTime = curTime;
[oldTime retain];
//use the timePassed_ms to augment your game logic. IE: Moving a ship
[ship moveLength:ship.velocity * timePassed_ms/1000.0];
}
这通常是我处理这类事情的方式。我通常喜欢在游戏对象中构建更新功能。所以更新船实际上看起来像这样:
[ship update:timePassed_mc];
答案 1 :(得分:1)
所以我最后使用Andrew Zimmer提出的建议,进行了一些微小的修改,因为我在相等的间隔内一起更新我的游戏对象。
所以我只使用一个循环,一个由CADisplayLink启动的循环。这是最终的代码:
- (void)drawFrame
{
if (!isGameTimerPaused)
{
NSDate *newDate = [NSDate date];
timeSinceLastUpdate += [newDate timeIntervalSinceDate:lastUpdateDate];
while (timeSinceLastUpdate > 1.0 / 60.0)
{
[self updateGame]; // UPDATE GAME OBJECTS
timeSinceLastUpdate -= 1.0 / 60.0;
}
[lastUpdateDate release];
lastUpdateDate = [newDate retain];
}
// DRAWING CODE HERE
(...)
//
}
答案 2 :(得分:0)
请注意,NSTimer不会给您任何可靠的时机。它很接近,但不能保证,如果你运行一个游戏循环,你会得到偶尔丢帧。
你可以在一个线程中做你的游戏逻辑,然后睡到下一帧(这不会是一个恒定的时间)。