RoguelikeKit/Assets/Common/Scripts/UI/JoystickBehavior.cs

158 lines
4.5 KiB
C#

using OctoberStudio.Extensions;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace OctoberStudio.UI
{
public class JoystickBehavior : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
public static JoystickBehavior Instance { get; private set; }
[SerializeField] Canvas canvas;
[SerializeField] CanvasGroup canvasGroup;
[Header("Joystick")]
[SerializeField] Image backgroundImage;
[SerializeField] Image handleImage;
[Space]
[SerializeField] float handleRange = 1;
[SerializeField] float deadZone = 0;
private RectTransform baseRectTransform;
private RectTransform backgroundRectTransform;
private RectTransform handleRectTransform;
private bool isBeingUsed;
public bool IsBeingUsed => isBeingUsed;
private Camera canvasCamera;
private Vector2 value = Vector2.zero;
public Vector2 Value => value;
private Vector2 defaultAnchoredPosition;
public event UnityAction OnBeingUsed;
public bool IsEnabled { get; private set; }
private void Awake()
{
Instance = this;
baseRectTransform = GetComponent<RectTransform>();
backgroundRectTransform = backgroundImage.rectTransform;
handleRectTransform = handleImage.rectTransform;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
canvasCamera = canvas.worldCamera;
var center = new Vector2(0.5f, 0.5f);
backgroundRectTransform.pivot = center;
handleRectTransform.anchorMin = center;
handleRectTransform.anchorMax = center;
handleRectTransform.pivot = center;
handleRectTransform.anchoredPosition = Vector2.zero;
isBeingUsed = false;
defaultAnchoredPosition = backgroundRectTransform.anchoredPosition;
GameController.InputManager.RegisterJoystick(this);
}
public void OnPointerDown(PointerEventData eventData)
{
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRectTransform, eventData.position, canvasCamera, out var localPoint))
{
var pivotOffset = baseRectTransform.pivot * baseRectTransform.sizeDelta;
backgroundRectTransform.anchoredPosition = localPoint - (backgroundRectTransform.anchorMax * baseRectTransform.sizeDelta) + pivotOffset;
} else
{
backgroundRectTransform.anchoredPosition = Vector2.zero;
}
isBeingUsed = true;
OnBeingUsed?.Invoke();
OnDrag(eventData);
}
public void OnPointerUp(PointerEventData eventData)
{
if (!isBeingUsed) return;
isBeingUsed = false;
ResetJoystick();
}
public void OnDrag(PointerEventData eventData)
{
if (!isBeingUsed) return;
var position = RectTransformUtility.WorldToScreenPoint(canvasCamera, backgroundRectTransform.position);
var radius = backgroundRectTransform.sizeDelta / 2;
value = (eventData.position - position) / (radius * canvas.scaleFactor);
if (value.magnitude > deadZone)
{
if (value.magnitude > 1) value = value.normalized;
}
else
{
value = Vector2.zero;
}
handleRectTransform.anchoredPosition = value * radius * handleRange;
}
public void ResetJoystick()
{
isBeingUsed = false;
backgroundRectTransform.anchoredPosition = defaultAnchoredPosition;
value = Vector2.zero;
handleRectTransform.anchoredPosition = Vector2.zero;
}
public void Enable()
{
IsEnabled = true;
canvasGroup.alpha = 1;
}
public void Disable()
{
IsEnabled = false;
canvasGroup.alpha = 0;
isBeingUsed = false;
ResetJoystick();
}
private void OnDestroy()
{
GameController.InputManager.RemoveJoystick();
}
public void Hide()
{
backgroundImage.color = backgroundImage.color.SetAlpha(0f);
handleImage.color = backgroundImage.color.SetAlpha(0f);
}
public void Show()
{
backgroundImage.SetAlpha(1f);
handleImage.SetAlpha(1f);
}
}
}