While the Motion Controller can be used with networked multiplayer games, they are tricky beasts and there’s a lot to understand. I am by no means a network or multiplayer expert. In fact, I’ve only worked with UNet and Photon a tiny bit. But, I wanted to put this post together to help how I could.
As a primer, please check out this video I created for UNet and the Motion Controller.
The first thing to realize is that your networking solution is doing all the work. Whether you’re using UNet, Photon, or some other solution, it’s that solution that creates the remote character, wraps up the animator parameters, and triggers events across the network.
The Motion Controller and specifically Reactors can help with this, but the Motion Controller itself doesn’t know anything about a network or remote player.
Please make sure you understand your networking solution and how it transfers data before you try to integrate any character controller.
This part isn’t based on any real experience, but from what I’ve read. So, I’m happy to get some input and evolve this.
When dealing with player characters, we’re dealing with two version:
- Local – This is the character that is running on the machine the player is physically playing on.
- Remote – This is the representation of that local character, but on all the other machines over the network.
When a player controls his character, he’s controlling the ‘local’ version. What another players see across the network is the ‘remote’ version.
The local and remote versions of the same character are not the same. What I mean by that is the local version needs to respond to the player’s input, determine animations, check for collisions, etc. The remote version doesn’t need any of that. It just does what the network solution told it to do.
At its simplest form, the remote version really only needs 3 things:
- Character position
- Character rotation
- Current animation to play
Think of the remote version as a ‘shadow’ of the local version. So, the flow goes like this:
- Local character gets input from the player (Unity Input Source)
- Local character animates (Motion Controller)
- Local character moves (Motion Controller)
- Local character data is sent across network (Networking Solution)
- Remote characters receive data (Networking Solution)
- Remote characters move (Networking Solution)
- Remote characters animate (Networking Solution)
Fast Changing Animator Parameters
One of the first things you’re going to run into with a networking solution is its support for ‘fast changing animator parameters’. For some reason, some solutions just don’t support them. This can cause the remote character to skip animations and become out of sync.
So, what are they?
Your game probably runs at 60 frames-per-second or higher. However, networked games typically send information at a much slower rate… say 5 frames per second.
That means any animator parameter that changes between the network activity can be lost.
In the example below, the animator parameter (AP) was changed to 5 on the 6th frame. It was then changed back to 0 on the 18th frame in order to prevent the animator from looping back into the animation.
Since the networking solution only picked up the animator parameter on the 1st frame and the 20th frame, it never saw the ‘fast changing animator parameter’ and the value of 5 was never sent to the remote character. So, the character never entered the animation.
When using Unity’s “Any State” transitions, we have to reset the animator parameter or Unity will loop the transition endlessly.
I would expect networking solutions to handle this as its a common issue. However, I’ve found a lot don’t. So, what can we do about it?
For UNet, I’ve created a Basic Actor Network Sync component that handles the fast changing animator parameters and sends them to the remote. The remote then unpackages the animator parameters and applies them.
I talk about this in the video and how you can use it.
One of the MC users was kind enough to send me this information from the Photon documentation:
Each value can be synchronized either discretely or continuously. . Discrete synchronization means that a value gets sent 10 times a second (in OnPhotonSerializeView). The receiving clients pass the value on to their local Animator. . Continuous synchronization means that the PhotonAnimatorView records additional values. When OnPhotonSerializeViewis called (10 times per second), the values recorded since the last call are sent together. The receiving client then applies the values in sequence to retain smooth transitions. While this mode is smoother, it also sends more data to achieve this effect.
So, the synchronized parameters would look something like this:
With Photon Bolt I’ve been told that its helpful to use a hidden feature that I’ve added to the Motion Controller. This feature delays the resetting of the animator parameters for a bit.
Warning! If you delay it too long, your animations will loop as I mentioned above.
MotionController lMC = gameObject.GetComponent<MotionController>();
lMC.AnimatorClearType = 1;
lMC.AnimatorClearDelay = 0.2f;
The code above will enable the clearing delay and set the delay to whatever you want.
Combat & Interactions
As we add interactions like combat, we need to start passing information from the remote characters back to the local version. Take melee combat for example…
On my machine, my local character swings at your character (which is a remote version of your character on my machine). If you’re not using some authoritative server, the remote version of your character on my machine needs to tell the local version of your character on your machine that it was damaged.
One way we could do this is with Reactors. You could put a simple Actor Core component on the remote characters and have them handle the “I’ve been hit” message. By handle, they could use the networking solution’s message system to send the message back to the local version of your character on your machine that would respond to the damage message. The damaged animation would play and the remotes would play the animation through normal network flow.
When building a networked multiplayer game, there is a TON of things that you have to think about. Understanding how your network solution works is key.
How you control your characters with the network data really depends on the network solution, but hopefully this information helps.
If you’re a network expert and you have some advice, please share!