1

我试图创建一个 NSThread 游戏循环,我有一些时间能够成功获得 57 FPS。

有时我的 fps 会上升到一些可笑的数字。

我不明白它是如何发生的。

我检查自上次循环以来的时间,如果它很快,则让线程休眠这么长时间。

这并不总是发生,它有时会逃避 if 检查速度并以循环方式快速。

任何评论都意味着很多。

我应该在哪里“打勾”?

   - (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];

  } 

}
4

4 回答 4

1

您不应该依赖休眠线程,因为您永远无法确定它会花费相同的时间。

所以不要让线程休眠,什么都不做,什么都不做(当然除了增加你的固定时间步长)

你会发现你会有一个更平滑的帧速率。

另请注意,不要将 FPS 用作性能指标。使用完成单个更新所花费的时间。

如果您瞄准 @ 60fps,您的目标处理时间应该是 0.01666* 秒。实际上,您应该能够将处理时间增加到 0.02555*,即 40fps,并且对游戏的性能应该没有明显影响

编辑:我还注意到您正在创建一个新池并在每次更新时耗尽,根据我的经验,自动释放池应该放置在更高级别,例如 appDelegate。但是我不会把它降低到水平创建(创建)/释放(排出),进一步提高它也有助于提高性能。

于 2012-01-02T01:23:18.943 回答
1

我建议切换到CADisplayLinkAPI(文档)。它创建了一个计时器,该计时器会在显示器刷新时自动触发,而您无需计算睡眠时间。这将解决向您的代码传递“刷新”事件的问题,但它不会解决您的所有问题。

显然,如果您的代码无法在 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();
}
于 2012-01-02T02:10:39.877 回答
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];
}
于 2013-01-04T07:15:59.990 回答
0

timeIntervalSinceDate:返回以秒为单位的间隔,而不是毫秒。

(我想在一个小评论中写这个,而不是在一个真正的答案中,但无法弄清楚如何做到这一点......)

于 2012-01-02T02:31:57.293 回答