我试图创建一个NSThread游戏循环,我有一些时间能够获得成功的57 FPS。
有些时候我的fps达到一些嘲笑数字。
我不明白它是如何发生的。
我检查自上一次循环以来有多长时间以及是否快速,让线程睡了很长时间。
这并不总是发生,它有时会逃脱对速度的检查,并以循环方式快速进行。
任何评论都意味着很多。
我在哪里接触“嘀嗒”字样。 ?
- (void)gameLoop{
//gameIsRunning is set to TRUE in viewDidLoad
while (gameIsRunnning){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Get Current date
NSDate *curTime = [NSDate date];
//Time since last loop and vurrent date;
NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:old_date];// * 1000.0;
NSLog(@"***************");
//Cout the time interval
NSLog(@"Loop Time %f",timePassed_ms);
//Check if the loop was to fast and sleep for long enough to make up for about 60 FPS
if (timePassed_ms < 1.0/60) {
double timeToSleep = timePassed_ms - (1.0/60);
timeToSleep = timeToSleep*-1;
NSLog(@"Sleep For %f",timeToSleep);
[NSThread sleepForTimeInterval:timeToSleep];
}
//This new date is to try and check if after waiting the loop is taking the correct duration
NSDate *newDate = [NSDate date];
NSTimeInterval timePassed_after = [newDate timeIntervalSinceDate:curTime];// * 1000.0;
//Make an fps out of this new time interval after wait
double FPS = (1.0/timePassed_after);
NSLog(@"FPS %f",FPS);
NSLog(@"Adjusted Time %f",timePassed_after);
NSLog(@"***************");
//Reset olddate for next loop
old_date = curTime;
//Apparently this will capture touches and button events
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);
//A test on moving a ball to see how smooth it will be
[self performSelectorOnMainThread:@selector(moveBall) withObject:nil waitUntilDone:NO];
[pool drain];
}
}
答案 0 :(得分:1)
你不应该依赖于睡眠线程,因为你永远无法确定它会花费相同的时间。
因此,不要让线程睡眠,不做任何事情,什么都不做(当然除了增加你的固定时间步骤)
您会发现帧速率会更加平滑。
另外,请注意,不要将FPS用作性能指标。使用完成单个更新所需的时间。
如果你的目标是@ 60fps,你的目标处理时间应为0.01666 *秒。实际上你应该能够将你的处理时间增加到0.02555 *,即40fps,游戏中不应该有明显的性能影响
编辑:我也注意到你每次更新时都会创建一个新池并耗尽,根据我的经验,自动释放池应放在更高级别的appDelegate。但是我不会把它降低到水平创建(创建)/释放(排水),进一步向上移动也有助于提高性能。
答案 1 :(得分:1)
我建议切换到CADisplayLink
API(docs)。它创建了一个计时器,可以在显示器刷新时自动触发,而无需计算出睡眠时间。这将解决向代码提供“刷新”事件的问题,但它无法解决您的所有问题。
显然,如果您的代码无法在1/60秒内完成,那么您将无法获得60 fps。确保您的游戏逻辑和物理与视频刷新率无关。有些人不同意CADisplayLink
是否正确。但是,商定的替代方案是尽可能快地更新硬件。
去年,我在玩具游戏中切换了渲染循环,我不得不使用显示链接(Mac,而不是iOS)。我注意到游戏感觉“平稳”的显着改善。您的结果可能会有所不同。
这是一种方法(半伪代码,简化):
- (void)update:(CADisplayLink *)link {
now = gettime();
while (gametime < now) {
// Physics always updated at rate of 1/delta
advanceframe();
gametime += delta;
}
draw();
}
答案 2 :(得分:1)
- (void) gameLoop
{
NSAutoreleasePool* loopPool = [NSAutoreleasePool new];
int loopCnt = 0;
while ( isRunning ) {
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);
[self draw];
select(0, 0, 0, 0, &tm);
if ( loopCnt > 20000 ) { // 20000
loopCnt = 0;
[loopPool release];
loopPool = [NSAutoreleasePool new];
}
++loopCnt;
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);
}
[loopPool release];
}
答案 3 :(得分:0)
timeIntervalSinceDate:
以秒为单位返回间隔,而不是毫秒。
(我想在一个小评论中写这个,而不是真正的答案,但无法弄清楚如何做到这一点......)