Legacy Tutorial – Please note: This tutorial was last tested in Unity 5.3.3f1 (x64 ‘Personal’ version). I am not currently using Unity as I use and develop my own engine technology. The code in this tutorial is all C# and calls to the XInputDotNet plugin, it should port over to more recent versions of the engine just fine.
Welcome to Part 4 of my Xbox360 gamepad tutorial for the Unity engine!
At the end of Part 3, we finished the ‘x360_Gamepad‘ script and it’s ready to go! Now it’s finally time to ‘manage’ some gamepads, it’s in the title of this tutorial series after all. Before we get started, I recommend reading and following the code in the previous parts if you’re reading this and haven’t already. Here is the link to download the complete tutorial code so far (you can also find it at the end of Part 3) and quick links to the other parts of this series.
Complete ‘x360_Gamepad’ C# script: Download (7.4 KB)
Jump to:
Part 1 – Setting up
Part 2 – Button input
Part 3 – Rumble + Thumbstick and Trigger input
Gamepad Management?
You could easily create an instance of the ‘x360_Gamepad‘ (or your class name) class in say, a character controller script to use the gamepad for player controls. The problem is this instance only exists there, if you wanted to get input from this instance in another script (several in my case, which is why I made this manager), you could find yourself writing more code to find the desired game object, get its desired script component and then get the gamepad instance from there.
To be honest, that’s what we did for a while on Tides of War. It might not be elegant but it does work. Before we get into the code, let’s sum up what we want the Gamepad Manager to do:
- Store up to four gamepads (handy for co-op / multiplayer on single screen)
- Exist only ONCE in the Unity project and be easy to access from ANY script
- Created once, kept in each Unity scene should the project switch between them
- Handle updating the gamepad(s) and any multi-gamepad functionality
Setting up the ‘GamepadManager’:
Feel free to call it whatever you like, for the rest of the tutorial I will be calling this system ‘GamepadManager’. Let’s start by creating two new C# scripts – ‘RefreshGamepads‘ (I’ll explain that one soon) and ‘GamepadManager‘. Of course, like any new script files they inherit from the MonoBehaviour class, which means we must attach them to a game object in the scene for them to run.
We’ll continue using ‘TestScene‘, our empty scene from Part 1. If you’re adding this system to an existing Unity project, use any scene you like. First, let’s create an empty game object. It won’t need anything fancy such as mesh or sprite renderers, or colliders. Since it won’t be visible, let’s position it to zero (all position values to zero). Next, attach the two new scripts we created. Now your ‘GamepadManager’ game object should look similar to this.
The Singleton Instance
This should sound familiar. Or you may be thinking “What’s a ‘singleton’?!”. For anyone unfamiliar, the Singleton is a design pattern in software development and we will use it for the GamepadManager. I won’t go into a lot of detail on the pattern itself, to put it simply though, it means the class will be created only once, prevent duplicate copies being created (on purpose or by mistake) and be accessible like a public variable…from anywhere in our other scripts!
Note: There are many great articles and tutorials in several programming languages on the net, detailing the Singleton and other design patterns.
The ‘GamepadManager‘ script is just a blank template at the moment, let’s remove the ‘Start‘ function Unity gave us and replace it with ‘Awake‘. We also need a few variables:
- GamepadCount – Number of gamepads you want to support (1 to 4)
- gamepads – List container to store the gamepad instances
- singleton – Important! This is the static instance of the script.
Now the ‘GamepadManager’ script should look similar to this:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// Gamepad Manager class
public class GamepadManager : MonoBehaviour
{
public int GamepadCount = 2; // Number of gamepads to support
private List gamepads; // Holds gamepad instances
private static GamepadManager singleton; // Singleton instance
// Initialize on 'Awake'
void Awake()
{
}
// Normal Unity update
void Update()
{
}
}
Note – ‘Awake’ vs ‘Start’: We’re using ‘Awake‘ because it is called by the engine before ‘Start‘ and is called only once when the script is loaded. The Unity documentation is very useful for looking up such functions! For more information, here are the Scripting API references for Awake and Start.
First, the GamepadManager should check to see if its singleton instance has been assigned AND if the singleton instance is NOT assigned to itself. You could think of it as the GamepadManager saying “My singleton is assigned but not to me!“. This means another instance of the GamepadManager was loaded, creating another copy of the singleton. We know the whole idea of the singleton is for there to be only ONE, not two or several copies.
If found, the duplicate singleton must be destroyed. We can perform this check with a simple if statement.
// Initialize on 'Awake'
void Awake()
{
// Found a duplicate instance of this class, destroy it!
if (singleton != null && singleton != this)
{
Destroy(this.gameObject);
return;
}
}
What if there isn’t a duplicate singleton? We run the remainder of our ‘Awake‘ function – the code to initialize the GamepadManager. We’ll start by assigning the singleton instance to this – the current instance of the GamepadManager script, as now we immediately destroy any other instance(s) that are found (there should only be one in your scene anyway).
Once again, you could think of it as the GamepadManager saying “My singleton is assigned, to me!“. Now we have ticked off our “exist only once” feature, next we must keep the GamepadManager object between scenes. Should you switch from one scene to another while the game is running, Unity cleans up by destroying all objects in the scene before loading the next one. This is fine until you want to keep a certain object for the next scene and Unity has a function to just that!
// Initialize on 'Awake'
void Awake()
{
// Duplicate singleton check...
else
{
// Create singleton instance
singleton = this;
DontDestroyOnLoad(this.gameObject);
}
}
Using the DontDestroyOnLoad function, we protect the GamepadManager object from being accidentally destroyed when switching scenes and tick off the “Created once, kept in each Unity scene” feature. Even if your game / project is just a single scene, it’s still handy to have this feature just in case.
Finally, to finish initializing the GamepadManager, we’ll restrict the GamepadCount to the supported 1 to 4 range and create the requested number of gamepad instances.
// Initialize on 'Awake'
void Awake()
{
// Duplicate singleton check...
else
{
// Create singleton instance...
// Lock GamepadCount to supported range
GamepadCount = Mathf.Clamp(GamepadCount, 1, 4);
gamepads = new List();
// Create specified number of gamepad instances
for (int i = 0; i < GamepadCount; ++i)
gamepads.Add(new x360_Gamepad(i + 1));
}
}
Accessing the Singleton Instance….From any Script:
So far we’ve created the GamepadManager singleton and the class will automatically check for and destroy any duplicates. Now let’s address the last, but definitely not least important feature of our singleton…being able to access it from any other script in the project.
Remember how we made the singleton variable static? I won’t detail use of the static keyword here, but simply put, it allows us to access the singleton instance without needing to make an instance of the class. If that sounds confusing, it will make sense very soon! Wait, we made the singleton variable private! Other scripts can’t access it at that protection level. Let’s make a ‘get‘ to publicly access the singleton from other scripts:
// Return instance
public static GamepadManager Instance
{
get
{
if (singleton == null)
{
Debug.LogError("[GamepadManager]: Instance does not exist!");
return null;
}
return singleton;
}
}
First of all, you may notice this isn’t a function (eg. something(); ). Because we’re using C#, we made use of the ‘get‘ statement, so you could think of using this like a public variable rather than a normal function. I added the error check so Unity will actually send an error message to its console if the singleton has not been created. You would only get this error if the script was not on a game object in the scene and you tried accessing the GamepadManager in another script. We have already prevented this by setting up the ‘GamepadManager’ object earlier.
Well that wraps up the singleton functionality, we can use GamepadManager.Instance to access the singleton from other scripts. Of course, we don’t have any other functionality in the GamepadManager yet. Next, let’s update and refresh the GamepadManager.
Update and Refresh:
Since we kept the original Update function (that you get in any MonoBehaviour script), we’re going to use it to update the gamepad(s). All we do here is loop through the gamepads list and call the ‘Update’ function of each gamepad.
// Normal unity update
void Update()
{
for (int i = 0; i < gamepads.Count; ++i)
gamepads[i].Update();
}
The ‘Refresh‘ function is almost identical, however it must be public since we will need to call it elsewhere.
// Refresh gamepad states for next update
public void Refresh()
{
for (int i = 0; i < gamepads.Count; ++i)
gamepads[i].Refresh();
}
For the gamepad’s ‘GetButtonDown‘ (button press on current frame only) functionality to work, ‘Refresh‘ must be called at the end of our update cycle – or in this case, Unity’s update cycle. The solution is our ‘RefreshGamepads‘ script and a little bit of changing the project settings!
First, let’s use the Unity update function in the still blank ‘RefreshGamepads‘ script to tell the GamepadManager to refresh the gamepads. With all the singleton work we’ve done, it’s as simple as this:
// Normal unity update
void Update()
{
GamepadManager.Instance.Refresh();
}
That’s our first look at the GamepadManager singleton in action, we didn’t need to make an instance, find the script or anything!
For the second and last step, we want the RefreshGamepads‘ Update to be called at the end of the update cycle and GamepadManager’s Update to be called at the start. Unity’s Script Execution Order menu will do this nicely! If you’re unfamiliar with this feature of Unity, it can be found under Edit > Project Settings > Script Execution Order.
As the editor says, all scripts we don’t add to this custom order will execute at the default time, which is fine. You can drag the scripts to this inspector pane or click the plus (‘+’) to add them to the custom order. We want GamepadManager to run before Default Time and RefreshGamepads to run after. Those numbers represent the order the scripts will execute and usually default to 100. Feel free to experiment with the numbers if you like, this screenshot shows what I used. Be sure to save your project or these changes won’t be saved!
Part 4 Summary:
I decided to split the final part of this tutorial into two separate parts, this being the first. The GamepadManager is now set up and can manage 1 to 4 gamepads as needed. You can even change the GamepadCount variable in the editor, without needing to change any code! With the core functionality complete, next we will look at the remaining ‘Utility’ functionality for the GamepadManager.
Continue to: Part 5 – Gamepad Management – ‘Utility‘
Jump to:
Part 1 – Setting up
Part 2 – Button input
Part 3 – Rumble + Thumbstick and Trigger input