232 lines
7.3 KiB
C#
232 lines
7.3 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.EventSystems;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
|
|||
|
|
namespace Watermelon
|
|||
|
|
{
|
|||
|
|
[RequireComponent(typeof(Animator))]
|
|||
|
|
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler, IControlBehavior
|
|||
|
|
{
|
|||
|
|
public static Joystick Instance { get; private set; }
|
|||
|
|
|
|||
|
|
[Header("Joystick")]
|
|||
|
|
[SerializeField] protected Image backgroundImage;
|
|||
|
|
[SerializeField] protected Image handleImage;
|
|||
|
|
|
|||
|
|
[Space]
|
|||
|
|
[SerializeField] Color backgroundActiveColor = Color.white;
|
|||
|
|
[SerializeField] Color backgroundDisableColor = Color.white;
|
|||
|
|
|
|||
|
|
[SerializeField] Color handleActiveColor = Color.white;
|
|||
|
|
[SerializeField] Color handleDisableColor = Color.white;
|
|||
|
|
|
|||
|
|
[Space]
|
|||
|
|
[SerializeField] float handleRange = 1;
|
|||
|
|
[SerializeField] float deadZone = 0;
|
|||
|
|
|
|||
|
|
[Header("Tutorial")]
|
|||
|
|
[SerializeField] bool useTutorial;
|
|||
|
|
[SerializeField] GameObject pointerGameObject;
|
|||
|
|
|
|||
|
|
private RectTransform baseRectTransform;
|
|||
|
|
private RectTransform backgroundRectTransform;
|
|||
|
|
private RectTransform handleRectTransform;
|
|||
|
|
|
|||
|
|
private bool isActive;
|
|||
|
|
public bool IsMovementInputNonZero => isActive;
|
|||
|
|
|
|||
|
|
private bool canDrag;
|
|||
|
|
|
|||
|
|
private Canvas canvas;
|
|||
|
|
private Camera canvasCamera;
|
|||
|
|
|
|||
|
|
protected Vector2 input = Vector2.zero;
|
|||
|
|
|
|||
|
|
public Vector3 Input => input;
|
|||
|
|
public Vector3 MovementInput => new Vector3(input.x, 0, input.y);
|
|||
|
|
|
|||
|
|
private Vector2 defaultAnchoredPosition;
|
|||
|
|
|
|||
|
|
public bool IsLookInputNonZero => false;
|
|||
|
|
public Vector3 LookInput => Vector3.zero;
|
|||
|
|
|
|||
|
|
private Animator joystickAnimator;
|
|||
|
|
private bool isTutorialDisplayed;
|
|||
|
|
private bool hideVisualsActive;
|
|||
|
|
|
|||
|
|
// Events
|
|||
|
|
public event SimpleCallback OnMovementInputActivated;
|
|||
|
|
|
|||
|
|
public void Init(Canvas canvas)
|
|||
|
|
{
|
|||
|
|
this.canvas = canvas;
|
|||
|
|
|
|||
|
|
Instance = this;
|
|||
|
|
|
|||
|
|
joystickAnimator = GetComponent<Animator>();
|
|||
|
|
|
|||
|
|
baseRectTransform = GetComponent<RectTransform>();
|
|||
|
|
backgroundRectTransform = backgroundImage.rectTransform;
|
|||
|
|
handleRectTransform = handleImage.rectTransform;
|
|||
|
|
|
|||
|
|
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
|
|||
|
|
canvasCamera = canvas.worldCamera;
|
|||
|
|
|
|||
|
|
Vector2 center = new Vector2(0.5f, 0.5f);
|
|||
|
|
backgroundRectTransform.pivot = center;
|
|||
|
|
handleRectTransform.anchorMin = center;
|
|||
|
|
handleRectTransform.anchorMax = center;
|
|||
|
|
handleRectTransform.pivot = center;
|
|||
|
|
handleRectTransform.anchoredPosition = Vector2.zero;
|
|||
|
|
|
|||
|
|
isActive = false;
|
|||
|
|
|
|||
|
|
if(useTutorial)
|
|||
|
|
{
|
|||
|
|
joystickAnimator.enabled = true;
|
|||
|
|
isTutorialDisplayed = true;
|
|||
|
|
|
|||
|
|
pointerGameObject.SetActive(true);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
joystickAnimator.enabled = false;
|
|||
|
|
isTutorialDisplayed = false;
|
|||
|
|
|
|||
|
|
pointerGameObject.SetActive(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
backgroundImage.color = backgroundDisableColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
handleImage.color = handleDisableColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
|
|||
|
|
defaultAnchoredPosition = backgroundRectTransform.anchoredPosition;
|
|||
|
|
|
|||
|
|
if (Control.InputType == InputType.UIJoystick)
|
|||
|
|
{
|
|||
|
|
Control.SetControl(this);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
gameObject.SetActive(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnPointerDown(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
canDrag = !WorldSpaceRaycaster.Raycast(eventData);
|
|||
|
|
|
|||
|
|
if (!canDrag) return;
|
|||
|
|
|
|||
|
|
if (!isTutorialDisplayed)
|
|||
|
|
{
|
|||
|
|
isTutorialDisplayed = true;
|
|||
|
|
|
|||
|
|
joystickAnimator.enabled = false;
|
|||
|
|
pointerGameObject.SetActive(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
backgroundRectTransform.anchoredPosition = ScreenPointToAnchoredPosition(eventData.position);
|
|||
|
|
|
|||
|
|
backgroundImage.color = backgroundActiveColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
handleImage.color = handleActiveColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
|
|||
|
|
isActive = true;
|
|||
|
|
|
|||
|
|
OnMovementInputActivated?.Invoke();
|
|||
|
|
|
|||
|
|
OnDrag(eventData);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
if (!isActive || !canDrag)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
Vector2 position = RectTransformUtility.WorldToScreenPoint(canvasCamera, backgroundRectTransform.position);
|
|||
|
|
Vector2 radius = backgroundRectTransform.sizeDelta / 2;
|
|||
|
|
input = (eventData.position - position) / (radius * canvas.scaleFactor);
|
|||
|
|
HandleInput(input.magnitude, input.normalized, radius, canvasCamera);
|
|||
|
|
handleRectTransform.anchoredPosition = input * radius * handleRange;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected void HandleInput(float magnitude, Vector2 normalised, Vector2 radius, Camera cam)
|
|||
|
|
{
|
|||
|
|
if (magnitude > deadZone)
|
|||
|
|
{
|
|||
|
|
if (magnitude > 1)
|
|||
|
|
input = normalised;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
input = Vector2.zero;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnPointerUp(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
WorldSpaceRaycaster.OnPointerUp(eventData);
|
|||
|
|
|
|||
|
|
if (!isActive)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
isActive = false;
|
|||
|
|
|
|||
|
|
ResetControl();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ResetControl()
|
|||
|
|
{
|
|||
|
|
isActive = false;
|
|||
|
|
|
|||
|
|
backgroundImage.color = backgroundDisableColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
handleImage.color = handleDisableColor.SetAlpha(hideVisualsActive ? 0f : backgroundDisableColor.a);
|
|||
|
|
|
|||
|
|
backgroundRectTransform.anchoredPosition = defaultAnchoredPosition;
|
|||
|
|
|
|||
|
|
input = Vector2.zero;
|
|||
|
|
handleRectTransform.anchoredPosition = Vector2.zero;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
|
|||
|
|
{
|
|||
|
|
Vector2 localPoint = Vector2.zero;
|
|||
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRectTransform, screenPosition, canvasCamera, out localPoint))
|
|||
|
|
{
|
|||
|
|
Vector2 pivotOffset = baseRectTransform.pivot * baseRectTransform.sizeDelta;
|
|||
|
|
return localPoint - (backgroundRectTransform.anchorMax * baseRectTransform.sizeDelta) + pivotOffset;
|
|||
|
|
}
|
|||
|
|
return Vector2.zero;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void EnableMovementControl()
|
|||
|
|
{
|
|||
|
|
gameObject.SetActive(true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void DisableMovementControl()
|
|||
|
|
{
|
|||
|
|
gameObject.SetActive(false);
|
|||
|
|
isActive = false;
|
|||
|
|
|
|||
|
|
ResetControl();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void HideVisuals()
|
|||
|
|
{
|
|||
|
|
hideVisualsActive = true;
|
|||
|
|
|
|||
|
|
backgroundImage.color = backgroundImage.color.SetAlpha(0f);
|
|||
|
|
handleImage.color = backgroundImage.color.SetAlpha(0f);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ShowVisuals()
|
|||
|
|
{
|
|||
|
|
hideVisualsActive = false;
|
|||
|
|
|
|||
|
|
backgroundImage.color = backgroundImage.color.SetAlpha(1f);
|
|||
|
|
handleImage.color = backgroundImage.color.SetAlpha(1f);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public delegate void OnJoystickTouchedCallback();
|
|||
|
|
}
|
|||
|
|
}
|