Press "Enter" to skip to content

Implementing Touch Controls in Unity 3D

So much input!
So much input!

Throughout the ages games have been controlled in a variety of ways: joysticks, gamepads, mouse & keyboard, and many more! With the advent of mobile devices new styles of input have become available to us, namely touch screen controls. In this tutorial you’ll learn how to implement two different styles of touch input in Unity:

  • Virtual joystick: This is where buttons on the screen that are similar to a gamepad or joystick are used.
  • Direct interaction: This is where the player directly interacts with objects in the game to control their movement, firing, and other actions.

Unity makes it incredibly easy to take advantage of different styles of input so that your game is accessible on many platforms. It’s time to tap in!

Note: This tutorial assumes that you’re familiar with the basics of the Unity Editor, its UI components, and that you have some knowledge of C#.

 

Getting Started

Make sure you’ve downloaded and installed the latest version of Unity from here.

Next, download the snowballcannon_starter_project for this tutorial. Then unzip it and open up the SnowballCannon project in Unity. This is the foundation for the game you’ll be implementing touch controls for.

Snowball Cannon
Snowball Cannon

The game is a simple one: snowmen are invading your back yard! Armed with your snowball cannon you must repel their relentless attack! You have control over firing and aiming a cannon that launches snowballs at the invading snowmen. You can also drop water balloons on the ground to slow down the snowmen.

The game logic is simple: the snowmen spawn every couple of seconds and move toward the cannon. If too many snowmen reach the cannon then the game is over. The scene is set up so that you can use mouse and keyboard to play immediately (StandAloneInputController.cs). So go ahead and run the scene to play the game and check out how it works.

Note: Assets for the game come from Kenney, Aetherna.

Before you get started with adding new controls, take a look at the class you’ll be interfacing with for controlling the cannon. Open up PlayerController.cs in your IDE (Visual Studio or MonoDevelop) and read through the code and comments to get a feel for how it works. The new classes that you’ll make for touch input will access the controls of the cannon via this class. Specifically you’ll be using the RotateCannon(int direction) and Fire() methods. In the scene hierarchy this script is attached to the Player game object.
Many of the classes are quite reuseable and the logic for the game is controlled through events that are all assigned in the inspector for the game objects (mainly Player and EnemySpawner). You’ll learn more about that throughout the tutorial.

You’ll also be using the WaterBalloonController class to make copies of the water balloons and then enable their rigidbody so that they drop onto the ground. That will be explained that in greater detail later. For now you can see an example of this in the StandaloneInputController class.

Using Unity UI for Player Input

In this section you’ll add some UI buttons to the game, create some scripts for those buttons to work intuitively, and assign the events for those buttons via the inspector.

Preparing the Scene

You’ll need to prep the scene first, make a copy of the Main.unity scene by opening it in the editor then going to the File menu and selecting Save Scene As. Save the scene as VirtualJoystick.unity.

Remove the event that enables StandaloneInputController from the OnClick event list on the PlayCanvas/Panel/PlayButton game object’s Button component like so:

1-remove-standardinputcontroller-event-from-play-button

Remove the event that disables StandaloneInputController from the Player game object’s Health component like so:
2-remove-standardinputcontroller-event-from-player-health

Great! Now you’ve removed the game’s ability to activate and deactivate the StandAloneInputController and you can no longer control the game. You’re scene is now ready for a new input method!

Adding the UI Joystick Buttons

Now add a new UI Canvas to the scene and name it VirtualJoystickCanvas. Add a Canvas Group component to it and deselect the Interactable checkbox (you’ll activate this later with the PlayButton‘s OnClick event). In that canvas, add 3 buttons: one for rotating the cannon up (1), one for rotating the cannon down (2), and a third for firing the cannon (3). In the Sprites/OnScreenControls/ShadedDark folder you’ll find the sprites that are used for the buttons. The scene should look like this when you’re done setting up the UI buttons:
3-virtualjoystickcanvas-setup

Adding the Events

