One of the core features required for Dora and Friends was the ability to record and playback Unity gameplay. As well as being able to playback gameplay, we also had a requirement for users to be able to scrub through the gameplay and export the gameplay data to a video.
The basic structure for the replay system we developed was as follows:
RecordingManager
The Recording Manager is responsible for polling any objects that we may want to record, and checking if they have made any changes since the last frame. If a change is detected the objects transform data will be recorded for that frame, otherwise we logged the index of the previous frame the object was updated on.
RecordableObject
The Recordable Object simply contained a list a variables that we wanted to record, with a series of helper methods to get and compare the various variables.
Here is a copy of the data we ended up recording for our game:
public class RecordableData { // ID of sprite displayed (for 2D objects) public ushort spriteId; // ID of parent objects, as we're only recording local movements public ushort parentId; public ushort frameNumber; public bool activeSelf; // Should object tween it's position for this frame public bool tweenPos; // Local XYZ coordinates public PositionData positionData; // Local quaternion data public RotationData rotationData; // Local scale public ScaleData scaleData; // RGB values for objects that change colour public ColourData colourData; }
It may be worth noting that it is much better and easier to record Quaternion rotations rather than Euler angles as they are more deterministic, and you won’t have to deal with angles wrapping from 360 to 0.
PlaybackManager
The playback is responsible for working out which frame the game should display during playback, and which objects it should move. The playback manager should be able to handle skipping frames and interpolating between frames, as the playback frame rate of the game may not necessarily be the same as the recording framerate.
In Dora & Friends, I ended up using a system that played pretty much exclusively interpolated frames, as the chance that the time passed between the frames would ever be identical. This also resulted in much smoother playback, and allowed us to record at lower framerates. I did allow objects to turn on and off the tweening where appropriate.
To serialise the replay data we used the excellent protobuf-net library. This tutorial outlines a great way to export custom structs as a binary file.
Another library worth mentioning is the iVidCapPro library, which provides a framework for exporting Unity3D gameplay to encoded video on iOS using the GPUImage Library. I ended up using a version of the library (modified to allow faster than realtime export) to save the gameplay videos to the devices.
Similarly, intel have just released this tutorial for the INDE Media Pack, which could be used to video export on Android. Although I have yet to test out it’s functionality.