Player input is one of those things that seems straightforward at first, but becomes super
complicated the moment you need to do anything advanced like support multiple controllers.
Luckily for us, Unity’s new input system solves a lot of the headaches that’re cause
by using the current input API.
In this video I’m gonna show you how to use a key feature of the new input system,
called input actions, to support multiple controllers in your game with just a few lines
of code.
But before we jump into that, let’s take a quick look at the example project that we’ll
be using throughout the tutorial.
This is the Player script.
It’s job is to consume input and move the player character around the scene.
It does this using basic transform-based logic that can be found in the Update method.
This logic looks simple at first glance because most of the heavy lifting is done by a set
of calculated properties.
These properties do all of the computational work.
They aren’t concerned with anything else.
So where does player input factor in?
Well, input is handled by two directional properties, Vertical and Horizontal.
Their values are pulled directly from the keyboard using the static Keyboard device
class, which is available in Unity’s new input system API.
If you haven’t seen yet, check out my tutorial on migrating to the new input system.
In that video I walk through the creation of this code, so it may be easier to follow
along if you watch that first.
But, in a nutshell, the property getters simply check the W and S keys for vertical movement
and the D and A keys for horizontal movement, and return -1, 0, or +1 based on the key that’s
currently being pressed.
The values that they return are then fed into the rest of the computational logic that you
just saw.
Now, if we switch to Unity and hit play, we can see that the code works just fine.
But the player is limited to a single type of controller: the keyboard.
And not just the keyboard, but only the W, A, S, and D keys.
I wanna be able to support multiple types of input at the same time.
And, in this video, I’m gonna show you how to do that using input actions.
But first, if you’d like to follow along, then head on over to my Patreon page where
you can download the example project free of charge.
I’ve split it up into two folders, before and after, so you can code along as you watch
or just skip to the finished product.
Either way, it’s time to get to work so let’s get started.
The first thing we need to do is introduce some InputAction fields to represent the player’s
axis-based input.
Create a private, serialized InputAction field for each direction: up, down, left, and right.
The InputAction class encapsulates input from one or more sources.
A source can be a controller, a gamepad, or, in our case, a keyboard.
You assign InputAction sources using bindings, which we can set from the editor.
Switch back to Unity and select the Player GameObject.
The Player component should now have a property drawer for each direction field.
Each drawer displays the name of the field along with a plus and minus sign, which are
used to add and remove bindings.
Go ahead and click the plus sign for the up field and select Binding.
Then double-click the Empty Binding that’s automatically generated.
Now this is probably a good time to mention that for this tutorial I'll be using Unity
2018.3.5f1 and the 0.2.0-preview version of the Unity input system package.
And, while I think that a lot of the high level concepts will remain the same, it’s
highly possible that some aspects of this tutorial will change over the course of the
next year or so.
Including some of the UIs that we’re about to use.
But don’t worry.
If you run into any issues, just check the comments to see if I or anyone in the community
has posted a solution.
Or feel free to hop onto our public Discord server.
We’ve got a great community that’s always willing to help
Alright, let’s get back to it.
So, again, double-click the Empty Binding and select the dropdown next to the word “path”.
This is where we’ll bind the actual control to the input action.
Search for and select the W key.
Now the W key is bound to up.
Let’s switch back to the code editor and add some debug statements so we can see it
in action.
Input actions have callbacks for events that are triggered during their life-cycles.
The ones we’re interested in are the performed and cancelled events.
Go ahead and register an anonymous function that logs each of up’s events.
The performed event is fired when the control that’s bound to it’s input action receives
input.
And the cancelled event is fired when that control stops receiving input.
Now, before we can test this functionality out, we need to enable and disable the input
action.
We can do this by implementing the Unity event functions OnEnabled and OnDisabled and making
a call to Enable and Disable respectively.
Alright, let’s switch back to Unity and run the scene.
Now, focusing on the console, press and hold the W key.
Check it out, the performed event has been logged just as expected.
Now let go of the W key.
And there’s the log for the cancelled event.
Beautiful.
While we’re here, let’s add bindings to the rest of our direction fields.
We’ll bind the S key to down, the D key to right, and the A key left.
Awesome.
Now let’s switch back to the code editor so we can flesh out the rest of our implementation.
We need to start taking advantage of our bindings by using the input action events to set the
Vertical and Horizontal properties instead of having them poll the keyboard directly.
But before we can do that we need to convert them to plain old auto-properties.
Let’s go ahead and do that now.
We just need to strip out the logic and expose some setters.
Now we can set Vertical to +1 when up’s performed event is fired and 0 when it’s
cancelled event is fire.
Let’s test it out.
Switch back to Unity.
Press play.
And then press the W key.
Nice.
Now let go.
Beautiful.
Back in the code editor we can go ahead and fill out the rest of the logic.
For input on down set the Vertical property to -1.
For input on right set the Horizontal property to +1.
And for input on left set the Horizontal property to -1.
Last but no least, let’s not forget to enable and disable each of our input actions.
Alright, let’s test it out.
Switch back to Unity, run the scene, and let’s just move around the scene.
Beautiful.
Now, for fun, why don’t we bind some additional keys to our directional input.
How about I, K, J, and L. Bind I to up, K to down, J to left, and L
to right.
Awesome!
Let’s press play one more time and test out the new bindings.
Works like a charm.
But, I will say, setting even two bindings for each direction is already is starting
to feel a little cumbersome.
I can’t imagine what this property drawer is gonna look like with three, four, or even
five control schemes.
Luckily, we can make this much cleaner by adding just one level of sophistication.
Instead of having an input action for each direction, we can use one to encapsulate them
all using a special binding called a composite.
Switch back to the code editor and I’ll show you what I mean.
Add a private, serialized InputAction field called “movement”.
Then register a listener to it’s performed event.
Let’s register an actual method this time.
We can call it “OnMovementPerformed”.
Next, let’s read a Vector2 value from the event’s CallbackContext parameter by calling
ReadValue and passing in Vector2 as the generic parameter.
Now we can use this value to set the Horizontal and Vertical properties.
Wahla.
And what’s great is that we can even reuse this method for the cancelled event, as well.
Great.
Last but not least, lets enable and disable just like we did for the other input actions.
And, of course, we should clean up our class by removing all of the other InputAction fields,
which are now deprecated.
Perfect.
Now we can switch back to Unity and create our binding.
To recreate our previous behavior, we’ll need to add two composite bindings to movement.
We can do this by clicking the plus sign and selecting composite, 2DVector.
Now, there's a small bug in this version of the input system.
You need to run the scene once in order to generate the binding options.
Let’s go ahead and do that.
There they are.
Now we can set them accordingly.
Again, we’ll use the same controls that we used before.
Perfect.
Run the scene.
Move around a little bit.
Beautiful.
It works perfectly and the code looks much better!
Alright, at this point we’re pretty much done covering the basics of input actions.
But I wanna make one small refactoring before we wrap things up, so let’s switch back
to the code editor.
With our new code in place, the Vertical and Horizontal properties have become nothing
more that middle men whose only job is to set the Direction property.
Why don’t we go ahead and cut them out, and set the Direction property directly within
the event callback.
Much better.
As always, we’ll pop back into Unity one more time.
Hit play and test it out.
Beautiful.
Alright, this seems like a good place to stop.
We’ve added multi-controller support with just a few lines of code.
It’s a nice, clean solution to a very common problem, but it isn’t perfect.
The input action approach can become more and more unwieldy as you begin to support
more controllers.
In the next video we’ll explore another feature of the new input system that’ll
help solve this problem.
You won’t wanna miss it.
If you enjoyed this video then please leave a like and a comment letting me know what
you thought.
And for more Unity tutorials just like this one, don’t forget to subscribe with notifications
on.
Thanks for watching and I’ll catch you in the next video.