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
- (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 に答える
1

同じ時間がかかると確信できないため、スレッドのスリープに依存しないでください。

したがって、スレッドをスリープ状態にする代わりに、何もしないでください (もちろん、固定時間ステップをインクリメントすることを除いて)

その場合、フレームレートがはるかにスムーズになることがわかります。

また、補足として、FPS をパフォーマンス指標として使用しないでください。1 回の更新が完了するまでにかかった時間を使用します。

@ 60fps を目指している場合、目標処理時間は 0.01666* 秒になるはずです。実際には、処理時間を 0.02555* (40 fps) に増やすことができ、ゲームのパフォーマンスに顕著な影響はないはずです。

編集:また、新しいプールを作成し、更新がヒットするたびに排出していることにも気付きました。私の経験では、自動解放プールは appDelegate などのより高いレベルに配置する必要があります。しかし、作成 (作成)/解放 (排出) レベルよりも低くすることはありません。これをさらに上に移動すると、パフォーマンスも向上します。

于 2012-01-02T01:23:18.943 に答える
1

CADisplayLinkAPI ( docs )に切り替えることをお勧めします。スリープする時間を把握しなくても、ディスプレイが更新されるたびに自動的に起動するタイマーを作成します。これにより、コードへの「更新」イベントの配信に関する問題は解決されますが、すべての問題が解決されるわけではありません。

明らかに、コードが 1/60 秒で終了できない場合、60 fps は得られません。ゲームのロジックと物理がビデオのリフレッシュ レートに結び付けられていないことを確認してください。CADisplayLink正しいことかどうかについて意見が分かれる人もいます。ただし、合意された代替手段は、ハードウェアが許す限り速く更新することです。

昨年、おもちゃのゲームのレンダリング ループを切り替えて、表示リンク (iOS ではなく Mac) を使用する必要がありました。ゲームの「滑らかさ」が大幅に改善されていることに気付きました。結果は異なる場合があります。

これを行う1つの方法は次のとおりです(半疑似コード、簡略化):

- (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 に答える
0

timeIntervalSinceDate:間隔をミリ秒ではなく秒単位で返します。

(これを本当の答えではなく、小さなコメントに書きたかったのですが、これを行う方法がわかりませんでした...)

于 2012-01-02T02:31:57.293 に答える