Files
beyond/Assets/ThirdParty/Joystick Pack/Scripts/Base/Joystick.cs
2024-11-20 15:21:28 +01:00

457 lines
14 KiB
C#

using System;
using UnityEngine;
using UnityEngine.EventSystems;
#if USE_NEW_INPUT
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.InputSystem.Layouts;
#endif
using Beyond;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;
using ButtonHandler = Beyond.ButtonHandler;
#if USE_NEW_INPUT
public class Joystick : OnScreenControl, IPointerDownHandler, IDragHandler, IPointerUpHandler
#else
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
#endif
{
#if USE_NEW_INPUT
[InputControl(layout = "Vector2")]
[SerializeField]
protected string m_ControlPath;
#endif
[SerializeField]
protected ControlType m_ControlType = ControlType.Joystick;
public AnimationCurve inputModifier = AnimationCurve.Linear(-1f, -1f, 1f, 1f);
public ButtonHandler action;
private const float activeActionValue = 0.99f * 2f;
private const float actionStartLerpValue = 0.9f * 2f;
private CanvasGroup actionCanvasGroup;
private CanvasGroup activeActionCanvasGroup;
private Vector2 inputProcessed = Vector2.zero;
private Vector2 inputProcessedByModifier = Vector2.zero;
public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input
protected CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
protected CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input
#if USE_NEW_INPUT
protected override string controlPathInternal
{
get => m_ControlPath;
set => m_ControlPath = value;
}
#endif
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); } }
void CreateVirtualAxes()
{
// set axes to use
// create new axes based on axes to use
if (CrossPlatformInputManager.AxisExists(horizontalAxisName))
{
m_HorizontalVirtualAxis = CrossPlatformInputManager.VirtualAxisReference(horizontalAxisName);
}
else
{
m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
}
if (CrossPlatformInputManager.AxisExists(verticalAxisName))
{
m_VerticalVirtualAxis = CrossPlatformInputManager.VirtualAxisReference(verticalAxisName);
}
else
{
m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
}
}
public float HandleRange
{
get { return handleRange; }
set { handleRange = Mathf.Abs(value); }
}
public float DeadZone
{
get { return deadZone; }
set { deadZone = 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 inputAmp = 1;
[SerializeField] private float deadZone = 0;
[SerializeField] private AxisOptions axisOptions = AxisOptions.Both;
[SerializeField] private float m_clampMin = 0.2f;
[SerializeField] private bool snapX = false;
[SerializeField] private bool snapY = false;
[SerializeField] private bool stepXY = true;
[SerializeField] private float stepSize = 0.65f;
[SerializeField] protected RectTransform background = null;
[SerializeField] private RectTransform handle = null;
private RectTransform baseRect = null;
private Canvas canvas;
private Camera cam;
private Vector2 input = Vector2.zero;
private bool m_Dragging;
private Vector2 delta;
private Vector2 prevInput;
protected virtual void Start()
{
HandleRange = handleRange;
DeadZone = deadZone;
baseRect = GetComponent<RectTransform>();
canvas = GetComponentInParent<Canvas>();
if (canvas == null)
Debug.LogError("The Joystick is not placed inside a canvas");
Vector2 center = new Vector2(0.5f, 0.5f);
background.pivot = center;
handle.anchorMin = center;
handle.anchorMax = center;
handle.pivot = center;
handle.anchoredPosition = Vector2.zero;
if (action)
{
actionCanvasGroup = action.GetComponent<CanvasGroup>();
if (actionCanvasGroup)
{
actionCanvasGroup.alpha = 0f;
}
if (action.transform.childCount > 0)
{
activeActionCanvasGroup = action.transform.GetChild(0).GetComponent<CanvasGroup>();
if (activeActionCanvasGroup)
{
activeActionCanvasGroup.alpha = 0f;
}
}
}
CreateVirtualAxes();
}
protected virtual void Update()
{
if (!m_Dragging)
{
return;
}
if (m_ControlType == ControlType.Touchpad)
{
delta = input;
delta.x -= prevInput.x;
delta.y -= prevInput.y;
prevInput = input;
inputProcessed.x = Horizontal;
inputProcessed.y = Vertical;
ClampValue();
if (delta.x == 0f)
{
inputProcessed.x = 0f;
}
if (delta.y == 0f)
{
inputProcessed.y = 0f;
}
#if USE_NEW_INPUT
SendValueToControl(inputProcessed);
#endif
}
}
private void ClampValue()
{
if (inputProcessed.x > 0)
{
inputProcessed.x = Mathf.Max(inputProcessed.x, m_clampMin);
}
if (inputProcessed.x < 0)
{
inputProcessed.x = Mathf.Min(inputProcessed.x, -m_clampMin);
}
if (inputProcessed.y > 0)
{
inputProcessed.y = Mathf.Max(inputProcessed.y, m_clampMin);
}
if (inputProcessed.y < 0)
{
inputProcessed.y = Mathf.Min(inputProcessed.y, -m_clampMin);
}
if (stepXY)
{
float mag = inputProcessed.magnitude;
var absM = Mathf.Abs(mag);
var sig = Mathf.Sign(mag);
if (absM > 0f)
{
inputProcessed /= absM;
if (absM < stepSize)
{
inputProcessed *= 0.5f;
}
}
}
/*
if (stepX)
{
if (inputProcessed.x > 0)
{
if (inputProcessed.x < stepSize)
{
inputProcessed.x = 0.5f;
}
else
{
inputProcessed.x = 1f;
}
}
else if (inputProcessed.x < 0)
{
if (inputProcessed.x > -stepSize)
{
inputProcessed.x = -0.5f;
}
else
{
inputProcessed.x = -1f;
}
}
}
if (stepY)
{
if (inputProcessed.y > 0)
{
if (inputProcessed.y < stepSize)
{
inputProcessed.y = 0.5f;
}
else
{
inputProcessed.y = 1f;
}
}
else if (inputProcessed.y < 0)
{
if (inputProcessed.y > -stepSize)
{
inputProcessed.y = -0.5f;
}
else
{
inputProcessed.y = -1f;
}
}
}
*/
}
public virtual void OnPointerDown(PointerEventData eventData)
{
m_Dragging = true;
OnDrag(eventData);
}
void UpdateVirtualAxes(Vector2 value)
{
//Debug.Log("Virtual axis: "+value);
m_HorizontalVirtualAxis.Update(value.x);
m_VerticalVirtualAxis.Update(value.y);
}
public void OnDrag(PointerEventData eventData)
{
cam = null;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
cam = canvas.worldCamera;
Vector2 position = RectTransformUtility.WorldToScreenPoint(cam, background.position);
Vector2 radius = background.sizeDelta / 2;
input = (eventData.position - position) / (radius * canvas.scaleFactor);
FormatInput();
HandleInput(input.magnitude, input.normalized, radius, cam);
handle.anchoredPosition = input * radius * handleRange;
if (m_ControlType == ControlType.Joystick)
{
inputProcessed.x = Horizontal;
inputProcessed.y = Vertical;
//ClampValue();
if (actionCanvasGroup)
{
var inputProcessedLength = inputProcessed.magnitude;
actionCanvasGroup.alpha = Mathf.InverseLerp(actionStartLerpValue, 1f, Mathf.Clamp01(inputProcessedLength));
if (activeActionCanvasGroup && inputProcessedLength > activeActionValue)
{
activeActionCanvasGroup.alpha = 1f;
}
else if (activeActionCanvasGroup)
{
activeActionCanvasGroup.alpha = 0f;
}
}
ClampValue();
inputProcessedByModifier.x = inputProcessed.x * inputAmp;
inputProcessedByModifier.y = inputProcessed.y * inputAmp;
//inputProcessedByModifier.x = inputModifier.Evaluate(inputProcessed.x) * inputAmp;
//inputProcessedByModifier.y = inputModifier.Evaluate(inputProcessed.y) * inputAmp;
#if USE_NEW_INPUT
SendValueToControl(inputProcessedByModifier);
#endif
UpdateVirtualAxes(inputProcessedByModifier);
}
}
protected virtual void HandleInput(float magnitude, Vector2 normalised, Vector2 radius, Camera cam)
{
if (magnitude > deadZone)
{
//if (magnitude > 1)
// input = normalised;
}
else
input = Vector2.zero;
}
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;
}
public virtual void OnPointerUp(PointerEventData eventData)
{
//Debug.Log("input " + input);
//Debug.Log("input.magnitude " + input.magnitude);
if (input.magnitude >= activeActionValue)
{
AdditionalAction();
StartCoroutine(DelayPointerUp());
return;
}
PointerUp();
}
private IEnumerator DelayPointerUp()
{
yield return new WaitForSeconds(0.1f);
PointerUp();
}
protected void OnDisable()
{
PointerUp();
}
protected void PointerUp()
{
if (actionCanvasGroup)
{
actionCanvasGroup.alpha = 0f;
}
if (activeActionCanvasGroup)
{
activeActionCanvasGroup.alpha = 0f;
}
m_Dragging = false;
input = Vector2.zero;
delta = Vector2.zero;
prevInput = Vector2.zero;
handle.anchoredPosition = Vector2.zero;
UpdateVirtualAxes(input);
#if USE_NEW_INPUT
SendValueToControl(input);
#endif
}
private void AdditionalAction()
{
if (action)
{
action.Click();
}
}
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
{
Vector2 localPoint = Vector2.zero;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, cam, out localPoint))
{
Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
return localPoint - (background.anchorMax * baseRect.sizeDelta) + pivotOffset;
}
return Vector2.zero;
}
}
public enum AxisOptions { Both, Horizontal, Vertical }
public enum ControlType { Joystick, Touchpad }