UX Framework

The One Handed Navigator

Interaction Pattern

Overview

Implementation of full locomotion and rotation using a single thumbstick.


Implementation Specification

The use of a single thumbstick to control locomotion and rotation and teleportation. Implementation is via a mode-switching mechanism.

A designated button (or trigger) toggles between locomotion and rotation and teleportation modes.

  1. The default thumbstick behaviour is locomotion mode, allowing the user to move forward, backward, left, or right.

  2. The first button press switches the thumbstick to rotation mode, enabling the user to rotate their view left or right.

  3. The second button press switches the thumbstick to teleportation mode, allowing the user to point and teleport to a new location.

  4. The third button press switches the thumbstick back to locomotion mode, and the cycle continues.

The One Handed Navigator mechanic


Reference Pattern

// Pseudo-code for The One Handed Navigator Mechanic Implementation
// Tone: Technical Implementation Guide

Enum NavigationMode {
    Locomotion,
    Rotation,
    Teleportation
}

Class OneHandedNavigatorManager : MonoBehaviour {

    // Configuration
    NavigationMode currentMode = NavigationMode.Locomotion;
    Float movementSpeed = 3.0f;
    Float snapRotationAngle = 45.0f;
    Boolean hasRotated = false;
    
    // User Interface & System References
    TMP_Text modeIndicatorUI;
    AudioSource feedbackAudio;
    TeleportTargeter teleportSystem;
    Transform cameraRig;

    // Main Execution Loop
    Function Update() {
        ProcessModeToggle();
        ProcessThumbstickInput();
    }

    // Phase 1: Mode Switching Logic
    Function ProcessModeToggle() {
        // Intercept designated toggle button event
        If (Input.GetButtonDown("ModeToggle")) {
            Switch (currentMode) {
                Case NavigationMode.Locomotion:
                    currentMode = NavigationMode.Rotation;
                    Break;
                Case NavigationMode.Rotation:
                    currentMode = NavigationMode.Teleportation;
                    teleportSystem.ActivateTargeter();
                    Break;
                Case NavigationMode.Teleportation:
                    currentMode = NavigationMode.Locomotion;
                    teleportSystem.DeactivateTargeter();
                    Break;
            }
            
            ExecuteMultimodalFeedback();
        }
    }

    // Phase 2: Input Processing Logic
    Function ProcessThumbstickInput() {
        // Abstract input to mirror dynamically to the active hand
        Vector2 thumbstickInput = GetActiveControllerThumbstick();

        Switch (currentMode) {
            Case NavigationMode.Locomotion:
                ExecuteLocomotion(thumbstickInput);
                Break;
            Case NavigationMode.Rotation:
                ExecuteRotation(thumbstickInput.x);
                Break;
            Case NavigationMode.Teleportation:
                ExecuteTeleportation(thumbstickInput);
                Break;
        }
    }

    // Execution: Locomotion State
    Function ExecuteLocomotion(Vector2 input) {
        // Apply continuous translation based on X and Y hardware axes
        Vector3 moveDirection = new Vector3(input.x, 0, input.y);
        cameraRig.Translate(moveDirection * movementSpeed * Time.deltaTime);
    }

    // Execution: Rotation State
    Function ExecuteRotation(Float xAxisInput) {
        // Apply discrete snap rotation upon thumbstick deflection threshold
        If (xAxisInput > 0.5f AND !hasRotated) {
            cameraRig.Rotate(0, snapRotationAngle, 0);
            hasRotated = true;
        } Else If (xAxisInput < -0.5f AND !hasRotated) {
            cameraRig.Rotate(0, -snapRotationAngle, 0);
            hasRotated = true;
        } Else If (Mathf.Abs(xAxisInput) < 0.1f) {
            hasRotated = false; // Reset threshold buffer
        }
    }

    // Execution: Teleportation State
    Function ExecuteTeleportation(Vector2 input) {
        // Manage targeter arc and execute on thumbstick forward threshold
        teleportSystem.UpdateArcPosition();
        
        If (input.y > 0.5f AND teleportSystem.HasValidTarget()) {
            teleportSystem.ExecuteTeleport();
        }
    }

    // System Feedback
    Function ExecuteMultimodalFeedback() {
        modeIndicatorUI.SetText(currentMode.ToString());
        feedbackAudio.PlayOneShot("ModeSwitchBeep");
        PlayHapticPulse(0.5f);
    }
}

Dependencies

Input Mirroring

Previous
The Magic Slingshot