A state system for complex movement mechanics


Here's a topic I'm really passionate about, because it lets you create interesting movement in your games while also keeping your codebase somewhat manageable ๐Ÿ˜Š

If you've ever tried to add movement mechanics to your UE4 game beyond of what the CharacterMovement component offers, you most likely tried to add every bit of logic into the Player Controller (or Character) class. If the mechanics are simple and you can do them with some boolean values, then it's not a problem. However, if you add sliding, wallrunning, ledge grabing etc., everything soon develoves into a huge mess with a lot of branches, sequences, and an absolutely massive tick event. The bugs will happen and it will be hard to track them all down (not to mention trying to change anything after not touching this code for a few months).

In such case, it makes perfect sense to use states. You could technically create an enum and keep track of the current state in a single variable (even CharacterMovement uses one to separate the walking, flying, swimming etc. logic). This, however, helps only slightly, because the movement class is still riddled with switches. The tick event and most of the input events will start with a switch on state enum.

Here's a cleaner idea!

(Before you continue reading, beware that this aproach might not be suitable for online multiplayer. It will definitely work with local splitscreen though as there is no replication needed!).

Introducing the strategy pattern

If you are unfamiliar with the strategy design pattern, the idea is to have a base class with multiple virtual functions, and multiple child classes that implement these functions. In our case the virtual class is called MovementMode, and its children will be called MovementMode_Walking, MovementMode_Jumping and so on. The main gimmick here is that only one mode is active at a time, thus creating a state machine where one state is an object and changing the active state is changing the reference to a different object.

Our MovementMode derives from Actor class and contains the standard BeginPlay and Tick events, and additional 4 functions representing 4 buttons that can be pressed by the player (jump, crouch, dash, hook). Additionally, notice the Char variable, which is a reference to the owner FirstPersonCharacter.

Because we can only allow one state to be running at a time, in the base MovementMode's construction script we "push" it to the Character to make it the current mode and destroy the previous mode. This means that a mere act of creating a new mode will automagically apply it as the current input handler.


Now hold up! If the mode was just created, how can it know which Controller is its owner? The Char variable will be null during construction. Here's an additional tip in case you never used it before - the Char variable in MovementMode is set as InstanceEditable and ExposeOnSpawn to make sure it's visible and settable when constructing the actor, before its BeginPlay call:


Set up the reference in the Controller

Add a reference to one MovementMode in the Controller class (or in my case, FirstPersonCharacter). Now the Controller class will serve as a passthrough of inputs to the specific MovementMode of our choosing:

Ideally you would want to have dedicated virtual methods in MovementMode to support press/release, but I was in a hurry durring the jam, hence these ugly booleans. I can access them from MovementModes just fine, because every mode has a reference to their owner Controller (the Char variable).

The movement modes though...

Yes, we haven't implemented them yet, haven't we ๐Ÿ˜… Here's a list of mode classes created for Reklaim to give you an idea of what is a state and what is not:

  • MovementMode_Walking
  • MovementMode_Jumping
  • MovementMode_Sliding (a fast crouch without an ability to change direction)
  • MovementMode_Crouching
  • MovementMode_HookingIn (hooking toward green hooks and keeping to be attached until the hook button is released)
  • MovementMode_HookingSwing (swinging around yellow hooks)
  • MovementMode_None (an input disabler for battles and cutscenes)

My favourite part about the modes is that you can handle complex movement chains easily. For example, at the very start of the Walking mode (spawned when the player touches the ground), we immediately check if we want to change to a different state - meaning that we can implement bunnyhopping and jump-to-slide with a single IsButtonPressed check:

(Note: I straightened the nodes and added the comments for this tutorial, don't bother too much with them during the jam unless REALLY necessary, every second counts!)

Changing the state is as simple as spawning a new MovementMode. We can also determine specific conditions for different states (ie. skip slide and go straight to crouch if moving slower than 200 units per second):


Additionally, if you need to change some CharacterMovement variables for the duration of the state, you can simply remember its old value on state's BeginPlay and set it back before pushing a different state.

You need to do a trace for detecting walls to perform a wall run? Go right ahead, implement them in the Jumping state. It's declutering the Controller because traces are known to be spaghetti inducers, and as a bonus it's also a free optimization because the tracing can never happen outside of the state that actually needs it.

Because the states manage themselves, sometimes the state can change more than once during a frame - every time you bunnyhop in Reklaim, on the frame of the next jump old Jumping mode is replaced with Walking mode, and then immediately a new Jumping mode is spawned. It's wasteful, yes, but it's a jam game and the performance is not visibly crippled so it's fine ๐Ÿ˜ค Outside of jams though, you'd want to do better. So here's what can be done better than my current Reklaim implementation.

What can be improved

First of all, don't use Actor as the base class. It's a pretty heavy class with its own transform that is completely unnecessary (and could potentially lead to issues when disabling tick for actors that are too far from the controlled Character). I only used Actor because I didn't want to deal with particular functions like Line Trace not being available in raw UObjects or ActorComponents without a valid WorldContextObject. My lazyness can be explained though - remember, it's a jam, so we have to be quick! Plus I didn't want to deal with potential reparenting in Blueprints - it's pretty much a death sentence when you are in a hurry.

(If you are confused what the heck was I talking about in the last paragraph, stick to the Actor class!)

Secondly, don't actually spawn and despawn every time. Keep all modes in memory and prepare a Reset function that will be called when the particular movement mode gets pushed as the current mode. This Reset function should set initial values of variables used by a state and replace BeginPlay from current implementation.

And last but not least - implement the system in C++. It will be a lot easier to not use Actor as a base and deal with WorldContextObjects from there than it would be in Blueprints.


Thanks for tuning in! ๐Ÿ˜ Next Sunday: Textureless shaders in UE4's Material Editor

Get Reklaim

Leave a comment

Log in with itch.io to leave a comment.