Best approach to replay system

Hi all,
I have been thinking about making a “replay system” for my racing game for long time before actually coding it, now that I have coded it the way I thought its not working right as I was fearing. The thing is Im storing keypresses according to time but actually time being measured with float is not a continuos and discrete value, well I mean that maybe due to system performance a certain specific time mark is skipped then it causes the replay system to not be perfect, if I add another check based on positions the system shows some gaps between point A and B although its more accurate at least on the positions of course but not aestheticaly good, then I wonder if maybe there is a better well known way to code this because somehow I cant think of other way, I know this have been done several times in racing games so Im sure there is a better approach to achieve an accurate and smooth result. Thanks a lot beforehand

PD Im using c# although I think its independent to the solution

I would just make a giant array of Vector3 for the position of the car, and Quaternion for the rotation of the car, and you could even do that for the cameras too.

If a V3 takes 16 bytes (it probably takes 12, but alignment might move it to 16 bytes), five minutes of 60fps gameplay would only take 288k of space, and the same amount for the rotations. For under 1mb of storage you could probably fit over 1000 seconds of gameplay for one object. If each sample is 16+16 bytes, then 1000000 bytes of storage would get you 1041 seconds at 60fps.

When you want to play it back, just “drive” those positions and rotations into your car and do whatever you want with the camera. It will be perfect every time. Obviously you would turn off the physics components because you are driving it with these precalculated physics results from the previous run.

2 Likes

Thanks a lot Kurt-Dekker =), I never thought it could be so small ammount of memory used doing it the way you mentioned storing all the positions and rotations.

So I assume the method you describe is record each frame with a time mark associated and then playback based on time of course (as we cant assure each frame is rendered one after another), well I would also add a speed value (float) so that I can rotate the wheels the right way and a drift flag to know if I have to activate the visual effect, I think it will work the same way.

Thanks a lot about this, I will do it and let you know if it worked, the way you said it will even work with cameras too

1 Like

Ha! You’re ahead of me there! Good point… First pass I would just blast it back the same way, one datapoint per update. That is probably good enough for a replay function on the same computer.

But if you wanted to simulate a “ghost racer” next to you while you are re-running the race, yeah, you’d wanna make sure the time was right. Easiest way would be to not advance the stored counter until the time is equal (or close) or greater. Better way would be to interpret between two datapoints using the current time.

I’d probably make a class that stored everything I wanted about each point in time, and as you think of other things you want to store, you can keep expanding that: camera angle, position of the helicopter flying around the track above you (think Ridge Racer), etc.

2 Likes

Thanks again for the explanation and ideas, yes you are right, for the recording procedure blasting a datapoint per update should be ok I think and for the playback well as you guessed I want to add a “ghost racer” too, at least have that option, player could either run against it or just watch the “ghost racer” drive through the track, so in both cases to keep an accurate time count is a key feature.

And speaking of how to handle that playing back, well currently (lets remember its not working smoothly) Im checking the way you said, mainly if time is equal or greater than the stored timepoint then get the data and advance the index. I havent considered interpolation between points with my previous approach as each point was very distant one from another, I think with the approach you suggested its probably not needed considering there is a timemark like every 0.016 seconds (if it goes at 60fps) or so, then I think it should be enough… well if it is still going wrong I will consider calculating values between two datapoints.

Also you are right, thats the way I was doing it, I have a class that stores everything I need (position rotation keys etc) and then its written into a file, so I will do as you suggested and expand it with your approach, also its a cool idea to have helicopter flying over the track like Ridge Racer, in fact I really like Ridge Racer games (except the lastest ones…) and it has been a point of inspiration for many aspects in the game (although I know that working alone I cant achieve a game like that).

I’m with you… they used to be remarkable in their incredible sense of speed and fine tuned race dynamics.

1 Like

True indeed, Ridge Racer games made a very special driving style that was so easy to pick up and enjoy yet very hard to master, as an overal these are my most favorited racing games. By the way I know my game is not going to be close to any of these games (not even the first one) but hey if you ever feel curious visit my site there I have currently a video and will update game status soon, as soon as I have enough features to make the gameplay video look cool enough (mainly make music and few other details), I dont know if I can post links to sites here, well its basically my nickname with “.com” at the end, dont hesitate to drop a line on youtube, Im always eager to hear what people think even if its yet so few thats shown.

And on an additional note, I was changing the approach of the replay system to the one you described when I noticed something was wrong (I was not saving values on the starting line when there is the countdown), that was causing delays of course. decided to change that and retry and the replay became more accurate (still a bit shaky) but having a deeper look into it I decided to apply some of the additional stored data to the “ghost car” (I was using only half the data: position rotation, keys), and surprisingly after applying more of the stored data (I havent applied all the data yet) the “ghost car” becomes a lot more accurate and not shaky, I can still see a few turns where it seems like it eats a few degrees here and there (abrupt turns I mean) but racing against it the “ghost car” looks a lot like a human car (yeah really you understand what I mean), Im considering having a few tweaks on it maybe applying more data and maybe leaving it as is, Im storing a lot of data each time to be honest but its not stored on every frame so the file is around 800kb for a minute and a half race and probably could be smaller if I stop storing some unused values, not bad, what do you think? Im hoping people can make their ghost replays and send them to friends, see who beats that new track time etc

Edit: The files are under 100kb dont know what I saw before
Edit2: The fact is replay looks overal right now but strangely ghost car can make slight variation from one run to another, it differs around 0.1 second makes me wonder if people will be fine with it

Unfortunatelly I have a bad update on this, meaning I still have an issue with replays, because it was still having around 0.1 seconds of difference I tried recording all frames as you suggested initially, the result is a lot smoother so you are right, thats the best solution aparently, but surprisingly its still showing same time difference, I think the issue is that the same time mark is not always being shown in the update, I mean maybe the arrival (crossing goal) was on 1:20.455 but the fraction thats shown in the update is 1:20.445 and then 1:20.460 meaning that the winning frame is shown with a slight delay making the track time a little different with each new run, Im open to more suggestions

Edit: The file size is 1.37Mb for a 2 minute race so its fine as you guessed and it can be smaller if I stop recording some data which I will be sure to do when its working finally

Edit2: Right now I can only think to fake the time the “ghost car” arrives, the overal replay looks fine and smooth so nobody will notice a slight delay in arrival if I tell them the time is the one made when it was recorded, I know its not the perfect solution, Im still open to new suggestions

1 Like

I’m going to be writing one of these myself, mostly for the purpose of a FPS “kill cam”. I have enjoyed reading this thread!.. I am going to take the same approach (thanks guys) and store it in RAM for now. Then assign a key and hopefully be able to play back the last 10 seconds of gameplay. I will let you know how I get on :slight_smile: If that works I will consider being able to write them to disk etc, it would be cool to share replays across the net with other users, just like quake used to do with its demo files :slight_smile: Now im excited!!

1 Like

An example here. Not that hard to implement.

(DEMO)

GitHub - ElmarTalibzade/GhostRecorder: A basic replay system for Unity Engine (Asset)

Note that it’s called GhostRecorder but it’s Not a ghost system.

1 Like

Awesome, yeh I think I need a custom one since I have a complex player, and lots of AIs with guns, grenades etc… but same principle… Plus I sort of want to write it for fun, I may regret that :slight_smile: