Replicated Door Open in Unreal Engine

[ ue4  ]
Written on December 16, 2021

It’s fairly easy to set up a door that opens in Unreal Engine, but having it replicate to all clients in a multiplayer game gets a little trickier. I’d like to show my take on this and explain the issues I’ve encountered.

I’ve set up a stand-alone project demonstrating opening doors, based on the third person template in Unreal Engine (version 4.27) - the project is available on GitHub.

Replicated Door Open

When testing the multiplayer aspect of an Unreal project, you need to be sure to set the Play settings properly:

Play Settings

This allows you play with two (or more) game clients on your own machine - I generally play in the selected viewport - when more clients are requested, each gets their own window and you can Alt-Tab between them. This setup behaves close enough to the real thing for most things, and still allows blueprint debugging with no additional fuss.

Basic Door

First, I want to show a bare bones opening door, that still replicates to all clients.

Basic Door Basic Door

This is a Blueprint Actor, with two mesh components, one for the frame and one for the door that opens inside the frame. I’ve added some very basic geometry that I modeled in Blender to the project for demonstration purposes.

To allow players to interact with the door I’ve created an interface called Openable with two functions, Open and Close, and assigned this interface to the BP_BasicDoor class. Opening and closing the door is then simply a matter of changing the rotation on the Door Static Mesh component. The component is set to replicate, so any movement of the component is replicated to all clients.

Basic Open and Close Basic Open and Close

Input Actions

In my test project, I’ve added two input actions, Open and Close, and bound them to E and R keys, respectively.

Input Actions Input Actions

It is important to remember that these actions must be performed on the server - telling the door to open on the client won’t replicate to the other clients so handling the input action must do an RPC over to the server, which in turn will open the door.

Open Door on Server Open Door on Server

This simply opens any door within range - here it is a one-meter radius so that should only find the door right in front of you. The nice thing about using an interface here is that I don’t have to do any casting to tell the door to open.

Animating

This basic door works in a multiplayer game, but it simply pops open rather than animating properly. I can fix that using a timeline in the Blueprint. First, I need to track the state of the door with an enum rather the boolean variable - it can now be in one of four states:

  • Open
  • Opening
  • Closing
  • Closed

If the door is opening and gets a Close event, it should reverse direction rather than playing from the closed state, and if it is closing and gets an open event, it should also reverse.

This leads to a rather messy Blueprint for handling Open and Close events:

Animated Open and Close Animated Open and Close

The timeline has one very simple curve:

Door Movement Curve

I set up the timeline to be of length 1.0, and animate from 0.0 to 1.0 - the rotation of the door is set in the Update Door State function that scales this value up to the actual rotation value. If you want the door to open faster or slower, you can set the play rate on the timeline.

Update Door State

This approach seems to work fine at first glance - the door rotates as it opens and closes and this movement is replicated to the other clients. The problem is that the animation only happens on the server and it replicates the transform of the component, and when the network connection is less than ideal you start seeing choppy movement of the door as there is no prediction going on as you get with character movement.

Network Emulation

When testing network play locally on your machine it’s easy to overlook such performance issues, but you can have Unreal Engine emulate bad network connections, so you are more likely to catch such issues while testing locally. Under the Play menu, select Advanced Settings and enable Network Emulation, setting Network Emulation Profile to Bad.

Network Emulation

With these settings, I start seeing choppy and uneven movement of the door.

Animating Client-side

A better approach is to only replicate the state change and have the clients move the door. All clients will move the door at the same rate, so even if they may be slightly out of sync they will eventually reach the same state, and this also reduces the load on the replication as the door will not have to be replicated every frame.

First, I remove the replication flag from the Door Static Mesh component, but enable replication on the State variable with a RepNotify setting:

State Variable

This adds a new function, OnRep_State to the class, that gets called whenever a client gets a new value for the State variable.

OnRep_State

That function simply forwards the call to an event:

Animate Door

This has to be implemented in an event so that the timeline is available. The timeline is a separate timeline from the one used on the server to open and close the door, but must be set up with an identical curve. It is best to use an external curve, and have both timelines reference that curve to ensure they are always identical. This allows for easier tweaking of the curve, to add ease-in/ease-out movement, for example.

Now the door animates smoothly on all clients, even with a bad network connection, as I’m only responding to the changes of the State variable. Any movement of the door, frame to frame, happens on the client, and I’m not relying on replication of the component transform.

Get the Code!

The code is available on GitHub:

https://github.com/snorristurluson/ReplicatedDoorOpen