Beginner micro-tutorial - One key event, many results using UObject to define input states

Suppose you are making a third person action game. While in the game, if you press R, the character should reload their gun. But if you are holding Q which makes a radial menu appear and then you press R, the ammo type should be changed.

How can you make this happen?

This simplest technique is to just make a boolean called something like “bRadialMenu” and if that is true, then you fire off a different event from the branch.

This might work for a quick prototype, but once your game grows this sort of blueprint code will quickly become difficult to manage.

Slightly better is to use an enumerator and a switch on node. This can work if there are only a few options, but it can also get out of hand pretty quickly.

The best option that I’ve found is to wrap what I call the “input state” into a UObject (I’ll just refer to it as an Object from here.)

This gives you a few benefits, but I won’t enumerate them - try it out for yourself and I think you’ll see pretty quickly the benefit of this technique.

What can I do with a UObject?

(create an Object just like any other blueprint)

An Object is just a blueprint class that has very little baggage attached to it. It is not something that lives within the level, it has no transform, it cannot hold any components… What can it do? The Object class can hold data and functions, and it can easily be constructed and then held as a reference by any actor.

You can think of it like a special orb that a character can keep in their satchel, and each orb can hold whatever magical power you want.

Now, if we had a handful of these special objects and each one has a name or some way to identify them, then we might say, “okay, right now, Object A is the equipped object. If I want to do a special object action, then it is Object A’s responsibility to carry that out.”

Let’s me show you example from my project:


In my project, when you press Spacebar, if you are in normal movement model, you will change to “grab mode” in which the mouse appears, and you can click and drag objects around in the scene.
Once you are in grab mode, if you press space again it will change to movement mode again.
But if you are in the main menu, pressing space will do a “confirm” action on whatever widget element has focus. And while in certain situations, pressing space will toggle some UI elements visibility.
I’ll show you the basic setup for that.

A PlayerStates_Component (aka Input state component) gets attached to my PlayerController. This is just an actor component. I am not using a component here because of a need for cross-class reuse. I only use the component for separating responsibilities of my different classes, which makes for more maintainable code in my experience.
I could put everything in the player controller, but if my eyes see too much nodes and functions and variables all at once, I am like a shark chasing a school of fish. Which one do I bite? I freeze!
But it also makes the code easier to reason about, because I don’t have to go hunting and pecking and try to remember where something is. Each class has a single responsibility, which means that in most cases the name tells me where something will reside, so it is much less that I need to remember.

In the PlayerController…

Raw input events are handled on the Player Controller, but the PlayerController directs the input to the PlayerState_Component.

The PlayerState_Component is keeping reference of the Current Player State:

From an array of Player State Objects, one has been selected as the Current Player State. This is who will take in the input and then reroute it to either the UI, or the player character, or maybe perform some special logic all on its own.

Each PlayerState object derives from a parent class I call Parent_PlayerState. The parent class holds an instance editable enumerator used to identify each instance. That way I can loop through all of the states and pick out one based on its ID.

There is also a common function for OnStateEnter and managing what sort of input mode that state will be - will it show mouse cursor and be UI related, or hide the cursor and be in-game related? An instance editable boolean will determine how that gets setup on the OnEnter function.

Notice that the PlayerState object also needs reference to the player controller. In my case, I also grab a reference to the HUD and the player character as well. But notice that these are not specific references to my own custom classes, they are just the generic references unreal gives you.
I can use an interface to communicate with the controller, HUD, and controlled pawn, and this way the player state stays class agnostic. It could be dropped into another project and continue working, so long as the targets implement the correct interface.

So what happens when the current player state is Movement and we press spacebar?

Inside the PlayerState_Movement:
First thing, On Entering the state we ask the HUD to show certain elements that are associated with this state

When that interface call from the player controller reaches here, I am just changing the PlayerState to grab mode:

Here are some other event examples. One toggles an automove mechanic, and another toggles a UI element:

When we switch to a new player state, what happens?

I prefer not to have to remember what UI elements I had toggled on or off, so I make a “sanitize” event which loops through all UI panels and elements and collapses them. Essentially, everything is turned off.

I call the Sanitize function whenever a state is changed:

Then, after setting the new current state, I call the states OnEnter function. The OnEnter function will dictate what UI elements to show, as well the input mode as I showed earlier.

This makes seeing what is happening in a state very easy. Each state only has to say, “these are the things I care about”, and it never has to care about what other states have done. This eliminates the need for me to have to do any mental gymnastics, or decipher any long execution flows with lots of branches and switches. Ahhh, now I code in a relaxing bliss.

And what about once we get into PlayerState_GrabMode?

Again, I just turn on whatever UI elements that state desires:

And when that Spacebar event gets called via interface from the PlayerController, I just swap back to movement mode:

As you can see, even though I have a single key event performing many different actions, it is very easy for me to see what it does in different situations, and it is not require deciphering any spaghetti graphs. Very easy.

What if you want for a key to do nothing in a specific state? Easy, you just don’t implement the interface event. For example, I have a “Locked” player state which becomes active when a match is starting. It does not implement any input events, therefore the player cannot do anything.

How to construct states?

Like this:

Finding a state by its ID:

Well I hope this is useful. I learned how UObjects can be used this way from this fantastic educational channel:
State Management, State Machines, and the State Design Pattern in Unreal Engine 4 Blueprint - YouTube
Introducing the Command Design Pattern in Unreal Engine 4 - YouTube

It has helped me make my games code much more manageable, and also helped me to easily prototype some complex systems in my next projects prototype.

The Object can be used as a way wrap and organize data/behavior for a variety of purposes, not just a state pattern. I’ve also used objects to manage an inventory system, an AI task system, and a building system. It’s a great tool to have in the toolbelt. I hope you’ll be able to put it to good use as well.

If you have any questions about implementation feel free to ask. If you are a complete beginner there is some prereq knowledge you have to understand about inheritance and interfaces before you’ll be able to understand the blueprints I’ve shown, but don’t worry it’s simple stuff, just fancy names is all.

1 Like