It’s Brian again and it’s time for another update post of the development of Wulverblade. I promised more detail after the last post and I’ve decided to focus on an area of the game that I’ve been working on a lot recently: input.
Input systems are the kind that get overlooked quite often. They aren’t glamorous or sexy but a game with poor input will never feel polished. This is one area where putting this game out on PC actually makes things considerably more complicated. Being on PC means supporting a lot of different input devices at the same time and also supporting a much higher expectation of customization than other platforms. When a game is released on PC you have to consider that users will expect to be able to fiddle with game settings and control many different aspects of the experience. You will need to think about the specter of rebindable controls.
The plan with Wulverblade is to support various gamepads as well as mouse & keyboard. So the question becomes: how do we support this flexibility for the user and what does Unity provide to us to make this easier (or harder)?
The input system in Unity is centered around the Input Manager which is a system that can be configured inside the editor. From code you can access the system using the Input class which has a bunch of static functions and properties. This let’s you check if keys or buttons are pressed or if a joystick or gamepad axis is being pushed. When you would like to handle an axis like this (think of pushing a thumbstick to the right) you must define the axis ahead of time by giving it a name, specifying the axis number, the joystick number, and other settings like deadzone in the Input Manager.
Let’s say you have set axis 5 for joystick 1 to be defined as “right.” What happens when a player plugs in a different controller which has the thumbstick axis not defined as 5? Suddenly the gamepad will not work correctly for this user. Since Unity’s Input Manager must be set up ahead of time it would appear that this kind of situation could happen easily and that there would be no real good solution to the problem. Even more complicated is that if we truly want configurable controls we need to allow “right” to be defined as a controller button, a controller axis, or a keyboard key code all of which are accessed and checked from the code using different functions (GetButton, GetAxis, GetKey respectively).
The first thing to do to start to create a more flexible system is to change the game from reacting to specific inputs to instead react to abstract “actions.” You define a set of actions that the game looks for which are the basic control concepts in the game. Here is how we define our actions currently:
public enum ActionType {
Left = 0,
Right = 1,
Up = 2,
Down = 3,
Jump = 4,
Attack1 = 5,
Attack2 = 6,
Special = 7,
Menu = 8,
LastAction
}
Explicitly assigning indices to the enumerations isn’t really necessary here as the compiler will do that for us but sometimes it is good to be explicit for our own sake. We can then map these actions to an input binding which can be either a mouse button, keyboard key, gamepad button, or gamepad axis. In our update loop we can then go through each possible action and check if the corresponding input binding is active or not and set our game action’s active state. For organization purposes we separate bindings for keyboard/mouse from gamepad. So a player will be put in gamepad mode or keyboard/mouse mode and the modes can be set by the user in the options menu.
The variable “currentInput” can be Keyboard, Gamepad1, or Gamepad2. You can see that when we check the gamepad axes we use our own dead zone checking. This is instead of using the Unity Input Manager built in dead zone checking. This is mostly a style choice as I prefer to do this sort of checking in my own code where I can control it and possibly do more sophisticated processing than is shown here.
We need to be able to store bindings for later. You can save out each binding fairly easily by saving the action and then it’s corresponding input binding setting. An important element to smoothly working input system is detecting when the user has set the bindings themselves or when default bindings should be used. The first time the game runs it will detect that no bindings had been saved and it will load defaults for keyboard/mouse and also for the gamepad.
Gamepad bindings on PC can be tricky because different devices will have different mappings. One gamepad can have its left analog stick affect Unity’s axis 0, while another might be bound to axis 1. We plan on supporting as many gamepads as possible with sensible defaults by creating text files which represent input bindings for popular gamepads. The input file has the name that the OS will tell us from the gamepad an then each action-input binding. These text files are loaded and then matched against the currently plugged in gamepad. In this way the most popular gamepads will be able to be used with no configuration by the user.
If you have any questions or want more specific and in-depth info on how this system works you can just ask in the comments. Also, let me know if there is another topic you’d like me to cover for the next update. Otherwise I’ll probably just talk about whatever system I spent a good deal of time working on.