2010-03-11 76 views
6

我是iPhone新手,但嘗試構建2D遊戲。我在下面的一本書,但它基本上創建遊戲圈說:這是一個爲iPhone遊戲做遊戲循環的好方法嗎?

function gameLoop 
    update() 
    render() 
    sleep(1/30th second) 
    gameLoop 

的理由是,這將在30fps的運行。然而,這看起來有點心理上的問題,因爲如果我的幀花費了1/30秒,那麼它將以15fps運行(因爲它將花費與更新一樣多的時間)。

因此,我做了一些挖掘並找到了將同步調用我的gameLoop函數到刷新率(或其一部分)的CADisplayLink類。我找不到它的很多樣本,所以我在這裏發佈代碼審查:-)它似乎按預期工作,它包括將已用(幀)時間傳遞到Update方法,所以我的邏輯可以是幀率(但是我實際上無法在文檔中找到如果我的框架花費的時間超過了允許的時間,CADisplayLink會執行什麼操作 - 我希望它盡最大努力追上,並且不會崩潰!)。

// 
// GameAppDelegate.m 
// 
// Created by Danny Tuppeny on 10/03/2010. 
// Copyright Danny Tuppeny 2010. All rights reserved. 
// 

#import "GameAppDelegate.h" 
#import "GameViewController.h" 
#import "GameStates/gsSplash.h" 

@implementation GameAppDelegate 

@synthesize window; 
@synthesize viewController; 

- (void) applicationDidFinishLaunching:(UIApplication *)application 
{ 
// Create an instance of the first GameState (Splash Screen) 
[self doStateChange:[gsSplash class]]; 

// Set up the game loop 
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(gameLoop)]; 
[displayLink setFrameInterval:2]; 
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

- (void) gameLoop 
{ 
// Calculate how long has passed since the previous frame 
CFTimeInterval currentFrameTime = [displayLink timestamp]; 
CFTimeInterval elapsed = 0; 

// For the first frame, we want to pass 0 (since we haven't elapsed any time), so only 
// calculate this in the case where we're not the first frame 
if (lastFrameTime != 0) 
{ 
    elapsed = currentFrameTime - lastFrameTime; 
} 

// Keep track of this frames time (so we can calculate this next time) 
lastFrameTime = currentFrameTime; 

NSLog([NSString stringWithFormat:@"%f", elapsed]); 

// Call update, passing the elapsed time in 
[((GameState*)viewController.view) Update:elapsed]; 
} 

- (void) doStateChange:(Class)state 
{ 
// Remove the previous GameState 
if (viewController.view != nil) 
{ 
    [viewController.view removeFromSuperview]; 
    [viewController.view release]; 
} 

// Create the new GameState 
viewController.view = [[state alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self]; 

// Now set as visible 
[window addSubview:viewController.view]; 
[window makeKeyAndVisible]; 
} 

- (void) dealloc 
{ 
[viewController release]; 
    [window release]; 
    [super dealloc]; 
} 

@end 

任何反饋將:-)

PS可以理解。如果你可以告訴我爲什麼所有書籍都使用「viewController.view」,但其他所有內容似乎都使用「[object name]」格式,那麼獎勵分數就可以。爲什麼不[viewController視圖]?

+0

雖然這段代碼有效,但它似乎有點結結巴巴。幀率不低,看起來不太平坦。我認爲這可能是因爲我正在同步幀速率,然後在我的遊戲循環中更新*。渲染是在drawRect中完成的。 我想我的代碼應該直接繪製在所謂的方法中(也許更新應該在繪製之後完成),但是我找不到任何CADisplayLink的好例子。 – 2010-03-12 07:06:23

+0

我改變了我的精靈的運動速度爲每秒30像素,並且它看起來非常平滑(偶爾會丟失幀),所以我認爲這只是我設定的速度 - 例如。每幀移動略多於一個像素,這意味着它最終會在一幀中跳躍兩個像素,使其看起來不均勻。我想這是不可避免的。 – 2010-03-12 18:07:21

回答

2

你有Cocos2D在你的問題中列爲標籤,但你實際上沒有使用任何Cocos2D代碼。你有沒有考慮過爲你的遊戲做一個Cocos2D實現?它會爲您節省一些不必要的麻煩。

至於你的語法問題[myObject view]用於調用方法myObjectmyObject.view用於設置/獲取作爲屬性公開的實例變量。我不記得您是否可以使用[myObject view]來檢索實例變量,但如果這樣做有效,那麼我猜兩者之間的唯一區別就是語法,您可以使用這兩種方法來檢索實例變量。

希望一些散漫對你有用。

+0

哎呀!告訴你我不知道我在做什麼!現在刪除標籤。 在語法上做了一些閱讀,現在理解它更好。似乎[myclass屬性]和myclass.property可以做不同的事情。首先是一個屬性(它可以執行代碼,儘管在大多數情況下我懷疑它只是返回變量),而點直接訪問變量(並且不具有自定義代碼)。 似乎暴露私人領域和C#中的屬性之間的差異,只是在這裏他們可以看起來都有相同的名字! – 2010-03-11 20:46:15

+0

其實,現在我很困惑,因爲我得到的錯誤: 訪問未知'rect'getter方法 這使我認爲使用點與使用get/set方法完全相同! – 2010-03-11 21:22:50

+0

如果使用圓點,則需要將要檢索的實例變量定義爲屬性,然後將其合成。查找「@property」和「@synthesize」調用的語法。 getter/setter方法會爲您隱式創建,但只能在使用@synthesize之後。這就是爲什麼你會得到一個未知的「矩形」吸氣方法。 – 2010-03-11 21:40:16

-2

從Apple的許多GL例子中,我認爲你應該使用計時器。

animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/60.0) 
                target:self 
               selector:@selector(updateAndRender) 
               userInfo:nil 
               repeats:TRUE]; 
+0

我相信CADisplayLink是作爲一種更好的方式添加的,但是因爲它只是最近才被添加,似乎很少有文檔/樣本:( – 2010-04-13 19:41:24