Two is better than one! This week for Feature Friday we are continuing were we left off last week in our discussion regarding player input.
Because our players interact directly with our games, it is important that we setup our input correctly for them to have the best experience with it.
Today we’ll dive deeper into things we can do with input such as:
- Mobile Input
- Local Multiplayer
- Creating Your Own Input Controller
If you aren’t already familiar with the basics of input in unity (mouse, keys, buttons, axes) then I’d highly suggest checking out the previous Feature Friday article where we go over just that!
As per usual in Feature Friday articles, I’ll be featuring something made with the Unity Game Engine. This week I am featuring a small game/devlog made by indie developer Thomas Brush.
1. Mobile Input
One of the best parts about Unity is that you can use it to create games for almost any modern device; and the wide availability of smartphones means a huge potential player base for our games.
If you’ve never used touch input, it may seem a bit daunting, but Unity makes it incredibly easy to track touch input, even with multiple fingers.
In general, what we will want to do is check if there is currently any touch input on the device. If there is, then we can access the different touches by index. When we have the touches we want, we can look at properties on them such as state and position.
So how does this exactly work? Similar to getting regular input, we’ll want to check for touches in the Update() loop.
private void Update(){
if(Input.touchCount > 0){
Debug.Log("Player touching screen");
}
}
The Input.touchCount property returns the number of touches on the touchscreen, if the number is greater than zero, then we know that the player is touching the screen.
Next, we will get access to the touch at index 0. Touch indexes are counted incrementally, so the touch at index 0 is the first touch, touch at index 1 is the second touch, and so on. This gets reset when all fingers are removed from the touch screen.
private void Update(){
if(Input.touchCount > 0){
Touch firstTouch = Input.GetTouch(0);
}
}
As you see, touches are returned in a Touch struct that we can use to get more information about the touch. For example if we wanted to get the position of the firstTouch we would do:
Vector2 firstTouchPos = firstTouch.position;
This position value returns the pixel coordinates where the touch is on the screen. The origin, (0, 0) is on the bottom left of the screen.
Related to position, is the deltaPosition property on the Touch struct. The deltaPosition property returns the change in pixels since the last frame and it can be useful when tracking movement on screen for input, swipes, etc.
The last major thing to be aware of when it comes to touch input is the touch phase. Each current touch detected by the device has a phase that will be one of the following options:
- Began – The finger touched the screen this frame
- Moved – The touch position is different from last frame
- Stationary – The finger is still touching the screen, but did not move
- Ended – The finger was removed from the screen this frame
- Cancelled – Tracking for this touch was cancelled by the system
Using these different touch phases, you can add different behavior to your game when players input specific input commands. These phases are similar to the begin, down, etc. functions on regular input but have extra ones for touch specific input such as moved and stationary.
Using these touch inputs, you’ll be able to do 99% of what you need to in your mobile games. It is also possible to look at accelerometer data on the phone to capture movement of the physical device, but that goes a bit outside the scope of this article, so I’ll leave a link to the docs here if you’d like to learn more:
https://docs.unity3d.com/Manual/MobileInput.html
2. Local Multiplayer Input
Local multiplayer, sometimes referred to as “couch co-op” or “split-screen” is when multiple people are playing a game on the same device with their own set of inputs.
You’ll often see this with racing or fighting games where you can play with or against your friends while you are physically in the same room together.
Luckily, we can set up local multiplayer fairly easily with Unity’s built-in input manager. To open it up, just navigate to Edit > Project Settings and in the project settings, click on the Input manager section.
By default, each of the buttons we have defined here, take in input from any controller. We can see where this is configured, at the bottom of each button section with the setting labeled “Joy Num.”
By default, you’ll see that it is set to “Get Motion from all Joysticks.” This means that if we had 4 controllers plugged into our system, input would be recognized when a player presses the specified button on any of those controllers.
By clicking the dropdown, you’ll see that we can define input for joysticks 1-16, meaning that our games can support up to 16 players locally!
You can think of Joystick 1 as “Player 1,” Joystick 2 as “Player 2,” and so on.
So now comes the tedious part – for every button and axis you have defined in the input manager, you need to recreate each button for each player that your game will be supporting.
So if you wanted to give each player the ability to jump, you’d need to setup buttons for Player1Jump and Player2Jump. And if you ever wanted to change key for the jump button, you would need to remember to change it for every button you initially configured.
To obtain the input for the specified button on the specified controller, you would just do:
if(Input.GetButtonDown("Player1Jump"){
Player1.Jump();
}
if(Input.GetButtonDown("Player2Jump"){
Player2.Jump();
}
This part can be a bit annoying to setup and implement, but it is something that is improved in the new Unity input system, which we will discuss in a future Feature Friday article.
3. Creating Your Own Input Controller
Before we wrap up for this week, I’d just like to talk about the importance of wrapping your input class and how you might implement that.
The main reason why you would want to do this is so all your input is in one place in your code. When I first started learning Unity, I would just have input statements littered throughout my codebase.
My player classes would be taking in input, the main menu class would be looking for input, if the player had a vehicle they could get into you better believe I was taking in input in the vehicle class as well.
Now fundamentally, all this code worked fine and did what I needed it to do. But it was not very modular nor extensible.
If I wanted to change how the input works, I would need to do that in several different places and chances are, I might forget to change the input in a few places.
Also this would be quite challenging for me if I wanted to add in support for different devices, maybe to support button and touch input. Again there would be several places I would need to implement this and it would be error prone.
So to get around these limitations, you can put all your calls to Unity’s input system in your own input class, then in the other places in your code, you can reference your own custom input system.
This may seem like just an extra unnecessary step, but hear me out. If you are setting up input to make the player jump when certain input is pressed, your player class only cares that the jump button was pressed – it does NOT care about which key or the type of device or the error checking steps taken to get to that final result.
For my input classes, I typically create them as static classes that do not inherit from MonoBehaviour or anything else. This way I can access my custom input class from anywhere without needing to instantiate it.
Then within my input controller class, I would define some static functions for actions that will happen in my game. So the jump example would look like this:
public static class InputController{
public static bool JumpButtonDown(){
return Input.GetKeyDown(KeyCode.Space);
}
}
Then in my player class I would simply need to call:
private void Update(){
if(InputController.JumpButtonDown()){
Jump();
}
}
Again this may seem like extra work at first, but if you ever wanted to add support for different devices, or add in some error checking to ensure that the player should actually be able to send input commands, you could set that all up in the InputController class and the implementation in the player class would never change.
This is a great habit to get yourself into as it will greatly increase your value as a developer as your code will be much easier to read, maintain, and extend.
Please let me know if you do have any further questions regarding setting up your own input controller as this just scratches the surface on this topic.
Featured Unity Video of the Week
If you’ve been watching lots of Unity game development content on YouTube, then you most likely have came across a developer named Thomas Brush. Thomas has been making games for several years now and has a really nice and artistic 2D style.
Recently, he challenged himself to recreate the game Cyberpunk 2077 in his 2D art style in one week. In this one week period, he created a really cool vertical slice of the game and he shared his whole development process in a devlog on his YouTube channel.
The end result looks really cool and it is certainly inspirational to go and create something awesome. Check out the video here:
And with that that wraps up our two part Feature Friday on Unity’s standard input system. I do plan to do another one (or multiple) of these on the new input system as that seems like it will become the new standard going forward. I still need to play around with that a bit more to familiarize myself and figure out how it actually works.
For now, make sure you stay tuned to the Turbo Makes Games YouTube channel, as I will be going over lots more interesting topics in the coming weeks and exploring new features coming to the Unity game engine.
Anyways I hope you are all staying well, and as always, keep on creating!
-Johnny Thompson
Turbo Makes Games
Recent Comments