Основной вопрос
Есть ли способ записи событий при воспроизведении в чувствительной ко времени (независимой от частоты кадров) системе?
Любая помощь, включая простое «Нет, извините, что это невозможно», будет принята с благодарностью. За последние несколько выходных я потратил на это почти 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 были изменены для соответствия.
У него были некоторые интересные побочные эффекты, которые можно было бы ожидать (например, некоторое замедление), но, к сожалению, это все равно приводило к десинхронизации воспроизведения.
Для получения дополнительной информации - и, возможно, причина, по которой мой подход к привязке времени не сработал - я использую BulletPhysics где-то в этом вызове UpdateAll. Вроде как это ...
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 должен был сделать свое дело, но все равно безрезультатно.