基本的な質問
時間に敏感な (フレームレートに依存しない) システム内で再生をイベント記録する方法はありますか?
簡単な「申し訳ありませんが不可能です」など、どんな助けでも大歓迎です。私は過去数週末にわたってこれに取り組んでほぼ 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);
}
しかし、 http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_Worldによれば、 pBulletWorkd->stepSimulation(diff, 0, 0) も試してみました.