259 lines
6.2 KiB
C#
259 lines
6.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
|
|
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler, IBeginDragHandler, IEndDragHandler, IPointerClickHandler
|
|
{
|
|
public float horizontal { get { return (_snapX) ? SnapFloat(_input.x, AxisOptions.Horizontal) : _input.x; } }
|
|
public float vertical { get { return (_snapY) ? SnapFloat(_input.y, AxisOptions.Vertical) : _input.y; } }
|
|
public Vector2 direction { get { return new Vector2(horizontal, vertical); } }
|
|
|
|
public float handleRange
|
|
{
|
|
get { return _handleRange; }
|
|
set { _handleRange = Mathf.Abs(value); }
|
|
}
|
|
|
|
public float invalidRange
|
|
{
|
|
get { return _invalidRange; }
|
|
set { _invalidRange = Mathf.Abs(value); }
|
|
}
|
|
|
|
public AxisOptions axisOptions { get { return _axisOptions; } set { _axisOptions = value; } }
|
|
public bool snapX { get { return _snapX; } set { _snapX = value; } }
|
|
public bool snapY { get { return _snapY; } set { _snapY = value; } }
|
|
|
|
[SerializeField] private float _handleRange = 1;
|
|
[SerializeField] private float _invalidRange = 0;
|
|
[SerializeField] private AxisOptions _axisOptions = AxisOptions.Both;
|
|
[SerializeField] private bool _snapX = false;
|
|
[SerializeField] private bool _snapY = false;
|
|
|
|
[SerializeField] protected RectTransform background = null;
|
|
[SerializeField] protected RectTransform handle = null;
|
|
[SerializeField] protected RectTransform indicator = null;
|
|
|
|
private RectTransform _baseRect = null;
|
|
|
|
private Canvas _canvas;
|
|
private Camera _camera;
|
|
|
|
private Vector2 _input = Vector2.zero;
|
|
|
|
private float _pointTime;
|
|
protected int _dragPointerId = int.MaxValue;
|
|
private float _dragPointTime;
|
|
private Vector2[] _dragPosition = new Vector2[2];
|
|
private bool _dragInvalid;
|
|
|
|
private void OnEnable()
|
|
{
|
|
#if UNITY_WEBGL
|
|
G.KPlatform.ApplicationFocusEvent += OnApplicationFocusEvent;
|
|
#endif
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
#if UNITY_WEBGL
|
|
G.KPlatform.ApplicationFocusEvent -= OnApplicationFocusEvent;
|
|
#endif
|
|
}
|
|
|
|
void OnApplicationFocusEvent(bool focus)
|
|
{
|
|
if (focus)
|
|
_dragPointerId = int.MaxValue;
|
|
}
|
|
|
|
protected virtual void Start()
|
|
{
|
|
handleRange = _handleRange;
|
|
invalidRange = _invalidRange;
|
|
_baseRect = GetComponent<RectTransform>();
|
|
_canvas = GetComponentInParent<Canvas>();
|
|
if (_canvas == null)
|
|
Debug.LogError("The Joystick is not placed inside a canvas");
|
|
|
|
//cam = null;
|
|
if (_canvas.renderMode == RenderMode.ScreenSpaceCamera)
|
|
_camera = _canvas.worldCamera;
|
|
|
|
Vector2 center = new Vector2(0.5f, 0.5f);
|
|
background.pivot = center;
|
|
handle.anchorMin = center;
|
|
handle.anchorMax = center;
|
|
handle.pivot = center;
|
|
handle.anchoredPosition = Vector2.zero;
|
|
}
|
|
|
|
public virtual void OnPointerDown(PointerEventData eventData)
|
|
{
|
|
_pointTime = Time.unscaledTime;
|
|
//OnDrag(eventData);
|
|
}
|
|
|
|
public virtual void OnPointerUp(PointerEventData eventData)
|
|
{
|
|
var magn = _input.magnitude;
|
|
|
|
_input = Vector2.zero;
|
|
handle.anchoredPosition = Vector2.zero;
|
|
|
|
indicator.gameObject.SetActive(false);
|
|
}
|
|
|
|
public void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
if (_dragPointerId != eventData.pointerId)
|
|
{
|
|
if (Time.unscaledTime - _pointTime < 0.36f)
|
|
{
|
|
OnShortTap();
|
|
}
|
|
}
|
|
//OnShortTap(eventData.position);
|
|
}
|
|
|
|
public virtual void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if (_dragPointerId == int.MaxValue)
|
|
{
|
|
_dragPointerId = eventData.pointerId;
|
|
_dragPointTime = Time.unscaledTime;
|
|
_dragInvalid = true;
|
|
}
|
|
}
|
|
|
|
public virtual void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
if (_dragPointerId == eventData.pointerId)
|
|
{
|
|
_dragPointerId = int.MaxValue;
|
|
|
|
if (_dragInvalid)
|
|
{
|
|
OnShortTap();
|
|
}
|
|
else
|
|
{
|
|
var iMagn = (eventData.position - eventData.pressPosition).sqrMagnitude;
|
|
var wMagn = (eventData.position - _dragPosition[0]).sqrMagnitude;
|
|
if ((iMagn > 900f && Time.unscaledTime - _dragPointTime < 0.3f) || wMagn > 450f)
|
|
{
|
|
OnArrowAction();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (_dragPointerId == eventData.pointerId)
|
|
{
|
|
_dragPosition[0] = _dragPosition[1];
|
|
_dragPosition[1] = eventData.position;
|
|
|
|
//Vector2 position = RectTransformUtility.WorldToScreenPoint(_camera, background.position);
|
|
Vector2 radius = background.sizeDelta / 2f;
|
|
|
|
_input = (eventData.position - eventData.pressPosition) / (radius * _canvas.scaleFactor);
|
|
|
|
FormatInput();
|
|
HandleInput(_input.magnitude, _input.normalized, radius, _camera);
|
|
handle.anchoredPosition = _input * radius * _handleRange;
|
|
}
|
|
}
|
|
|
|
protected virtual void HandleInput(float magnitude, Vector2 normalised, Vector2 radius, Camera cam)
|
|
{
|
|
if (magnitude > _invalidRange)
|
|
{
|
|
_dragInvalid = false;
|
|
|
|
if (magnitude > 1)
|
|
_input = normalised;
|
|
if (indicator)
|
|
{
|
|
indicator.gameObject.SetActive(true);
|
|
indicator.right = _input;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_input = Vector2.zero;
|
|
if (indicator)
|
|
{
|
|
indicator.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FormatInput()
|
|
{
|
|
if (_axisOptions == AxisOptions.Horizontal)
|
|
_input = new Vector2(_input.x, 0f);
|
|
else if (_axisOptions == AxisOptions.Vertical)
|
|
_input = new Vector2(0f, _input.y);
|
|
}
|
|
|
|
private float SnapFloat(float value, AxisOptions snapAxis)
|
|
{
|
|
if (value == 0)
|
|
return value;
|
|
|
|
if (_axisOptions == AxisOptions.Both)
|
|
{
|
|
float angle = Vector2.Angle(_input, Vector2.up);
|
|
if (snapAxis == AxisOptions.Horizontal)
|
|
{
|
|
if (angle < 22.5f || angle > 157.5f)
|
|
return 0;
|
|
else
|
|
return (value > 0) ? 1 : -1;
|
|
}
|
|
else if (snapAxis == AxisOptions.Vertical)
|
|
{
|
|
if (angle > 67.5f && angle < 112.5f)
|
|
return 0;
|
|
else
|
|
return (value > 0) ? 1 : -1;
|
|
}
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
if (value > 0)
|
|
return 1;
|
|
if (value < 0)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
|
|
{
|
|
Vector2 localPoint = Vector2.zero;
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(_baseRect, screenPosition, _camera, out localPoint))
|
|
{
|
|
Vector2 pivotOffset = _baseRect.pivot * _baseRect.sizeDelta;
|
|
return localPoint - (background.anchorMax * _baseRect.sizeDelta) + pivotOffset;
|
|
}
|
|
return Vector2.zero;
|
|
}
|
|
|
|
protected virtual void OnArrowAction()
|
|
{
|
|
}
|
|
|
|
protected virtual void OnShortTap()
|
|
{
|
|
}
|
|
|
|
protected virtual void OnLongTap()
|
|
{
|
|
}
|
|
|
|
}
|
|
|
|
public enum AxisOptions { Both, Horizontal, Vertical } |