GDNet+ - Reputation: 1771
Posted 14 March 2007 - 05:25 AM
1) If you have a deterministic game, all you need to store and replay are inputs (user inputs, frame timesteps, random number seeds, ...).
2) Serialisation / Deserialisation of the game state. Have your objects record and replay their states. In fact, you don;t record the states, but the state changes (many objects won't change).
#1 Is very lightweight, IF IT WORKS! The trick is to have a fully deterministic game, and that in itself can be a problem. Second, if there is a discrepancy, it is very hard to track down what made the game and it's recorded part deviate. And once they deviate by the slightest bit, that's it, game over. Anything as trivial as doing one collision check out of order is enough to send the replay sideways. Detecting deviation for debugging requires you to build hash values of object states (whatever that is, like a ray-traces, messages, ...)
Also, you cannot rewind, step into the game, without having to rollback the simulation to the very start, and replay up to the point of interest. Also, you need to decouple the update, and the rendering, if you do not have a fixed frame timestep, and you want stuff like slow motion.
#2 Requires more code. You need to implement serialisation methods to your objects. Then being able to record changes in game states (if you want to have a small replay buffer). It's not dissimilar in many respects to the Quake3 Networking Model. Instead of sending the game state to a client, you just write it to a buffer, and for replaying, grab the game states from the buffer, do interpolation, effects...
Members - Reputation: 128
Posted 14 March 2007 - 01:59 PM
Once you have a deterministic game then it's simply a matter of logging the user's inputs and replaying them back during the correct game update. It was surprisingly easy to implement but as was mentioned, the hard part is in making sure that your game is completely deterministic.
I decided to make mine deterministic because it's easier to debug and you don't have any crazy thing that can rarely happen for no reason at all.
Members - Reputation: 1294
Posted 14 March 2007 - 02:08 PM
It is very, very light on memory though - typically you only have to record a handful of inputs every frame, so you can have quite long recordings without taking up much memory at all.
GDNet+ - Reputation: 1771
Posted 14 March 2007 - 11:21 PM
As said, 1) is very fragile. When your game code changes (anything from A.I., to collision, tiny optimisations even), the inputs will most likely no longer be valid. This is not quite so true for 2), although a change in the data format will invalidate the replay as well.
Both require a lot of work tbh. 1) is to make sure it's 100% deterministic, write debug tools to check on that (record/test hash values made of game data) and everytime you tweak the code, you have to keep it mind if the determinism will stick, 2) is writing all the serialisation and delta-compression methods, which is no small task.
Lots of things can get in the way of determinism, especially if you have a multithreaded system, then I'd be very careful. Obviously the threads will have to be sequenced properly, and that may or may not be part of your engine.
If you are pretty confident that your game can be fully deterministic, 1) is definitely the easiest. It's painstaking work (debugging notably), but it's still way more lightweight than 2) which will be a monster.
Members - Reputation: 544
Posted 15 March 2007 - 12:22 AM
Instant Replay : Building a Game Engine with Reproducible Behavior
Developing Your Own Replay System
(sign-up is free)
Posted 15 March 2007 - 05:58 AM
I had an array (note the int is actually Fixed point) in the Player class,
int m_iReplayPos[NumberOfFrames]; where NumberOfFrames = the number of frames to save, and pos0 = X, and pos1 = Z;
In addition, I stored their animation data like this
byte m_ReplayAnims[NumberOfFrames]; where NumberOfFrames = the number of frames to save, and pos0 = Direction they're facing (North, south, etc), and pos1 = their animation.
For each frame that was rendered (remember this is a cell phone game so fps = 10->15) i stored the position of each player and their animation + direction (I had a function that when it rendered them, used the animation and direction to display the correct frame).
I did the same thing for the ball and camera, and just iterate through this array when replaying, disabling ALL AI and anything else that would divert from this set course. As i said, it had to be simple for a cell phone game, (which was already pretty simple), but it integrated nicely into our game. In about 2 hours, I had the replay working no problems using about 10k for 15 seconds or so of replay.
Hope this helps!