如何在不使用NSTimer的情况下在iPhone上进行游戏循环

如何在不使用NSTimer的情况下在iPhone上进行游戏循环,iphone,opengl-es,loops,Iphone,Opengl Es,Loops,为了将我的游戏干净地移植到iPhone上,我正在尝试制作一个不使用NSTimer的游戏循环 我注意到,在一些示例代码中,如果使用NSTimer,您会在开始时使用以下内容进行设置 self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES]; 其中drawVi

为了将我的游戏干净地移植到iPhone上,我正在尝试制作一个不使用NSTimer的游戏循环

我注意到,在一些示例代码中,如果使用NSTimer,您会在开始时使用以下内容进行设置

    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
其中drawView看起来像:


- (void)drawView 
{
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    mFooModel->render();
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

while(gGameState != kShutDown)
{
    [self drawView]
}
当使用此技术时,mFooModel渲染效果很好,但我希望创建自己的调用drawView的游戏循环,而不是让NSTimer每秒调用drawView 60次。我想要一些像:


- (void)drawView 
{
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    mFooModel->render();
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

while(gGameState != kShutDown)
{
    [self drawView]
}
不幸的是,当我这样做时,我得到的只是一个黑屏。为什么会发生这种情况?我是否可以实现我在这里描述的内容

我想避免NSTimer的原因是因为我想在游戏循环中进行物理和AI更新。我使用自己的时钟/计时器来记录经过的时间量,以便能够准确地完成这项工作。渲染速度尽可能快。我尝试使用中描述的一些技术

这是一个有点冲动的问题(这是一个你在编码了一整天之后做的问题,陷入困境,希望早上答案就在那里)


各位干杯。

如果您不想使用
NSTimer
可以尝试手动运行:

static BOOL shouldContinueGameLoop;
static void RunGameLoop() {
    NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
    NSDate *destDate = [[NSDate alloc] init];
    do {
        // Create an autorelease pool
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        // Run the runloop to process OS events
        [currentRunLoop runUntilDate:destDate];
        // Your logic/draw code goes here
        // Drain the pool
        [pool drain];
        // Calculate the new date
        NSDate *newDate = [[NSDate alloc] initWithTimeInterval:1.0f/45 sinceDate:destDate];
        [destDate release];
        destDate = newDate;
    } while(shouldContinueGameLoop);
    [destDate release];
}

iPhoneOS 3.1的另一个选项是使用新的CADisplayLink api。这将在需要更新屏幕内容时调用您指定的选择器

displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(renderAndUpdate)];
[displayLink setFrameInterval:2];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

如果您需要更多示例代码,XCode中新的OpenGL项目模板也会使用CADisplayLink。

而使用CADisplayLink对于基于3.1的游戏来说确实是一个不错的选择,
任何使用“定时器”的东西都是个糟糕的主意

最好的方法是使用旧的“三重缓冲”来解耦GPU的工作

法比恩在他的末日Iphone评论中有一个很好的解释:

关于Fabien的CADisplayLink和iPhone末日文章,我给Fabien发了电子邮件,我认为最好的选择是主观的。性能方面的DisplayLink和三重缓冲应该相同,但DisplayLink仅在>OS 3.1上可用。因此,这应该是您的决定因素。

小心使用
self
作为
displayLinkWithTarget
的目标,手册上说“新构建的显示链接保留了目标”。
Martin

我忘了提醒你,如果你的工作时间超过1/45秒(或者runloop暂停时间超过1/45秒),你就会出现口吃、触摸事件延迟和其他奇怪的问题。一定要彻底测试。更新代码以解释这一点是可能的,但应用程序特定运行循环中的所有alloc/dealloc不都会影响性能吗?有没有办法把这一切都排除在外?几乎没有。池在那里,因此如果runloop创建临时对象,它们将被释放而不是建立。这两个
NSDate
s是水桶里的一小滴。我很抱歉问了一个愚蠢的问题,但是这个代码必须插入到项目的哪个地方?它是否覆盖了一些cocoa类的静态方法和道具?还是应该显式调用RunGameLoop?是否需要为DisplayLinks添加NSAutoreleasePool?不需要NSAutoreleasePool。在XCode中创建一个新的基于OpenGL的项目,您将了解如何使用它。