Adding an Action Replay to a Game - Unity Game Development Tutorial
In this Unity game development tutorial we're going to look at how we can add an action replay to our game. We'll look at how to add a standard replay, a rewind, a slow motion replay, and how to pause on any part of the replay.
You can either watch the video version below or continue reading for written instructions.
Right, we're going to start with the project we created in our 'Target Selection' tutorial.
In this tutorial, we created a tower of blocks that we can target with the mouse, before clicking the left mouse button to fire the ball.
To add an action replay to our scene, we need to record what has happened in each frame. So the first thing we'll do is create a C# class to hold the information we want to record. To do this we'll click on the plus button on the project panel and select C# script.
We'll call this script ActionReplayRecord. We'll double click to open it in Visual Studio and change it to match the following.
This class doesn't need to derive from MonoBehaviour so we've deleted this, and the Start and Update methods.
For our replay to work we're going to need to record the position of our objects, so we've added a public Vector3 field for this. We also want to record the rotation of our objects, so we've added another field for this.
Now we have a class to hold the information, we need to record this for each object every frame. To do this we'll save the script and switch back to Unity.
We'll select the ball in the Hierarchy, and then we'll click on 'Add Component' in the Inspector and search for the script component.
We'll call this script ActionReplay.
Let’s double click the script to open it in Visual Studio.
To hold all the records for our replay, we'll create a list of our action replay records.
Now we need to add to this list every frame. The Update method might seem like the obvious place for this but the rate that this method is called varies depending on the frame rate.
Instead, we'll use the Fixed Update method which is called on a fixed interval. In here, we'll add a new record to the list and we'll store the current position and rotation of the object.
Now we're recording the history of the object, we need a way to switch to replay mode. To know whether we're in replay mode, we’ll create a boolean field.
Then in the Update method we'll check for the 'R' key being pressed. If it is, we'll toggle the boolean field. So every time the 'R' key is pressed it will switch between normal and replay mode.
We'll then create an 'if else' statement to check whether we are coming in or out of replay mode.
The first thing we need to do when we enter replay mode is to set the position and the rotation of our object back to the first frame we recorded, and when we exit replay mode, we want to set our object back to the last frame.
To help us with this, we'll create a method to set the transform of our object. We'll add an index parameter to our method so we know which recorded frame we want to set.
In here, we’ll get the relevant record from our list, and then we'll set the position and rotation of our object to that of the stored record.
Next we'll go back to our Update method and call this method. If we are entering replay mode, we'll set the transform to the first frame, and if we are exiting replay mode we'll set the transform back to the last frame.
At the moment we're recording every frame, even when we're in replay mode. This isn't what we want, so we'll change our FixedUpdate method to check we aren't in replay mode before adding to our list.
One other thing we need to do is prevent our object responding to physics when we’re in replay mode. To do this we need access to the Rigidbody component of the object.
We’ll create a field to store this.
And we'll get this component in the Start method.
Now, in the Update method, when we enter replay mode, we'll set the IsKinematic property of the Rigidbody to true.
This will stop the object responding to forces and collisions.
When we exit replay mode we’ll set this value back to false.
This script should now look as follows.
Let's save this script and switch back to Unity.
We'll press play to try out what we have so far. If we click on a target, the ball will be fired and knock down the boxes. If we now press the 'R' key to enter replay mode, the ball returns to its original position.
While we're in this mode, we can't move the ball and selecting a target has no effect. If we press 'R' to return to normal mode, the ball goes back to the position it was in before we entered replay mode, and we can move the ball again.
Currently our replay is only affecting the ball. Let's stop the game to apply it to our boxes as well.
To do this, we'll select one of the boxes in the Hierarchy. We can then Click the Select Prefab button to find the prefab for the box.
We'll then click Add Component and add our Action Replay script. By adding the script to the prefab it will add it to all of our boxes.
Let's press play to try this out.
We'll knock over the boxes again. Now if we switch to replay mode it resets the boxes as well, and if we exit replay mode, the boxes go back to where they were.
So now we have everything in place to enter and exit replay mode, the next thing we want to do is actually play the replay.
We'll stop the game and switch back to our script.
What we want to be able to do is step through all our recorded transforms and replay them. To be able to do this, we'll add a new field to store the current index we're showing.
We'll then set this in our SetTransform method.
In our FixedUpdate method we'll add an 'else' statement. In here we'll add 1 to the current index to get the next index. We'll then call our SetTransform method with this new index to update to the next frame.
At the moment, this code will keep adding 1 to the index forever. We need to stop it from going over the number of frames we have stored in our list. To do this, we'll add an 'if' statement to check if the next index is less than the number of records we have. Only if the next index is valid will we call the SetTransform method.
The script should now look as follows.
Let's save the script and switch back to Unity.
We'll press play to try this out. We’ll knock over some boxes again and we’ll press 'R' to enter replay mode. Now we get an action replay of the boxes being knocked over!
This has given us the basic replay functionality. Next we're going to have a look at how we can add rewind, slow motion and pause to our replay.
Let's stop the game and switch back to the script.
We want to be able to control the speed and the direction of the replay, so we'll add a float field for the index change rate.
Then in our update method we'll initially set this to zero.
We'll then check whether the right arrow key is being pressed. If it is, we want the replay to play in the forward direction so we’ll set the change rate to 1.
We'll then check whether the left arrow key is being pressed. If it is, we want the replay to play in reverse so we'll set the change rate to -1.
We'll then check whether the left shift key is being pressed. If it is, we want the replay to play at half speed, so we'll multiply the change rate by 0.5.
Now in our FixedUpdate method, we'll use the change rate to calculate our next index position.
We need to change this variable to a float as we can now change the index by half a frame when replaying in slow motion.
We'll also need to change the parameter in our method to accept a float.
And we'll change our current index field to match.
Then, to get the record from our list, we'll need to cast the index back to an integer. This will round the index down to a whole number.
The final thing we need to do is add another check in the FixedUpdate method. As we can now run in reverse, we need to check that the next index is greater or equal to zero.
This script should now look as follows.
Let's save our script and switch back to Unity.
We'll press play to try it out and we'll fire the ball at the boxes again.
Then we'll press 'R' to enter replay mode. Now, when we hold down the right arrow it will play our replay as normal.
If we press the left arrow, our replay will play in reverse!
If we hold down the shift key while pressing the right arrow the replay will play at half speed.
And if we let go of the right arrow, the replay will pause.
We've now created a functioning replay system, but there's lots more we could do. For a start, we'd want to add some UI elements to show the player they are in replay mode, and allow them to control the replay by clicking buttons rather than using the keys.
We'll look into how to do this and other ways to improve the replay system in a future tutorial, so please subscribe so you don’t miss it.
That covers everything for this tutorial. We hope that you found it useful. Please leave any questions or feedback in the comments below, and don't forget to subscribe to get notified when we publish our next post.