FREE TRIAL

|

☀
☾

Clicking UIBlocks

  1. Create a Component that calls the following in Update():
// Pass mouse events to Nova's Interactions API.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Interaction.Point(new Interaction.Update(ray), Input.GetMouseButton(0));
  1. Add an Interactable to the same Gamebject as the UIBlock you want to click.

  2. Create a Component that will subscribe to and handle click events.

// Assign to the Interactable added in step (2)
public Interactable Button = null;

private void Start()
{
    // Listen for OnClick events and log "Clicked!" to the console whenever one occurs.
    Button.UIBlock.AddGestureHandler<Gesture.OnClick>((evt) => Debug.Log("Clicked!"));
}
  1. Play

Input Overview

Nova's input system revolves around three primary concepts:

Concept Description
Interactions The entry-point of the input system. A user calls into the Interaction API per input-device-update (e.g. mouse move, mouse click, etc.), to route the raw input information to some UI content.
GestureRecognizers Interactable and Scroller components in a connected UIBlock hierarchy responsible for converting per-frame Interaction.Updates to a Nova-supported Gesture.
Gestures Events generated based on patterns of one or more consecutive Interaction.Updates.

The following diagram illustrates the input pipeline, breaking it down into four stages (from left to right):

  1. A user-written component, e.g. InputManager, calls into Nova's Interaction API.
  2. Nova's Interaction API determines which GestureRecognizer (i.e. Interactable or Scroller) in the scene will receive the interaction update.
  3. The GestureRecognizer receiving the interaction update converts the event into one of the Nova-provided Gestures, based on its previous gesture state and the new interaction update, and fires the gesture event on its attached UIBlock. The gesture event propogates through the UIBlock event system.
  4. A user-written component, e.g. GestureHandler, receives the gesture event and reacts accordingly.

Input Diagram

Sending Interactions

The Interaction.Update type represents the pointer state of an input control performing a gesture on a given frame. Some examples of what's meant by pointer and control:

Pointer Control
Mouse Cursor Left Mouse Button
Mouse Cursor Scroll Wheel
Touch Point Index Finger
Left XR Device Ray Left XR Device Trigger
Right XR Device Ray Right XR Device Joystick

Every Interaction.Update contains:

Field Description
ControlID A unique identifier for the control attached to the input pointer.
Ray The current location and direction (in world space) of the input pointer.
UserData Any additional data the caller wishes to pass along to the gesture event handler listening for the interaction update.

The user provides Interaction.Updates to the Interaction API, which will internally:

  1. Perform a hit-test against all active UIBlocks in the scene.
  2. Route the Interaction.Update to the appropriate GestureRecognizer (i.e. Interactable or Scroller) attached to a hit UIBlock.
using Nova;
using UnityEngine;

/// <summary>
/// A sample component responsible for sending mouse events through the Interaction API to the UI content.
/// </summary>
public class SimpleInputManager : MonoBehaviour
{
    private const uint LeftMouseButtonID = 0;
    
    // In Unity's legacy input system, '0' is the button ID for the left mouse button.
    private const int LeftMouseButton = 0;

    public void Update()
    {
        if (!Input.mousePresent)
        {
            // No mouse present, exit early.
            return;
        }

        /*** Create Interaction.Update from mouse event ***/

        // Convert the mouse position to a world-space ray.
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        // Create a new Interaction.Update from the ray, and give it a control ID.
        Interaction.Update update = new Interaction.Update(ray, controlID: LeftMouseButtonID);

        // Is the left mouse button pressed?
        bool mousePressed = Input.GetMouseButton(LeftMouseButton);

        /*** Pass along to Nova's interaction system ***/

        // Call Nova's Interaction.Point method with the interaction update and button state.
        Interaction.Point(update, mousePressed);
    }
}
Note

Nova uses UIBlock.CalculatedSize to determine the set of UIBlocks intersecting with a given Ray or Sphere and doesn't depend on nor make use of any Unity Physics APIs, including colliders.

Interactable & Scroller

Nova provides two components which process and handle Interaction.Updates passed into the Interaction API. Once the component receives an Interaction.Update, it will fire a corresponding gesture event.

