Hi! I’m developing a drive simulator for my degree thesis which is synchronized with an eyetracker.
I have to record the “gameplay” to replay it after (like a demo) and sync with the eyetracker output.
I’m using “FixedUpdate” for the motion of my model and here i take the input of the controls, if it have changed, i save it in a db.
My question is if FixedUpdate can start and be “cutted” by the next “FixedUpdate”, because when i play in the simulator, it behaves in one way and when it replays it is different
I’m using timestamps and the variation is minimal, that’s not the problem
Can you advice me about a better way to save the gameplay?
Are you accounting for the fact that fixed update can be run multiple times per frame?
It sounds like you’re putting input in based on real time and not simulation time. You might get better results if you count the number of fixed updates and use that as a “timestamp” instead.
I think the method is a common way to repeat gameplay: set all starting values to the same at the start, then input the same data. Seems logically sound either way.
Because this was such an interesting question, I’ll post my solution too.
The problem of tracking eye motion or gameplay is the same as of recording music or any analog signal. You’ll need to set a sampling rate, the key being that you have a set amount of samples per second. You can then interpolate between the samples to reproduce the movement. Using frames as the measuring stick may cause problems because the frame rates could be different during subsequent runs.
I would first attempt at storing values would be something like this:
public class SampleTaker : MonoBehaviour{
List<Sample> samples; //needs initialization
public static int frequency = 44000f;
float sampleRate = 1/frequency;
public void StartTakingSamples(){
//Start the coroutine or use Invoke
}
public void EndTakingSamples(){
//End the coroutine/invoke
}
IEnumerator TakeSample(){
//record position of car and eye
//store in samples list
yield return new WaitForSeconds(sampleRate);
}
}
public struct Sample{
public readonly Transform carPosition;
public readonly Vector2 eyePosition;
private Sample(Transform newCarPosition, Vector2 newEyePosition){
/*set values*/
}
public static Sample CreateSample(Transform carPosition, Vector2 eyePosition){
return new Sample(carPosition, eyePosition);
}
}
And to play them back I would just Lerp the transform/Vector2. Because we know the sample rate, playback can be done to accurately replay the motions.
Notice that Sample is actually a struct. They’re faster to create than full-blown classes, but depending on your sample rate, may cause a stack overflow. If this happens, you will have to make them a reference type as well.