Simple Script for Gamepad UI Navigation

For my upcoming game, Mouse Dreams, I need to support gamepad input as well as keyboard and touch. It turns out this is not quite as simple as I first thought. The big issue with supporting UI with different input methods is how it will appear to the user. With touch or mouse input, the user simply presses a button, but with controller or keyboard input, you need to indicate to the player which button is currently selected.

Unity’s UI can easily implement colour changes when a button is selected, but this can look weird with touch input, and is not always easy to see. Unity’s UI also doesn’t work with controller input if no UI object is currently selected (or a default set), which is a pain.

I wrote a simple script to help with these problems. It simply scales the currently selected UI button to be a bit larger than the others. The scaling amount can be adjusted in the Inspector, and you can set a default UI object to be selected when the scene starts, which in turn enables controller input.

The Code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class ButtonHighlighter : MonoBehaviour
{
    private Button previousButton;
    [SerializeField] private float scaleAmount = 1.4f;
    [SerializeField] private GameObject defaultButton;
   
    void Start()
    {
       if (defaultButton != null)
       {
          EventSystem.current.SetSelectedGameObject(defaultButton);
       }
    }

    void Update()
    {
       var selectedObj =   EventSystem.current.currentSelectedGameObject;
    if (selectedObj == null) return;
    var selectedAsButton = selectedObj.GetComponent<Button>();
    if(selectedAsButton != null && selectedAsButton != previousButton)
    {
       if(selectedAsButton.transform.name != "PauseButton")
       HighlightButton(selectedAsButton);
    }
    if (previousButton != null && previousButton != selectedAsButton)
    {
       UnHighlightButton(previousButton);
    }
    previousButton = selectedAsButton;
 }
 
  void OnDisable()
  {
     if (previousButton != null) UnHighlightButton(previousButton);
  }

  void HighlightButton(Button butt)
  {
    if (SettingsManager.Instance.UsingTouchControls) return;
    butt.transform.localScale = new Vector3(scaleAmount, scaleAmount, scaleAmount);
 }

 void UnHighlightButton(Button butt)
 {
    if (SettingsManager.Instance.UsingTouchControls) return;
    butt.transform.localScale = new Vector3(1, 1, 1)
 }
}

How to Use

Just add the script to a UI canvas with multiple buttons. I coded the script specifically for buttons, but you can easily adjust it to work with different UI objects if you need to.

For improved scaling, you can implement some tweening or lerping.

Set the scaling to an appropriate amount. The default is 1.4f, which may be a bit large for some uses. You need to find a balance between looking good and being noticeable to the player.

Set a default button in the Inspector. This will be selected automatically when the scene starts, which has the side effect of enabling controller input.

Leave a Comment