/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Input.VirtualControls { using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// /// A virtual joystick that stays within the specified radius range. When the press is released the joystick knob will snap back to the starting position. /// public class VirtualJoystick : VirtualAxis, IDragHandler { [Tooltip("A reference to the joystick that moves with the press position.")] [SerializeField] protected RectTransform m_Joystick; [Tooltip("The maximum number of pixels that the joystick can move.")] [SerializeField] protected float m_Radius = 100; [Tooltip("The joystick will return a zero value when the radius is within the specified deadzone radius of the center.")] [SerializeField] protected float m_DeadzoneRadius = 5; private Transform m_CanvasScalarTransform; private Vector2 m_JoystickStartPosition; protected override void Awake() { if (m_Joystick == null) { Debug.LogError("Error: A joystick transform must be specified."); enabled = false; return; } m_CanvasScalarTransform = GetComponentInParent().transform; m_JoystickStartPosition = m_Joystick.anchoredPosition; base.Awake(); } /// /// Callback when a pointer has dragged the button. /// /// The pointer data. public void OnDrag(PointerEventData data) { var canvasScale = m_CanvasScalarTransform == null ? Vector3.one : m_CanvasScalarTransform.localScale; m_DeltaPosition.x += data.delta.x / canvasScale.x; m_DeltaPosition.y += data.delta.y / canvasScale.y; m_DeltaPosition.x = Mathf.Clamp(m_DeltaPosition.x, -m_Radius, m_Radius); m_DeltaPosition.y = Mathf.Clamp(m_DeltaPosition.y, -m_Radius, m_Radius); if (m_DeltaPosition.magnitude > m_Radius) { m_DeltaPosition = m_DeltaPosition.normalized * m_Radius; } // Update the joystick position. m_Joystick.anchoredPosition = m_JoystickStartPosition + m_DeltaPosition; } /// /// Callback when a finger has released the button. /// /// The pointer data. public override void OnPointerUp(PointerEventData data) { if (!m_Pressed) { return; } base.OnPointerUp(data); m_Joystick.anchoredPosition = m_JoystickStartPosition; } /// /// Returns the value of the axis. /// /// The name of the axis. /// The value of the axis. public override float GetAxis(string name) { if (!m_Pressed) { return 0; } if (name == m_HorizontalInputName) { if (Mathf.Abs(m_DeltaPosition.x) > m_DeadzoneRadius) { return m_DeltaPosition.x / m_Radius; } } else { if (Mathf.Abs(m_DeltaPosition.y) > m_DeadzoneRadius) { return m_DeltaPosition.y / m_Radius; } } return 0; } } }