Bolt 102 - Properties and callbacks

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 MonoBehaviour.

Before we go into adding any code inside CubeBehaviour let's look at what exactly Bolt.EntityBehaviour<ICubeState> does. 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 CubeBehaviour script.

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.

Inside the 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 ICubeState.
  • transform - The transform of the gameobject
  • CubeTransform. - Here we access the CubeTransform property 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 CubeBehaviour script 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 networkView.isMine checks.

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 material.color property.

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 CubeBehaviour.

Now when you build and run your game, it will look something like in the picture below.

 To Document Top