In 'Bolt 101' we learned the basics of getting Bolt running and how to instantiate prefabs over the network. In this part we will look at how we go about replicating (serializing) properties over the network.
When we created our 'Cube' prefab, and the state 'CubeState' for it, we added a property called 'CubeTransform'. Now it's time to use the property and introduce ourselves to coding Bolt entities.
Start by creating a script called 'CubeBehaviour' in the 'Tutorial/Scripts' folder and open it up in your text editor of choice. Remove the default unity methods and have the class inherit from
Bolt.EntityBehaviour<ICubeState> instead of the normal
Before we go into adding any code inside
CubeBehaviour let's look at what exactly
ICubeState is a C# interface created by Bolt automatically when you run Assets/Bolt Engine/Compile Assembly that exposes all of the properties you have defined on the state. This gives you easy and statically typed access to all properties of your states.
The class we inherit from, which is defined as
Bolt.EntityBehaviour<T> in the Bolt source code, takes the type of the state we want to use as it's generic parameter, this just tells Bolt the type of the state we want to access inside our
As with the
Bolt.GlobalEventListener class from 'Bolt 101' the
Bolt.EntityBehaviour<T> class inherits from
MonoBehaviour and you can use all normal Unity methods in here also.
We are going to implement a specific Bolt method called
Attached, this can be thought of as the equivalent of the
Start method which exists in Unity, but it's called after the game object has been setup inside Bolt and exists on the network.
Important: Like the
SceneLoadLocalDone method from 'Bolt 101' we use the
public override ... version of implementing methods and not the way Unity does it.
Attached method we are going to add a single line of code:
state.SetTransforms(state.CubeTransform, transform);, lets break it down:
state.- This part accesses the state of the entity, which is
transform- The transform of the gameobject
CubeTransform.- Here we access the
CubeTransformproperty we defined in the state in the 'Bolt Assets' and 'Bolt Editor' windows.
SetTransforms- Here we tell Bolt to use the transform of the current game object the
CubeBehaviourscript is attached to and to replicate it over the network.
The complete sample should now look like this.
We're going to add some very simple movement code to our
CubeBehaviour, we could use just the normal Unity
void Update() ... way of doing things, but Bolt provides another method we can use called
SimulateOwner. We implement
SimulateOwner in the same way we did with
Attached and add the movement code inside of it.
The code inside
SimulateOwner is pretty much standard Unity stuff, very simple. The only thing which is Bolt specific is the
BoltNetwork.frameDeltaTime property. Currently this simply wraps the built-in Unity
Time.fixedDeltaTime property, but it's still recommended to use the Bolt version for future compatibility.
Before we continue, let's take a step back and look at what
SimulateOwner actually is. The computer which called
BoltNetwork.Instantiate will always be considered the "Owner" and this is where
SimulateOwner will be called, and only called on that computer. This means we can write specific code for movement or other things that only should run on the computer that instantiated a prefab, without the need for any
The last thing we need to do before starting our game is to just attach our
CubeBehaviour script to our 'Cube' prefab.
If you build your game now and start up two instances, one server and one client (or more), you will be able to move the Cube around and it will properly replicate over the network.
You might notice that the remote cube stutters a bit, it's not interpolating smoothly and instead "snapping" to it's new position. Bolt has built-in features for handling this, so let's enable them!
The first thing we should do is to enable 'Interpolation' for our 'CubeTransform' property on our 'CubeState'. Open the Bolt Assets window from Window/Bolt Engine/Assets if it's not already open and click on the 'CubeState' to begin editing it.
Find the 'Smoothing Algorithm' field under the settings for our 'CubeTransform' property, switch it from 'None' to 'Interpolation'. Now compile Bolt again to make it aware of the changes, either by clicking on the green arrow in the 'Bolt Assets' window or running the Assets/Bolt Engine/Compile Assembly command.
You can now build and start the game again, and you will see that the cube now interpolates smoothly for the other player. Bolt has further advanced features to remove what's usually reffered to as 'micro stutter', for now we will skip these as they are not required when just starting out and is usually the final touches you add at the end of your game.
Important: If the cube is still stuttering for you make sure you ran the Compile Assembly command.
Currently in our game it's a bit difficult to see which cube you are controlling, as they both look exactly the same with no way to distinct them from each other. Let's fix this with some colors!
Open up the 'CubeState' in the 'Bolt Editor' and click 'New Property', name the property 'CubeColor' and set the type of it to 'Color'.
After this, make sure to run the Compile Assembly command again. In the
CubeBehaviour class and inside our
Attached method we are now going to add a couple of lines of code which randomizes a color for each cube.
The new code is the if-statement and the line of code within it. The reason we check for
entity.isOwner is that we only want to do this on the person that instantiated the object, not everyone.
Some of you I'm sure are asking: So why not use
SimulateOwner then? That would let us write code that runs only on the owner, correct. But that also executes every frame, which we don't need. There is no special
AttachedOwner callback because most of the code in attached will be the exact same for everyone.
So far so good, we are setting the color on the owner only but we're not doing anything with it currently. Now we get the chance to look at another feature: Property Callbacks.
Property callbacks simply let you hook up a method to be invoked whenever a property changes value. First let's create a new method called
ColorChanged which takes our color from the
state.CubeColor and assigns it to the Renderer's
Simple enough. At the end of our
Attached method we are going to hook up our
ColorChanged method so that it's called whenever the
state.CubeColor property changes.
The last line in
Attached that reads
state.AddCallback("CubeColor", ColorChanged); is the key, currently you have to type out the property name, in this case
"CubeColor" in a string (we are working on making this statically typed also).
We're going to add one last thing before we run the game again, inside our
CubeBehaviour add a Unity
OnGUI method which looks like this.
And here is the entire source code for
Now when you build and run your game, it will look something like in the picture below.