4

我正在为 iPhone 使用 OpenGL ES 创建 2D 游戏。我正在使用 NSTimer 以 0.002 (60 fps) 的间隔调用我的游戏循环,并将重复设置为“NO”(我正在按照建议从函数内再次运行 NSTimer):


-(void)gameLoop:(id)sender {
    double currTime=(double)CACurrentMediaTime();
    m_FPS_framesThisSecond++;
    float timeThisSecond=currTime-m_FPS_lastSecondStart;
    if (timeThisSecond>1.0f) {
        m_FPS=m_FPS_framesThisSecond;
        m_FPS_framesThisSecond=0;
        m_FPS_lastSecondStart=currTime;
    }

    [game update];
    [game render];

        //Continue the loop
    [NSTimer scheduledTimerWithTimeInterval:0.002 target:self selector:@selector(gameLoop:) userInfo:nil repeats:NO];
}

这在我的 3GS 上运行流畅,但是当我在 2G 上测试时,游戏运行速度要慢得多,有时我会偶尔出现空白帧。当我将间隔降低到 0.033 (30 fps) 时。3G太慢了。

我知道必须有某种方法可以在两种设备上获得一致的播放。Doodle Jump 似乎在两部手机上运行流畅且帧率相同。

4

2 回答 2

2

本质问题是这样的:

您的游戏需要根据自上次渲染后经过的时间量进行更新,而不是根据渲染次数进行更新。假设您正在根据某个速度计算精灵的位置。新位置应该基于渲染之间的时间来计算,而不是假设自上次渲染以来已经过去了 0.002 秒。这称为 FPS 独立动画。

所以,这是一个简单的例子:

// FPS dependent animation
int x = sprite.x + sprite.velocity.x

正确的方法是使用自上次渲染以来的时间,并按比例更新。以下代码假定 0.002 是时基。

// FPS independent animation
int x = sprite.x + sprite.velocity.x * time_since_last_render/0.002

在渲染时间是两倍的设备上,下一次更新会将对象移动两倍的距离,因此它最终会在与更快的设备上相同的位置。

一个附带问题,您不应该总是在未来 0.002 秒后渲染下一帧。您应该看到当前帧渲染所用的时间,从 0.002 中减去它并使用它来安排下一次渲染。自然地,这个数字的最小值为零,因此在慢速设备上,您不会开始安排过去。例如,如果您的渲染函数需要 0.002 秒来渲染,这将不必要地降低您的帧速率一半。

于 2010-07-10T16:10:24.557 回答
2

实际上有两种类型的帧速率:

  • 显示帧率:屏幕重绘的速率
  • 逻辑帧率:游戏逻辑更新的速率(游戏速度)

我认为您正在寻找一个恒定的逻辑帧速率,它与根据手机硬件功能调整的显示帧速率分离。与必须为每个逻辑帧完成一个显示帧的游戏循环相比。

查看deWiTTERS 游戏循环中描述的“具有最大 FPS 的恒定游戏速度”算法游戏逻辑在 3G 和 2GS 上似乎以相同的速度运行,但显示帧速率将调整为较慢的 2G CPU。虽然上面的文章没有涉及,但您也可以限制显示帧速率以节省电池。

于 2010-07-10T16:15:02.110 回答