0

这是我的游戏循环代码:

        while (shouldUpdate)
        {
            timeSinceLastUpdate = 0;
            startTime = clock();

                while (timeAccumulator >= timeDelta)
                {
                    listener.handle();
                    em.update();
                    timeAccumulator -= timeDelta;
                    timeSinceLastUpdate += timeDelta;
                }

            rm.beginRender();
                _x->draw();
            rm.endRender();

            timeAccumulator += clock() - startTime;
        }

它运行几乎完美,但它有一些抖动,每秒几次而不是 _x(它在更新中所做的所有测试实体都是 x++)向右移动 1 个像素,它实际上向右移动 2 个像素并且这是一个明显的滞后/抖动效应。我猜 clock() 不够准确。那么我能做些什么来改善这个游戏循环呢?

如果重要的话,我会使用 SDL 和 SDL_image。

编辑:做了比时钟更准确的事情后没有任何改变。但是,我发现,这一切都归功于 timeDelta。这就是我发表这篇文章时 timeDelta 的定义方式:

double timeDelta = 1000/60;

但是当我在乱七八糟的时候把它定义为别的东西......

double timeDelta = 16.666666;

我注意到游戏开始的最初几秒钟,它像黄油一样光滑。但仅仅几秒后,游戏就卡顿得厉害,然后又恢复了流畅,就这样重演了一遍。我添加的 6 (或 . 之后的任何内容)越多,游戏最初流畅的时间越长,并且延迟越严重。似乎浮动错误正在攻击。那我该怎么办?

EDIT2:我已经尝试了很多东西,现在它甚至都不好笑......有人可以帮我解决循环的数学部分吗?既然这就是造成这种情况的原因...

EDIT3:我给一些人发了一个测试程序,有人说它非常流畅,其他人说它像我描述的那样紧张。对于愿意在这里测试它的任何人,它是(src):https ://www.mediafire.com/?vfpy4phkdj97q9j

EDIT4:我将链接更改为 source code

4

1 回答 1

7

这几乎肯定是因为clock()

使用std::chronoSDL_GetTicks()来测量自纪元以来的时间。

我会推荐使用std::chrono只是因为我更喜欢 C++ api,这里有一个例子:

int main(){
    using clock = std::chrono::high_resolution_clock;
    using milliseconds = std::chrono::milliseconds;
    using std::chrono::duration_cast;

    auto start = clock::now(), end = clock::now();
    uint64_t diff;


    while(running){
        diff = duration_cast<milliseconds>(end - start).count();
        start = clock::now();     

        // do time difference related things

        end = clock::now();
    }
}

要仅在指定的增量后更新,您可以像这样执行循环:

int main(){
    auto start = clock::now(), end = clock::now();
    uint64_t diff = duration_cast<milliseconds>(end - start).count();

    auto accum_start = clock::now();
    while(running){
        start = clock::now();
        diff = duration_cast<milliseconds>(end - start).count();

        if(duration_cast<nanoseconds>(clock::now() - accum_start).count() >= 16666666){
            // do render updates every 60th of a second
            accum_start = clock::now();
        }

        end = clock::now();
    }
}

start并且end都属于我们std::chrono::time_point<clock>之前clock定义为的类型std::chrono::high_resolution_clock

2 之间的差异time_point将是 a std::chrono::duration,可以是纳秒、毫秒或您喜欢的任何其他单位。我们将其转换为毫秒,然后将count()其分配给我们的uint64_t. 如果您愿意,可以使用其他整数类型。

diff是你应该如何计算你的timeDelta. 您应该将其设置为常量。即使你确定它是正确的,你也错了。每一帧都会有不同的增量,即使它是一秒的最小部分。

如果要设置恒定的帧差,请使用SDL_GL_SetSwapInterval设置垂直同步。

编辑

只是为了你,我创建了这个示例 git repo。注意main.cpp我乘以diff得到每帧调整后的差异。这种调整(或缺乏)是你感到紧张的地方。

于 2015-07-16T03:59:37.790 回答