除了使用NSTimer,还有什么比在iPhone上创建游戏循环更好的方式呢?

时间:2022-03-22 21:59:28

I am programming a game on the iPhone. I am currently using NSTimer to trigger my game update/render. The problem with this is that (after profiling) I appear to lose a lot of time between updates/renders and this seems to be mostly to do with the time interval that I plug into NSTimer.

我正在用iPhone编程一个游戏。我目前正在使用NSTimer来触发我的游戏更新/渲染。这样做的问题是(在分析之后)我似乎在更新/渲染之间丢失了很多时间,这主要是由于我插入到NSTimer的时间间隔造成的。

So my question is what is the best alternative to using NSTimer?

我的问题是什么是使用NSTimer的最佳选择?

One alternative per answer please.

每个答案各有一个选择。

3 个解决方案

#1


18  

You can get a better performance with threads, try something like this:

您可以使用线程获得更好的性能,试试以下方法:

- (void) gameLoop
{
    while (running)
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        [self renderFrame];
        [pool release];
    }
}

- (void) startLoop
{
    running = YES;
#ifdef THREADED_ANIMATION
    [NSThread detachNewThreadSelector:@selector(gameLoop)
    toTarget:self withObject:nil];
#else
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0f/60
    target:self selector:@selector(renderFrame) userInfo:nil repeats:YES];
#endif
}

- (void) stopLoop
{
    [timer invalidate];
    running = NO;
}

In the renderFrame method You prepare the framebuffer, draw frame and present the framebuffer on screen. (P.S. There is a great article on various types of game loops and their pros and cons.)

在renderFrame方法中,您准备framebuffer,绘制frame,并在屏幕上显示framebuffer。(P.S.有一篇关于各种类型的游戏循环及其利弊的文章。)

#2


4  

I don't know about the iPhone in particular, but I may still be able to help: Instead of simply plugging in a fixed delay at the end of the loop, use the following:

我并不特别了解iPhone,但我可能仍然能够提供帮助:与其简单地在循环结束时插入一个固定的延时,不如使用以下方法:

  • Determine a refresh interval that you would be happy with and that is larger than a single pass through your main loop.
  • 确定一个刷新时间间隔,这个时间间隔要比通过主循环的单个时间间隔大。
  • At the start of the loop, take a current timestamp of whatever resolution you have available and store it.
  • 在循环开始时,取可用的任何分辨率的当前时间戳并存储它。
  • At the end of the loop, take another timestamp, and determine the elapsed time since the last timestamp (initialize this before the loop).
  • 在循环结束时,获取另一个时间戳,并确定自上次时间戳以来的运行时间(在循环之前初始化这个时间戳)。
  • sleep/delay for the difference between your ideal frame time and the already elapsed time this for the frame.
  • 为理想帧时间和已经经过的帧时间之间的差异进行睡眠/延迟。
  • At the next frame, you can even try to compensate for inaccuracies in the sleep interval by comparing to the timestamp at the start of the previous loop. Store the difference and add/subtract it from the sleep interval at the end of this loop (sleep/delay can go too long OR too short).
  • 在下一帧中,您甚至可以尝试通过与前一个循环开始时的时间戳进行比较来补偿睡眠时间间隔中的不准确性。将差异存储起来,并在这个循环的末尾从睡眠间隔中添加/减去它(睡眠/延迟可能太长或太短)。

You might want to have an alert mechanism that lets you know if you're timing is too tight(i,e, if your sleep time after all the compensating is less than 0, which would mean you're taking more time to process than your frame rate allows). The effect will be that your game slows down. For extra points, you may want to simplify rendering for a while, if you detect this happening, until you have enough spare capacity again.

您可能想要有一个警报机制,让您知道您的时间是否太紧(i,e,如果您的睡眠时间在补偿之后小于0,这意味着您处理的时间比您的帧速率允许的时间要长)。其结果是你的游戏会变慢。对于额外的点,您可能想要简化渲染一段时间,如果您检测到这种情况发生,直到您再次拥有足够的备用容量。

#3


0  