Now that the UI is set up in the scene it’s time to make the buttons interactive. What good is a button you can’t press, right? Start with the simple one, the FireButton. To set this up simply click the button in the On Click() area of the inspector. Drag and drop the Player game object into the empty slot that appears. Then select PlayerController.Fire() from the dropdown menu like so:
4-add-firebutton-event

Now any time this button is clicked it will fire a snowball. Nice and easy! For the Up and Down buttons there is a little more work to do. This is because the OnClick() event for a button is only fired once per click. The cannon should rotate continuously while the button is held down. To do this you’ll need to make a script to handle the state of the button and you’ll need to make use of Unity’s Event Trigger component.

Create a new C# script and name it HoldButtonEventHandler. The script will only use two namespaces:

The UnityEngine.Events namespace contains a class called UnityEvent. When a public object of this type is added to a MonoBehaviour derived class it becomes visible in the inspector and shows up just like the OnClick() events on a Button component.

5-holdbuttoneventhandler-component-empty

Now add the following variables to the class:

  1. The OnButtonHeld event will be invoked (or fired) when the button is being held down. This event will be assigned in the inspector similar to the OnClick event for the FireButton.
  2. The value of pressed will tell the class that the OnButtonHeld event should be invoked.

Add the following lines of code to the HoldButtonEventHandler class to finish it up.

  1. The SetPressed method will be called from an Event Trigger that will pass the value of true to the method when the Up or Down button is pressed.
  2. The Update method will continuously check to see if pressed is true. If it is then OnButtonHeld will be invoked.

Now that the script is ready it’s time to set up the components on the button to connect it all together:

  1. Add an Event Trigger component and add the new Hold Button Event Handler script to the Up button.
  2. Click the Add New Event Type button on the Event Trigger component and add a PointerDown event.
  3. In the event area click the button to add a new event slot just like you did for the OnClick() event for the fire button.
  4. Drag and drop the Up button game object from the hierarchy window into the empty slot and select HoldButtonEventHandler and then SetPressed from the dropdown menu.
  5. A checkbox should now appear. The is the parameter of SetPressed. Since this is the PointerDown event, you’ll want to check the checkbox to indicate the bool parameter’s value is true.

Repeat this process for a PointerUp event on the Event Trigger component, but leave the checkbox unchecked since this will be telling the HoldButtonEventHandler class that the button is no longer being pressed. Finally, in the Hold Button Event Handler component add PlayerController.RotatateCannon method call with a parameter value of 1. This will rotate the cannon up. Your Up button’s inspector should now look like this:
6-up-button-inspector

Repeat that same process for the Down button, but in the Hold Button Event Handler component’s call to PlayerController.RotatateCannon use a parameter value of -1 so that the cannon will rotate down.

Finally, ensure that the VirtualJoystickCanvas game object’s Canvas Group component is set to interactable when the PlayButton is pressed and set to not interactable when the player dies (i.e. when the Player game object’s Health component’s OnHealthZero() event fires).

After setting that up, your PlayButton OnClick events should look like this:
7a-playbutton-virtualjoystick-interactable

Your Player OnHealthZero events should look like this:
7b-player-virtualjoystick-not-interactable

Take a coffee break and play the game a little! If you’ve followed all of the steps correctly then you will be able to aim and fire the cannon with your new virtual joystick! Be careful not to spill that coffee on the snowmen, they’re taking enough torture from the snowball onslaught!

 

This is much easier with two hands!
This is much easier with two hands!

Input Through Direct Interaction

This is where the fun truly begins and you’ll dive deeper into Unity’s Event systems. User input on mobile devices is quite touch and go… It’s very natural to control items on the screen by touching them and moving them. In this section you’ll learn how to make the cannon rotate by swiping up or down. It’ll fire whenever you tap and lift your finger. Finally, you’ll make it so that the water balloons can be dragged and dropped onto the ground.

Scene Preparation Revisited

Repeat the same process that was described in Preparing The Scene, but this time name the copy of the scene EventInterfaces.

