{"id":45,"date":"2014-09-15T21:49:13","date_gmt":"2014-09-15T21:49:13","guid":{"rendered":"http:\/\/joelherber.com\/?p=45"},"modified":"2019-12-27T16:05:37","modified_gmt":"2019-12-27T16:05:37","slug":"recording-and-playing-back-gameplay-in-unity","status":"publish","type":"post","link":"https:\/\/joelherber.com\/?p=45","title":{"rendered":"Recording and Playing Back Gameplay In Unity"},"content":{"rendered":"<p>One of the core features\u00a0required for Dora and Friends was the ability to record and playback Unity gameplay.\u00a0As well as being able to playback gameplay, we also had a requirement for users to be able to scrub through the gameplay\u00a0and\u00a0export the gameplay data to a video.<\/p>\n<p>The basic structure for the replay system we developed was as follows:<\/p>\n<p><strong>RecordingManager<br \/>\n<\/strong>The Recording Manager is\u00a0responsible 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\u00a0detected the objects transform data will\u00a0be recorded\u00a0for that frame, otherwise we logged the index of the previous frame the object was updated on.<\/p>\n<p><strong>RecordableObject<br \/>\n<\/strong>The Recordable Object simply contained\u00a0a list a variables that we wanted to record, with a series of helper methods to get and compare the various variables.<br \/>\nHere is a copy of the data we ended up recording for our game:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n    public class RecordableData\r\n    {\r\n        \/\/ ID of sprite displayed (for 2D objects)\r\n        public ushort spriteId;\r\n        \/\/ ID of parent objects, as we're only recording local movements\r\n        public ushort parentId;\r\n        public ushort frameNumber;\r\n        public bool activeSelf;\r\n        \/\/ Should object tween it's position for this frame\r\n        public bool tweenPos;\r\n        \/\/ Local XYZ coordinates\r\n        public PositionData positionData;\r\n        \/\/ Local quaternion data\r\n        public RotationData rotationData;\r\n        \/\/ Local scale\r\n        public ScaleData scaleData;\r\n        \/\/ RGB values for objects that change colour\r\n        public ColourData colourData;\r\n    }\r\n<\/pre>\n<p>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&#8217;t have to deal with angles wrapping from 360 to 0.<\/p>\n<p><strong>PlaybackManager<\/p>\n<p><\/strong>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\u00a0interpolating between frames, as the playback frame rate of the game may not necessarily be the same as the recording framerate.<br \/>\nIn Dora &amp; Friends, I\u00a0ended up using a system that played pretty much exclusively\u00a0interpolated frames, as the chance that the time passed between the frames would ever be identical. This also resulted\u00a0in much smoother playback, and allowed us to record at lower framerates. I did allow objects to turn on and off the tweening where appropriate.<\/p>\n<p>To serialise the replay data we used the excellent <a href=\"https:\/\/code.google.com\/p\/protobuf-net\/\">protobuf-net\u00a0<\/a>library.\u00a0<a href=\"http:\/\/purdyjotut.blogspot.co.uk\/2013\/10\/using-protobuf-in-unity3d.html\">This tutorial<\/a> outlines a great way to export custom structs as a binary file.<\/p>\n<p>Another library worth mentioning is the <a href=\"http:\/\/eccentric-orbits.com\/eoe\/site\/ividcappro-unity-plugin\/\">iVidCapPro library<\/a>, which provides\u00a0a framework for exporting Unity3D gameplay to encoded video on iOS using the<a title=\"GPU image\" href=\"https:\/\/github.com\/BradLarson\/GPUImage\"> GPUImage Library<\/a>. I ended up using a\u00a0version of the library (modified to allow faster than realtime export)\u00a0to save the gameplay videos to the devices.<\/p>\n<p>Similarly, intel have just released this <a href=\"https:\/\/software.intel.com\/en-us\/articles\/intel-inde-media-pack-for-android-tutorials-video-capturing-for-unity3d-applications\">tutorial for the\u00a0INDE Media Pack<\/a>, which could be used to video export on Android. Although I have yet to test out it&#8217;s functionality.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the core features\u00a0required for Dora and Friends was the ability to record and playback Unity gameplay.\u00a0As well as being able to playback gameplay, we also had a requirement for users to be able to scrub through the gameplay\u00a0and\u00a0export the gameplay data to a video. The basic structure for the replay system we developed&#8230; <\/p>\n<p class=\"more\"><a class=\"more-link\" href=\"https:\/\/joelherber.com\/?p=45\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/posts\/45"}],"collection":[{"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/joelherber.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=45"}],"version-history":[{"count":1,"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/posts\/45\/revisions"}],"predecessor-version":[{"id":730,"href":"https:\/\/joelherber.com\/index.php?rest_route=\/wp\/v2\/posts\/45\/revisions\/730"}],"wp:attachment":[{"href":"https:\/\/joelherber.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=45"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/joelherber.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=45"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/joelherber.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=45"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}