创建NSThread游戏循环

时间:2012-01-02 00:53:29

标签: iphone objective-c ipad game-loop

我试图创建一个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];

  } 

}

4 个答案:

答案 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:以秒为单位返回间隔,而不是毫秒。

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