Unity3D: Input Controllers and uGUI


Unity3D 4.6 has recently introduced the long awaited GUI system, and along with that, Input Controllers.

Input Controllers are the backbone of controlling uGUI and by default, Unity provides a Standalone Input Module and a Touch Input Module. These cover simple interactions such as single select and movement, but don't cover more complex controllers or multiple inputs on their own.

I ran into the issue of hosting 2 players on a single GUI canvas early in development of BirdBall. Luck wasn't on our side either with us as we were also using the early Unity 4.6 beta. At the time, there was no documented solution. Fortunately, during the development of 4.6, Tim Cooper (Stramit) posted examples of Input Controllers for us to use as a guide to create more complex Input Controllers.

A key point to note in creating a custom input controller is that Unity doesn't regulate what is selected or unselected. The EventSystem however can change an objects state with the following:

ExecuteEvents.Execute<ISelectHandler>(Selected, new BaseEventData(EventSystem.current), ExecuteEvents.selectHandler);  

This also extends to Pointer Movements, Dragging, Selecting, and essentially all the supported interactions.

As an example, you could submit a selected object:

private bool SendSubmitEventToSelectedObject()  
{
    // Return if nothing is selected
    if (EventSystem.current.currentSelectedGameObject == null)
        return false;

    ExecuteEvents.Execute<ISubmitHandler>(EventSystem.current.currentSelectedGameObject, new BaseEventData(EventSystem.current), ExecuteEvents.submitHandler);

    return true;
}

Or a movement event:
(This example uses the InControl asset)

public void CheckInput()  
{
    float time = Time.unscaledTime;
    bool allow = InputManager.Devices[0].LeftStick.HasChanged;
    //Ensures that the cursor doesn't move too fast
    allow |= (time > _NextAction);
    if(InputManager.Devices[Input].Action1.WasPressed){
        Debug.LogWarning("Pressed!");
        SendSubmitEventToSelectedObject();
    }

    if ( !allow || _IsSelected ) return;

    //To then
    //... Use Unity's MoveHandler
    ExecuteEvents.Execute (EventSystem.current.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);

    //... Or Selecting the Object Manually
    ExecuteEvents.Execute<ISelectHandler>(Selected, new BaseEventData(EventSystem.current), ExecuteEvents.selectHandler);
}

Quick Tips:

You can limit input fields to Integer, Float, or String by going to the debug inspector and setting the Input Type.
You can also set delegate events from code by adding a Listener.

public Button MyButton = null; // assign in the editor

void Start()  
{
    MyButton.onClick.AddListener(() => { MyFunction(); });  
}

Note:
Listeners added in editor are called Persistent Listeners
Listeners added in script are called Non Persistent Listeners
As the name would suggest, any delegates added via scripting won't be reflected in the Editor

If you have any more tips, or want to more, follow me on Twitter!