Use the CADisplayLink, you can find how in the OpenGL ES template project provided in XCODE (create a project starting from this template and give a look to the EAGLView class, this example is based on open GL, but you can use CADisplayLink only for other kind of games

使用CADisplayLink,您可以在XCODE中提供的OpenGL ES模板项目中找到如何(从这个模板创建一个项目并查看EAGLView类,这个例子基于open GL,但是您只能在其他类型的游戏中使用CADisplayLink

#1


18  

You can get a better performance with threads, try something like this:

您可以使用线程获得更好的性能,试试以下方法:

- (void) gameLoop
{
    while (running)
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        [self renderFrame];
        [pool release];
    }
}

- (void) startLoop
{
    running = YES;
#ifdef THREADED_ANIMATION
    [NSThread detachNewThreadSelector:@selector(gameLoop)
    toTarget:self withObject:nil];
#else
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0f/60
    target:self selector:@selector(renderFrame) userInfo:nil repeats:YES];
#endif
}

- (void) stopLoop
{
    [timer invalidate];
    running = NO;
}

In the renderFrame method You prepare the framebuffer, draw frame and present the framebuffer on screen. (P.S. There is a great article on various types of game loops and their pros and cons.)

在renderFrame方法中,您准备framebuffer,绘制frame,并在屏幕上显示framebuffer。(P.S.有一篇关于各种类型的游戏循环及其利弊的文章。)

#2


4  

I don't know about the iPhone in particular, but I may still be able to help: Instead of simply plugging in a fixed delay at the end of the loop, use the following:

我并不特别了解iPhone,但我可能仍然能够提供帮助:与其简单地在循环结束时插入一个固定的延时,不如使用以下方法:

  • Determine a refresh interval that you would be happy with and that is larger than a single pass through your main loop.
  • 确定一个刷新时间间隔,这个时间间隔要比通过主循环的单个时间间隔大。
  • At the start of the loop, take a current timestamp of whatever resolution you have available and store it.
  • 在循环开始时,取可用的任何分辨率的当前时间戳并存储它。
  • At the end of the loop, take another timestamp, and determine the elapsed time since the last timestamp (initialize this before the loop).
  • 在循环结束时,获取另一个时间戳,并确定自上次时间戳以来的运行时间(在循环之前初始化这个时间戳)。
  • sleep/delay for the difference between your ideal frame time and the already elapsed time this for the frame.
  • 为理想帧时间和已经经过的帧时间之间的差异进行睡眠/延迟。
  • At the next frame, you can even try to compensate for inaccuracies in the sleep interval by comparing to the timestamp at the start of the previous loop. Store the difference and add/subtract it from the sleep interval at the end of this loop (sleep/delay can go too long OR too short).
  • 在下一帧中,您甚至可以尝试通过与前一个循环开始时的时间戳进行比较来补偿睡眠时间间隔中的不准确性。将差异存储起来,并在这个循环的末尾从睡眠间隔中添加/减去它(睡眠/延迟可能太长或太短)。

You might want to have an alert mechanism that lets you know if you're timing is too tight(i,e, if your sleep time after all the compensating is less than 0, which would mean you're taking more time to process than your frame rate allows). The effect will be that your game slows down. For extra points, you may want to simplify rendering for a while, if you detect this happening, until you have enough spare capacity again.

您可能想要有一个警报机制,让您知道您的时间是否太紧(i,e,如果您的睡眠时间在补偿之后小于0,这意味着您处理的时间比您的帧速率允许的时间要长)。其结果是你的游戏会变慢。对于额外的点,您可能想要简化渲染一段时间,如果您检测到这种情况发生,直到您再次拥有足够的备用容量。

#3


0  

Use the CADisplayLink, you can find how in the OpenGL ES template project provided in XCODE (create a project starting from this template and give a look to the EAGLView class, this example is based on open GL, but you can use CADisplayLink only for other kind of games

使用CADisplayLink,您可以在XCODE中提供的OpenGL ES模板项目中找到如何(从这个模板创建一个项目并查看EAGLView类,这个例子基于open GL,但是您只能在其他类型的游戏中使用CADisplayLink