Best way to create a replay system?

Blitz3D Forums/Blitz3D Programming/Best way to create a replay system?

OverDozing(Posted 2004) [#1]
Hey,

I was wonderig what would be the best way to create a replay system on a race car game?

Would it be to record keystroke?
or would it be to record car position and rotation?

Let say I would have 5-8 cars on one race...

Any suggestions? better idea?

Thank you in advanced :)


AntonyWells(Posted 2004) [#2]
Never record absolute positions etc.

Record keystrokes, but it then becomes vital that your engine is deterministic. I.e every unique action always creates an equal(or as close as possible) reaction. Otherwise things will go out of sync quicker than paris hilton's vison after 20 shots of vodka.

things like fx etc are best left to choas..there's no need for them for be identical unless it interferes/interacts with the scene in a hugely noticable way.


Koriolis(Posted 2004) [#3]
Are you kidding?
Never record keystrokes you mean!
Doing a fully deterministic engine is just an unneeded pain. For starters you'd be forced to lock the framerate.
DO record the absolute positions, and save the time with each record, so that when replaying you can play it at the right speed. Pretty simple.
As a final touch add some interpolation (between each record) to make it perfect. That's pretty simple.


AntonyWells(Posted 2004) [#4]
Well for a start you want to lock your frame-rate anyway.. I've yet to see a gameplay model that isn't directly influenced by the speed of the game. Without frame-locking it'll either run too fast or too slow...especially a car game.

Secondly, the cost of key changes is MUCH smaller than the footprint of each frame overall.

Here's what a professional ps2 developer has to say on it, from gamesutra, on the downsides of using a absolute method like you suggest as opposed to a keystroke one.


It would require about 200MB to store 18,0000 frames. Even on a PC game, it's better to avoid allocating so much memory and accessing the hard disk so extensively during replay. I hope I have convinced you that the deterministic approach is the proper route to take.




Deterministic Vs. Saving The State

So what are the different approaches we can take to implement a replay system? Imagine a crash of two cars occurring in the street--and that we want to reproduce the scene, making a movie out of it. The first solution is to ask two stuntmen in two new cars to drive the same way, and to turn, accelerate and brake the way original drivers did. If a given number of conditions are met--having almost identical cars, the same traffic conditions alongside the two vehicles, and so on--we can expect that the replay crash will look almost like the original one. The second solution would be to log the important details every few seconds: the position of each car, the position and orientation of all wheels, the state of the body of the car, and the state of any damage--then use this information to reproduce the scene again every few seconds. I suppose you get the point that the second approach is not well-suited for this purpose and would need to store a lot of information about the state of the car at frequent intervals to reproduce the scene accurately.




Koriolis(Posted 2004) [#5]
Well for a start you want to lock your frame-rate anyway..
No I don't. I'd use the delta time method so that people with fast computer don't have to play at 10 fps just because I wan't my game to run on a p2.
Sure you can also use tweening then, so that the framerate is not tied to the game update rate. A lot of people don't use that neither, me included.


I've yet to see a gameplay model that isn't directly influenced by the speed of the game
That's precisely the problem, because then replaying it at a different speed will break everything (I have already said I personnaly wouldn't want to limit the framerate).

Secondly, the cost of key changes is MUCH smaller than the footprint of each frame overall.
Sure. But who cares, that's still very few information to store. one vector per vehicle every frame, I think we can afford that...
So if you put the space requirement aside (I do) it's all about what is more convenient and safe. Don't overcomplicate your life just for the sake of it.

Here's what a professional ps2 developer
A ps2 devlopper is in a confortable situation, its game will always run in the very same environment. Same speed, same all.


AntonyWells(Posted 2004) [#6]
Frame rate locking doesn't cap the frame rate limit, only the update limit. I.e 30 fps will ensure the game logic updates at 30 intervals a second. The amount of renders will be as many as the gpu can handle, be it less (10fps) or more (200fps)...it just ensures the game logic is constant. (Or at least it does when I do it, can't speak for other people's methods)

Perhaps this is delta-timing as you see it, a clash of termnology...;) -Edit, wrote this before you edited.

As for the rest, I stand by it. Copying carbon data is very easy when you're in a simple '1 vector' situration like you say...but i've yet to see a project that was that simple come the end. :)


Koriolis(Posted 2004) [#7]
replay system on a race car game
I don't see how that can be hard to save/restore, but maybe that's just me.

Actually what *I* would do if the recorded data ever happens to be too big, is to indeed record the user actions (with their "date", rather than relying on the frame count), plus the very important part: the actual full information every N seconds to avoid going out of sync. Much like a mpeg movie contains reference frames for the very same reason.
This is the most sensible way IMHO, if size really matters here, which I doubt.


eBusiness(Posted 2004) [#8]
200MB / 180000 frames / 24 B/car = 46 cars/frame. It might not be the lot of us including 46 cars in a game. If you save 20 frames a second (with interpolation it's more than enought), then: 180000 frames / 20 frames/second = 9000 seconds = 2h30. Conclusion, this guy don't know what he's talking about.

A realistic example: 10 mins, 8 cars, 20 frames/second

10 mins * 20 frames/second =12000 frames

12000 frames * 8 cars * 24 B/car = 2.3 MB. Shouldn't be so hard to fit into memory. For saving to harddisk you could just save delta position and delta rotation using a single byte for each piece of info, that'll cut harddisk useage down by a factor 4. Shurely, saving the input does take less space, but saving positions is not unrealistic.


AntonyWells(Posted 2004) [#9]

I don't see how that can be hard to save/restore, but maybe that's just me.



Not enough of the project is known to make that call anyway. Do the cars have weapons? Does the AI?

Is the track interactive? Does it animate?

The more complex it becomes, the more data you have to record with the direct method.

Where as this method, you just record one very small set of input data and that's it. Initilize the ai with the same seeds/varaibles as the actual game and it'll react identically. (Same seeds means even RND calls etc will be the same..so it places no restrictions on the type of code you can use.)

So you have very small memory usage and absolutely no drawbacks, because the more I think about the more I realise you don't need to lock the frame-rate at all. Just create a high definition frame varaible(Comprised of say 255bytes, some internal number system, so no messy 32bit limits)

So you have all the benefits and none of the drawbacks plus the safety of knowing it'll cope with even the most complex siturations...


AntonyWells(Posted 2004) [#10]

12000 frames * 8 cars * 24 B/car = 2.3 MB. Shouldn't be so hard to fit into memory. For saving to harddisk you could just save delta position and delta rotation using a single byte for each piece of info, that'll cut harddisk useage down by a factor 4. Shurely, saving the input does take less space, but saving positions is not unrealistic.


Sure, that's an extremely simple non-realistic sample though. There's a lot more going on than just eight cars moving usually. (Sure you omit as much as you want, but then it becomes a question of quality/size trade-off..nasty situration)

Their car game for example, 3 minutes of direct 'position' saving etc, would take up 200mb. Which is obscene ;)


Koriolis(Posted 2004) [#11]
the more I think about the more I realise you don't need to lock the frame-rate at all.
Right, you don't have to if you store the time with it, just what I suggested if you read it.
But alone it's not even enough, because you'll still have inaccuracies accumulating over time (because some interpolation is needed to take into account the real game update rate.
Again, unless you lock the game update rate.

Or else you have to resync everything on a regular basis, which is what I just suggested.

So you have all the benefits and none of the drawbacks plus the safety of knowing it'll cope with even the most complex siturations...
That's plain wrong. It sure has benefits, but does have drawbacks. And above all the main drawback - keeping everything entirely deterministic - can precisely get tougher as complexity arises. Well anyhow, that's still sensible though, and not really hard to implement neither. I think I've already stated how I would do it. Let's give it a rest, and let HRC_SPIDER decide. Only him knows the real pros and cons in his situation.

[EDIT]What's wrong with a 32 bits long frame counter? Even dropping the sign bit you can count more than 27 years at 60 hz. Should be enough, no?
Also my first post was above all a reply to "Never record absolute positions", like t's hell. It's not[/EDIT]


eBusiness(Posted 2004) [#12]
You might reach 200MB if you save a very detailed damage status once every loop, but maybe it would be possible only to save the damage status when it changes.


AntonyWells(Posted 2004) [#13]
K
There wouldn't be any innaccuracies over time. For that to be true there would have to be functions in the game code that may react in more than one way to the same set of data, whatever that may be. The only thing I've ever known to cause that is rnd calls, which can be controlled instantly by reusing the same seed.

Where else can an inaccuracy occur? You simply 'fake' player input at the same frame he pressed last time. (I.e frame0-A-Key In. Frame25-A-Key-Out.) so as far as the game's engine is concerned, there is ZERO difference, as if a key read was missed in a frame, then it would also be missed in the original frame, as they just borrow the same control states. I.e can't be out of sync as they are the same value constantly across whatever maybe using them.

-
As for the drawbacks, I simply don't see anything that poses any problems code-wise. Perhaps for someone who just dives in head first, then yeah...but if you know what you're planning to do, there's nothing to stop you from doing it.
It's probably one of the easiest things I could think of that I need to code for my next game right now tbh. Maybe you've had a bad experiance with this method, but I havn't...


Rambus(Posted 2004) [#14]
I think its best to record both keystrokes and absolute positions. So that if it does go a little out of synch the absolute value corrects it. (say record absolute position every 2-3 secounds) Keeps the file size down and is very acurite.


Koriolis(Posted 2004) [#15]
There wouldn't be any innaccuracies over time
*sigh*.
There WOULD. If your game update runs at a diffrent speed that what it was when you were recording, you'll be doing multiplication to take that into account. There lie the floating point errors.

So that if it does go a little out of synch the absolute value corrects it
Exactly. In fact it is needed to resync from now and on, as I said, unless your game update is guaranteed to have always the same frequency, which could be really a big limit for some people/projects.


Well enough for me today. Cheers. See you later.


AntonyWells(Posted 2004) [#16]
The only time 'time' comes into it is for timers...which is simply by passed by replacing timers in the key-stroke system as events 'Timer 2 Ticked'...so they always tick on the right frame(Optimise it so a tick is only active if checked.)
Which completely detachs the whole show from the concept of 'time'..it doesn't matter how long it takes to render one frame. There's no need to over-complicate the 'approach'.


Koriolis(Posted 2004) [#17]
With this pipeline then yes, for sure, no discussion. It seems we're simply really not talking about the same main loop framework since the very beginning. As I already said, I'm assuming a non constant update speed

Well, real game over this time, bye.


sswift(Posted 2004) [#18]
I'm going to have to go with Otacon on this.

As much as I hate frame tweening... I never use it myself... using tweening is beneficial to recording demos.

As Otacon said, you can record the keystrokes.

You might say that you can just record the positions of the cars, but think about it... If you do that, then you will need an entirely seperate game pipeline that is dedicated to playing back the demo, and tweening it in case the compouter it's being played back on doesn't have the same framerate.

In addition to recording the car positions though... you need to record all the collisions that occur... so that you can throw up sparks.... And all the explosions that occur, so you can make a car explode when it takes too much damage...

It would be a HUGE pain in the ass, and really mess up your code trying to record all that information. Just in my bullet function alone, I'd have to have like 20 seperate records being kept for each kind of bullet, and the collisions that those cause.

Huge pain in the ass.

With the method Otacon describes, all you need to do is record the keystrokes. And there is no problem with things getting out of sync.

With frame tweening, the physics might be run 10 times a second. That's 10 keystrokes per second, easily recorded.

The graphics are tweened so they can run at 60fps if they want to. That has no effect on this.

But by doing the physics 10 times a second, and only 10 times a second, you ensure that all objects move the same amount of distance on every comouter, and that they collide with the same objects on every computer.

And your main game code handles all the explosions, sparks, cars flipping over, etc, just based on these keypresses.

As all motions always move the same amount every frame on evey PC, there is no way for the calculations to be different from one PC to another, unless you mess up the code and reference the millisecond timer somewhere in your code to time how long something should take... which you should not do with frame tweening.


Mark Judd(Posted 2004) [#19]
My two cents for what its worth.

I've just finished implementing a replay system for my tokamak powered land yacht racing game.
After quite a bit of experimenting i have reliable results from the following :-

I have a fully fixed frame/calculation rate.
During normal game play i record the physics properties of each of the tokamak entities related to the yachts for every main loop iteration.

I moved away from storing input signals since my AI vehicles didn't use the keyboard (if you see what i mean) they have their own routines to determine steering input and sail adjustments.

Properties stored for the ten 'vehicles' are location, velocity, momentum and millisecs() spent waiting by the program to maintain the constant fps.

When switched to replay mode i replace the tokamak advancement command with a recall routine that supplies the stored variables and applies them to the physics entities.

Having the fixed framerate helps me with consistancy across different machine specs and gives stable physics.

I've not had any problems using this method - and seems reasonably efficient given that it runs well enough on my development machine which is a 1Ghz laptop c/w integrated graphics.

cheers

Funky Frank


eBusiness(Posted 2004) [#20]
If you use the position storing method the trick is that you can throw a lot of data away, only store some positions and use interpolation to generate the rest. For things like sparks and alternating damage status you can use an eventlog, only storing data when something special happens.

Anyway, HRC_SPIDER go with what you like, it's probably easiest to store positions etc. But keystrokes will give you the smallest files.


OverDozing(Posted 2004) [#21]
First of all, thank you everyone! It was very rewarding to read all of your posts!

You guys came up with some points I even didn't think about.

I am not totally ready to start developing the replay system but as my game looks, I may go for the position/rotation timing record. After all, I don't really care if the replay file is 10Meg (but maybe the memory does care?? I do not know at this point).

I am using Tokamak, maybe recording torque, velocity as Funky Frank said may be a good solution.

I believe I will have to make a lot of testing with the different techniques possible and choose the one that gives the best results.

Thank you for your help, everyone! :)


Pongo(Posted 2004) [#22]
Here's something I didn't see mentioned.

If you want to alter the replay playback, then recording absolute positions would be the way to go wouldn't it?

For example if you want to be able to rewind or jump to a section during replay, with the absolute method, you simply access that info. With the keystroke method, you would have to process through all the previous info to find the right positions.

Am I right on this?


Mark Judd(Posted 2004) [#23]
I use a pointer to retrieve the info from my replay array and so have fastforward / rewind / slo-mo options, also the ability to jump to the previous / next collision between players.

Funky Frank


BlitzSupport(Posted 2004) [#24]
Bear in mind that with keystrokes, you don't have to record each KeyDown instance met per loop -- just the time a key goes down and the time it goes back up. This also would allow you to turn car wheels, etc, programmatically in the replay, rather than trying to store all that extra information along with car position/rotation.


Koriolis(Posted 2004) [#25]
But by doing the physics 10 times a second, and only 10 times a second
For the last time, that was precisely the constraint I personnaly don't want. I - don't - use - a - fixed - update - speed. Just like you I don't like much frame tweening.
And this leads to at least recording a full game state every N seconds (so *in this situation* you do have to setup a separate pipeline anyway, and recording/replaying keystrokes instead of doing a brute force recording is done due to space constraints only).
You say
As much as I hate frame tweening... I never use it myself... using tweening is beneficial to recording demos.
But if you don't use frame tweening when the user is playing, then using it at replay is not beneficial.
Fact: *I* don't use frame tweening -> no fixed game update speed. And I surely won't use frame tweening just for the sake of making replay easier.
Consequence : my replay speed is different from the one when recording -> it *does* have accumulating errors and a regular resync (between keystroke replays) is needed.

BTW, I've searched for the article Otacon mentioned. I've only read some lines, but enough to see that even though he works on a PS2 where having a fixed update frequency is a lot more natural, he does have a regular resync (with a full game state).
In short he simply does exactly what I said I would do if space was an issue (and this is more an issue on PS2. On a PC it depends a lot on the context, even though the effort to provide is pretty low if planned from the beginning - as stated by Otacon).