Select the Camera in the scene and add a Physics 2D Raycaster component. This allows Unity to detect pointer or touch input and cast a ray (a straight line) into the scene to detect what collider is hit by the ray. This is super important!

Note: Make sure to add the Physics 2D Raycaster component to your scene’s main camera. Also note that all of the scripts in this section must be attached to game objects with colliders. The collider is what tells the Physics 2D Raycaster that something is being pointed at.

 

Controlling The Cannon

To control the cannon via direct input you’ll need two scripts: one to handle swiping (rotating the cannon) and another to handle pointer up (firing the cannon). Start with the OnPointerUpEventHandler class.

Notice the similarities between this and the HoldButtonEventHandler class. Here’s how it all works:

  1. The OnPointerReleased event will be assigned in the inspector. It’ll be used to call the PlayerController.Fire() method.
  2. enabledOnAwake will allow or prevent the methods in this class from running until it is desired.
  3. The Awake method will simply set this Monobehaviour enabled (or not) when it wakes up so it will respect te setting of enabledOnAwake.
  4. The OnPointerUp method is a required method for the implementation of the IPointerUpHandler interface. This is what sends and receives data from Unity’s event system. This method will simply Invoke the OnPointerReleased event when the pointer click (or touch) is released.
  5. The OnPointerDown method doesn’t actually do anything in this class, but it is required (along with IPointerDownHandler) to make OnPointerUp work.

This class inherits from MonoBehaviour, but also notice that it implements two interfaces: IPointerUpHandler and IPointerDownHandler (these are both in the UnityEngine.EventSystems namespace). Interfaces can be thought of as contracts or templates that the class is going to specifically define (i.e. implement). If you’re using Visual Studio, you may notice that when you type in these interface names they are underlined with a red mark. You can hover your mouse over these words, click on the light bulb icon, and select Implement interface, then Visual Studio will create stubs for the methods that are required by the interface.
8a-vs-interface-fill

Note: It is very important that you implement both IPointerUpHandler and IPointerDownHandler.

Go back to the Unity Editor and add this new script to the Player game object. Assign PlayerController.Fire to the OnPointerReleased() event. Make sure that Enabled On Awake checkbox is off. Your inspector should look like this:
8-onpointerupeventhandler

Don’t press play yet! There’s still some work to do. Next, make a class to handle the rotation of the cannon, call it SwipeEventHandler. The class is very similar to the OnPointerUpEventHandler class.

Here’s what it all does:

  1. The OnDragUpward event will be assigned in the inspector. This will be used to call the PlayerController.RotateCannon(1) method to rotated the cannon upward.
  2. The OnDrageDownward event will do the opposite and be used to rotate the cannon down.
  3. The OnDrag method is the method required by IDragHandler. This method uses its eventData parameter’s change in y position to decide whether to invoke OnDragUpward or OnDrageDownward.

Back in the Unity Editor, add this script to the Player game object and assign the OnDragUpward() event to call PlayerController.RotateCannon with a parameter value of 1. Do the same with OnDragDownward but use a parameter value of -1 to rotate the cannon down. Make sure that Enabled On Awake is off. The inspector for this component should look like this:

Similar to before, ensure that these components are correctly activated when the PlayButton is pressed and deactivated when the Player game object’s Health component’s OnHealthZero event is fired. The inspector for the Player game object’s Health component should look like this:

10-PlayerHealthEvents

Finally, make sure that the PlayButton game object’s OnClick() event properly enables the SwipeEventHandler and OnPointerUpHnadler. It’s inspector should look like this when you’re done:
11-PlayButton_EventEnables

The code is pretty short and sweet and these classes are highly reusable. It’s time to take a short break and play a little! If everything is connected properly you should be able to aim the cannon by clicking and dragging up or down over the cannon, every time the mouse button is released (or finger is lifted) the cannon will fire.

Ready, aim, snowball!
Ready, aim, snowball!

Dragging and Dropping Water Balloons

