事件记录是否对时间敏感?

时间:2011-06-06 01:44:22

标签: c++ events playback deterministic

基本问题

是否有任何方法可以在时间敏感(独立于帧速率的)系统中录制回放事件?

任何帮助 - 包括简单的“不抱歉不可能” - 将不胜感激。在过去的几个周末,我花了将近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));

真正的问题是回击这些。使用高性能计数器(QueryPreformanceCounter),我的LoopTimer具有极高的精度。这意味着几乎不可能使用下面的代码来代替// 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,它应该已经完成​​了这个技巧,但仍无济于事。

1 个答案:

答案 0 :(得分:0)

回答我自己的问题,让其他人偶然发现这个问题。

基本上,如果您需要确定性录制和播放,则需要锁定帧速率。如果系统无法处理帧速率,则必须引入速度降低或dsyncronization风险。

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

具有依赖于浮点数的确定性引擎的唯一解决方案是具有稳定且固定的帧速率。帧速率的任何变化 - 长期 - 都会导致播放失去同步。