CHAPTER 5
If the player can’t control the game, we don’t have much of a game. The main types of input your game must handle will be mouse and keyboard (PC), gamepad (PC and console), and touch (mobile). You might also consider voice and tilt inputs, although we won’t cover those here. And, touch is difficult to implement correctly—it would require more explanation than we have room for here. If you’re creating only mobile games, you’ll want to look into both touch and tilt input methods. The Touch, TouchScreenKeyboard, and Gyroscope classes in the API will be good places to start.
Fortunately, Unity handles a lot of the input automatically. For PC games, the mouse works fine. No need to draw the pointer every frame and calculate its location. Unity also handles a lot of the UI work for you. Nearly all you need to do is write code for whatever a button does when you click on it, what happens when a check box is checked or unchecked, etc. We’ll see that in the UI section.
Before dealing with getting input, we need to see how Unity handles peripheral configuration. The Input Manager tracks which keys/mouse control/etc. is used for actions in the game and allows the player to configure the input. The screenshot in Figure 27 shows the Input tab of the window being displayed when a game is run.

Figure 27: Game Configuration Window
This window shows the input values that were set when the game was compiled. These values can be changed in the InputManager window in the Unity editor, as shown in Figure 28.

Figure 28: InputManager Window
Note that some actions, such as Horizontal, Vertical, Fire, Submit, and Jump, are listed multiple times. If you open all the versions of an action, you’ll see that they are defined for multiple types of input devices. The first Horizontal type is Key or Mouse button—the left/right or a/d keys, as well as the x-axis on the mouse, will trigger horizontal movement. The second Horizontal type is Joystick Axis. You might wonder why they didn’t simply define the Joystick type with the mouse. A PC will almost always have a mouse and keyboard, but a joystick is generally pretty rare.
In order to make this more confusing, take a look at the Fire1 actions. Both are listed as Key or Mouse button, one is left Ctrl/mouse 0 and the other is joystick button 0. This means that configuring your own actions will take some trial and error. Or you can just use the Get… methods of the Input class to check for specific inputs for specific actions and not allow the player to custom configure those actions. This will limit your game somewhat, however.
The main class you’ll be dealing with is the Input class. Everything in the class is static, which means you don’t need an instance of the class. For PC, the variables you’ll be dealing with are inputString, mousePosition, and possibly anyKey and anyKeyDown. There are a number of methods in the class for dealing with mouse and keyboard (and joystick for those who still use them). Table 3 shows a partial list of input methods.
Table 3: Input Class Methods for PC
GetAxis | Returns the value of the virtual axis identified by axisName. |
GetAxisRow | Returns the value of the virtual axis identified by axisName with no smoothing filtering applied. |
Returns true while the virtual button identified by buttonName is held down. | |
Returns true during the frame the user pressed down the virtual button identified by buttonName. | |
Returns true the first frame the user releases the virtual button identified by buttonName. | |
GetJoystickNames | Returns an array of strings describing the connected joysticks. |
Returns true while the user holds down the key identified by name. Think autofire. | |
Returns true during the frame the user starts pressing down the key identified by name. | |
Returns true during the frame the user releases the key identified by name. | |
Returns whether the given mouse button is held down. | |
Returns true during the frame the user pressed the given mouse button. | |
Returns true during the frame the user releases the given mouse button. |
Fortunately, for our purposes we’ll only need to use three methods and the mousePosition variable. We don’t have any text input to deal with. If you want to enhance the game by adding a login for items such as a multiplayer mode and tracking high scores, you still won’t necessarily need to use any more functionality in the Input class because the UI controls will be able to handle most of your needs.
We’ll use the GetKeyDown method for determining when to pause and unpause the game. We’ll use the GetAxis method for moving the player. We’ll use the GetButton method for handling firing bullets. Lastly, we’ll use the mousePosition for determining where the character is pointing in order to rotate the character sprite, which will affect where the bullet is fired.
In the Scripts folder, add a class that we’ll use for controlling the character or player. I have called it PlayerController because that’s the name you’ll find in a lot of Unity samples and tutorials. Add the code from Code Listing 12.
Code Listing 12: PlayerController Class
public float Speed; private float _fireRate = .5f; private float _nextFireTime = 0.0F; public GameObject Bullet; private bool _bulletFired = true; void OnTriggerEnter2D(Collider2D collider) { if (Globals.CurGameState == GameState.PlayingGame) { if (collider.gameObject.tag == "Ghost") { Globals.Health--; Destroy(collider.gameObject); } } } void Update() { if (Globals.CurGameState == GameState.PlayingGame) { Vector3 vel = new Vector3(); vel.x = Input.GetAxis("Horizontal"); vel.y = Input.GetAxis("Vertical"); Vector3.Normalize(vel); vel *= Speed; float x, y; GetComponent<Rigidbody2D>().velocity = vel; x = Mathf.Clamp(transform.position.x, -4.5f, 4.5f); y = Mathf.Clamp(transform.position.y, -3.0f, 3.0f); transform.position = new Vector3(x, y, 0); //rotation Vector3 mouse = Input.mousePosition; Vector3 screenPoint = Camera.main.WorldToScreenPoint(transform.localPosition); Vector2 offset = new Vector2(mouse.x - screenPoint.x, mouse.y - screenPoint.y); float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - 90.0f; transform.rotation = Quaternion.Euler(0, 0, angle); if (_bulletFired) { _nextFireTime += Time.deltaTime; if (_nextFireTime >= _fireRate) _bulletFired = false; } if (Input.GetButton("Fire1") && !_bulletFired) { //spawn bullet GameObject bullet = (GameObject)Instantiate(Bullet, transform.position, transform.rotation); _nextFireTime -= _fireRate; _bulletFired = true; }
} } |
The Update method will be called with every frame. We’ll use the current mouse and keyboard values to determine where the character script will be drawn and which way it will face. The Horizontal and Vertical axes are used along with a constant speed, which is set in the Unity editor, and the current position of the sprite from the built-in Transform object to determine the new position. The mousePosition variable of the Input class is used along with the position of the sprite in order to determine how much the sprite needs to be rotated in order for it to face the mouse—so that the sprite will appear to be firing toward where the mouse is pointed.
The last action of the method will check to see if the player is pressing the control mapped to the Fire1 action. If so, and if the player is allowed to fire, a bullet is spawned and variables are set to ensure the player can’t fire again before he’s allowed.
The code uses a couple of globals that we need to add to the Globals script. The CurGameState and Health members go in the Globals class, with the enum outside of it.
Code Listing 13: Input-Related Global Code
public static GameState CurGameState; public static int Health; public enum GameState { PlayingGame, PauseGame, GameOver } |
You might want to consider allowing the player to use a gamepad in order to control the character. Even on a PC, some players prefer to use a gamepad for games. Allowing your game to handle a gamepad will also make it easier to convert to a console version.