0

基本问题

有没有办法在时间敏感(与帧速率无关)系统中记录回放?

任何帮助 - 包括简单的“抱歉,这是不可能的” - 将不胜感激。在过去的几个周末里,我花了将近 20 个小时来处理这个问题,这让我自己发疯了。

详细信息

这是目前针对游戏的,但我正在编写的库被设计为更通用,这个概念不仅仅适用于我的 C++ 编码。

我有一些看起来功能相似的代码......(它是用 C++0x 编写的,但我冒昧地让它更紧凑)

void InputThread()
{
    InputAxisReturn AxisState[IA_SIZE];
    while (Continue)
    {
        Threading()->EventWait(InputEvent);
        Threading()->EventReset(InputEvent);

        pInput->GetChangedAxis(AxisState);

        //REF ALPHA

        if (AxisState[IA_GAMEPAD_0_X].Changed)
        {
             X_Axis = AxisState[IA_GAMEPAD_0_X].Value;
        }
    }
}

我有一个看起来像这样的单独线程......

//REF BETA
while (Continue) 
{
    //Is there a message to process? 
    StandardWindowsPeekMessageProcessing();

    //GetElapsedTime() returns a float of time in seconds since its last call
    UpdateAll(LoopTimer.GetElapsedTime());
}

现在我想记录用于回放的输入事件以进行测试和一些有限的回放功能。

只需在我标记//REF ALPHA 的位置插入以下代码,我就可以轻松地以精确的时间记录事件

//REF ALPHA
EventRecordings.pushback(EventRecording(TimeSinceRecordingBegan, AxisState));

真正的问题是回放这些。我的 LoopTimer 使用高性能计数器 (QueryPreformanceCounter) 具有极高的精度。这意味着使用如下代码代替 //REF BETA 几乎不可能达到相同的时差

// REF BETA
NextEvent = EventRecordings.pop_back()
Time TimeSincePlaybackBegan;
while (Continue) 
{
    //Is there a message to process? 
    StandardWindowsPeekMessageProcessing();

    //Did we reach the next event?
    if (TimeSincePlaybackBegan >= NextEvent.TimeSinceRecordingBegan)
    {
        if (NextEvent.AxisState[IA_GAMEPAD_0_X].Changed)
        {
             X_Axis = NextEvent.AxisState[IA_GAMEPAD_0_X].Value;
        }

        NextEvent = EventRecordings.pop_back();
    }

    //GetElapsedTime() returns a float of time in seconds since its last call
    Time elapsed = LoopTimer.GetElapsedTime()
    UpdateAll(elapsed);
    TimeSincePlabackBegan += elapsed;
}

这种方法的问题在于,您几乎永远不会达到完全相同的时间,因此您将有几微秒的时间播放与录音不匹配。

我也尝试过事件捕捉。一种令人困惑的术语,但基本上如果 TimeSincePlaybackBegan > NextEvent.TimeSinceRecordingBegan 然后 TimeSincePlaybackBegan = NextEvent.TimeSinceRecordingBegan 和 ElapsedTime 被改变以适应。

它有一些你可以预料到的有趣的副作用(比如一些减速),但不幸的是它仍然导致播放不同步。

对于更多背景信息- 可能是我的时间捕捉方法不起作用的原因 - 我在 UpdateAll 调用的某个地方使用 BulletPhysics。有点像这样...

void Update(float diff)
{
    static const float m_FixedTimeStep = 0.005f;
    static const uint32 MaxSteps = 200;

    //Updates the fps
    cWorldInternal::Update(diff);

    if (diff > MaxSteps * m_FixedTimeStep)
    {
        Warning("cBulletWorld::Update() diff > MaxTimestep. Determinism will be lost");
    }

    pBulletWorld->stepSimulation(diff, MaxSteps, m_FixedTimeStep);
}

但我也尝试使用 pBulletWorkd->stepSimulation(diff, 0, 0) 根据http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_World应该可以解决问题但仍然无济于事.

4

1 回答 1

0

为其他偶然发现此问题的人回答我自己的问题。

基本上,如果您想要确定性的录制和播放,您需要锁定帧速率。如果系统无法处理帧速率,则必须引入减速或风险不同步。

经过两周的额外研究,我认为这是不可能的,因为浮点数不足以及浮点数不一定是关联的。

拥有依赖浮点数的确定性引擎的唯一解决方案是拥有稳定且固定的帧速率。从长远来看,帧速率的任何变化都会导致播放变得不同步。

于 2011-06-26T18:33:56.723 回答