2011-10-27 151 views
6

我想將遊戲邏輯和渲染分成兩個不同的循環,因爲我不想讓fps控制遊戲速度。我試圖通過創建用於渲染的CADisplayLink和用於遊戲邏輯的NSTimer來實現此目的。但是後來發生了一件奇怪的事情:遊戲運行速度非常低(大約5-10),但其餘的時間都非常流暢。有時候(15個應用程序中有1個運行)遊戲運行速度非常低(大約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

你不應該創建兩個循環脫離遊戲的速度和FPS ... – thedaian

+0

然後,我怎麼能與一個循環做到這一點? – mikabast

回答

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]; 
+0

感謝您的建議。它激發了我最終的解決方案(見下文)。 – mikabast

0

請注意,NSTimer不會給你任何可靠的時機。它很接近,但不能保證,如果你運行一個遊戲循環,你會偶爾出現丟幀。

你可以在一個線程中完成你的遊戲邏輯,並且一直睡到下一幀(這不會持續一段時間)。

+0

NSTimer不是真的可靠,但從用戶體驗角度來看,每秒56次更新或每秒64次更新並沒有真正改變。但是,如果我只在繪製時更新遊戲對象,那麼在速度較慢的設備上運行速度提高兩倍時,它可以在較慢的設備上每秒下降20或30次更新。 – mikabast

1

所以最後我用什麼安德魯·席莫認爲,有一些微小的改動,因爲我更新自己的遊戲等間隔之間的對象在一起。

因此,我只使用一個循環,即由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 
    (...) 
    // 
} 
+0

很高興這是爲你工作!請注意,如果您在updateGame函數中進行了大量處理(例如很多對象之間的碰撞檢測),則可能會出現性能下降。 乾杯! –