Icon Component Description Captures Fires Events Notes
Interactable Interactable Processes Interaction.Point data and fires pointer-based events such as hover, click, drag (separate from scrolling), etc.
  • Interaction.Point
  • Interaction.Cancel
  • Navigation.Move
  • Navigation.Select
  • Navigation.Deselect
  • Gesture.OnClick
  • Gesture.OnDrag
  • Gesture.OnMove
  • Gesture.OnHover
  • Gesture.OnUnhover
  • Gesture.OnPress
  • Gesture.OnRelease
  • Gesture.OnCancel
  • Navigate.OnDirection
  • Navigate.OnMoveTo
  • Navigate.OnMoveFrom
  • Navigate.OnSelect
  • Navigate.OnDeselect
Doesn't fire Gesture.OnScroll events
Scroller Scroller Scrolls the attached UIBlock's content along its AutoLayout.Axis with an optional iOS-like inertia and bounce effect. Also fires most pointer-based events.
  • Interaction.Point
  • Interaction.Scroll
  • Interaction.Cancel
  • Navigation.Move
  • Navigation.Select
  • Navigation.Deselect
  • Gesture.OnClick
  • Gesture.OnScroll
  • Gesture.OnMove
  • Gesture.OnHover
  • Gesture.OnUnhover
  • Gesture.OnPress
  • Gesture.OnRelease
  • Gesture.OnCancel
  • Navigate.OnDirection
  • Navigate.OnMoveTo
  • Navigate.OnMoveFrom
  • Navigate.OnSelect
  • Navigate.OnDeselect
Doesn't fire Gesture.OnDrag events

Only one Interactable or Scroller component will receive a given Interaction.Update. This means if a Ray or Sphere intersects with multiple UIBlocks, only one of them will fire the corresponding gesture event. For Gesture.OnHover and Gesture.OnPress events, the event will always be fired from the top-most-rendered UIBlock with an Interactable or Scroller component. Gesture.OnDrag and Gesture.OnScroll events may fire from UIBlocks behind other Interactables or Scrollers, depending on the configured drag thresholds and draggable axes.

Handling Gestures

With a system calling into the Interaction API in place and one or more Interactable or Scroller components in the scene prepared to receive interaction updates, the UI is ready to listen for and react to various gesture events.

All gesture events include a copy of the particular event data in the form of different gesture event struct types. All gesture event structs implement the IGestureEvent interface, allowing all Nova-supported gestures to provide:

Property Description
Interaction The Interaction.Update responsible for triggering the event. Either passed into or created by an Interaction method.
Receiver The UIBlock attached to the same Gamebject as the GestureRecognizer component capturing the interaction update and generating the gesture event.
Target A UIBlock ancestor of the Receiver (or the Receiver itself) holding information pertinent to the event handler.

See Event System to learn more about hierarchical event propogation and handling.

using Nova;
using UnityEngine;

/// <summary>
/// A sample component responsible for subscribing to and handling hover, unhover, and click events.
/// </summary>
public class SimpleButtonHandler : MonoBehaviour
{
    // Serialize and assign in Editor
    public Interactable Button = null;
    public Color DefaultColor = Color.grey;
    public Color HoverColor = Color.white;

    public void OnEnable()
    {
        /*** Subscribe to desired gesture events ***/
        Button.UIBlock.AddGestureHandler<Gesture.OnHover>(HandleHoverEvent);
        Button.UIBlock.AddGestureHandler<Gesture.OnUnhover>(HandleUnhoverEvent);
        Button.UIBlock.AddGestureHandler<Gesture.OnClick>(HandleClickEvent);
    }

    private void HandleHoverEvent(Gesture.OnHover evt)
    {
        // Change the color of the UIBlock under the pointer.
        Button.UIBlock.Color = HoverColor;
    }

    private void HandleUnhoverEvent(Gesture.OnUnhover evt)
    {
        // Change the color of the UIBlock exited by the pointer.
        Button.UIBlock.Color = DefaultColor;
    }

    private void HandleClickEvent(Gesture.OnClick evt)
    {
        // Log a message each time the Button is clicked.
        Debug.Log("Clicked!");
    }

    public void OnDisable()
    {
        /*** Unsubscribe from gesture events previously subscribed to in OnEnable ***/
        Button.UIBlock.RemoveGestureHandler<Gesture.OnHover>(HandleHoverEvent);
        Button.UIBlock.RemoveGestureHandler<Gesture.OnUnhover>(HandleUnhoverEvent);
        Button.UIBlock.RemoveGestureHandler<Gesture.OnClick>(HandleClickEvent);
    }
}
☀
☾
In This Article
Legal EmailContact Github
Copyright © 2022 Supernova Technologies, LLC