In the final part of this tutorial you’ll set up another event handler to allow the user to drag and drop water balloons so they fall onto the ground and create an ice patch to slow down the snowmen. Create a new class called DragDropEventHandler with the following code:

Many parts of this class are exactly the same as previous classes, so they won’t be explained again. In this class there is a another class, Vector3Event. UnityEvents can have have up to four parameters, but you need a little extra to get them to show in the inspector. Here’s how it works:

  1. The Vector3Event class is a custom event that can accept a Vector3 parameter. The class must be marked [System.Serializable] to get Vector3Event variables to display in the inspector.
  2. The OnDragMove event will show up in the inspector just like the other events that you’ve used. This event will be used to control the positions of the water ballons as they’re dragged.

The next part of this class will implement the required methods for the IBeginDragHandler, IDragHandler, and IDropHandler interfaces.

  1. The OnBeginDrag method is the required method for IBeginDragHandler. This runs when the user starts to click and drag the game object this script is attached to. The method simply Invokes the OnDragStart event which will be assigned in the inspector.
  2. The OnDrag method is the required method for IDragHandler. This will run as the user holds down the pointer and moves around. It will Invoke OnDragMove and pass through the world position of the pointer. This will be used to position the balloon as it is dragged around.
  3. The OnDrop method is the required method for IDropHandler. This runs when the user releases the pointer click and simply Invokes OnDragReleased which will be assigned in the inspector to activate the physics on the balloon so it will drop to the ground.

Add this script to the WaterBalloon game object and set up its events like so:
12-WaterBalloon-DragDropEventHandler

Important! When selecting the method to call for OnDragMove you need to select from the Dynamic section of the dropdown menu. This ensures that the value passed via Invoke is sent to the Water baloon’s Transform.position property.

12b-DynamicEvent

When dragging starts a copy of the WaterBalloon game object is created by calling the WaterBalloonController.MakeCopy method. The copy stays in place of the existing one since the user is actually dragging the existing water balloon. When the drag is moving the world position of the pointer is passed into the transform of the water balloon which makes it follow the pointer. Finally, when the drag is released the DragDropEventHandler is disabled and the RigidBody2D component on the WaterBalloon is set to no longer be kinematic so that it will fall to the ground.

Once you have the DragDropEventHandler all set up on the WaterBalloon game object the last thing to do is to make sure it is enabled when the PlayButton is clicked and disabled when the player’s health is zero just like you’ve done with the other event handlers. The inspector for the PlayButton should look like this:

13-PlayButton-WaterBalloon-DragDropEvent

And the Player game object’s Health component should look like this:
14-Player-Health-DragDrop

Now you can press play and test out the new drag and drop functionality of the water balloon. Soak those snowmen and make them slip on the ice! Great job for making it this far! This is a lot of new information, but the code is in small chunks and everything is simple to set up in the inspector so that you can control logic without changing the code.

Now that's cool
Now that’s cool…

Which Method Should You Use?

ask-questionsThat’s a great question! The answer is… “It depends.” Ask yourself the following:

  • Can you afford screen space for joystick buttons?
  • Are the controls of your game too complex to directly interact with objects?
  • Which method “feels” better?

When in doubt, try both methods and ask beta users. This tutorial has provided you with the basis of adding these controls to your game, but the actual input method chosen is often best left up to users. Some people are more comfortable with a gamepad and others are more comfortable with mouse and keyboard. It’s not that difficult to give the user the choice and oftentimes users love to have the option!

Where to Go from Here?

  • Read more on Unity’s Event Systems and explore the various supported events.
  • Explore the Event Trigger component more and try invoking other class methods with it.

You can download the complete project from here (snowballcannon_completed) to have a reference to check your work against.

As always, thanks for reading and don’t forget to subscribe for more awesome tutorials right to your inbox! If you have any questions or feedback just leave a comment down below!

Loading

2 Comments

  1. Mckinney Via
    Mckinney Via 2021/11/18

    Very much appreciated. Thank you for this excellent article. Keep posting!

Leave a Reply

Your email address will not be published. Required fields are marked *