LunarInfantry/Assets/Bremsengine/Rect Transform Click Event/RenderTextureCursorHandler.cs
2026-01-02 01:31:54 -08:00

170 lines
No EOL
6.4 KiB
C#

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
namespace Bremsengine
{
public enum PointerButton
{
Left,
Right,
Middle
}
public class RenderTextureCursorHandler : MonoBehaviour, IPointerDownHandler, IPointerMoveHandler, IPointerExitHandler, IPointerEnterHandler, IPointerUpHandler
{
[SerializeField] RectTransform renderTexture;
Camera renderCamera;
static Transform controllerReference;
public delegate void OnClick(Vector2 worldPosition, PointerButton pressType);
public static event OnClick ClickDown;
public static event OnClick ClickUp;
static bool IsPressed;
private static Vector2 lastCursorWorldPosition;
static PointerEventData lastPointerData;
Vector2 lastControllerInput;
static bool internalWasHovering;
public static Vector2 CursorWorldPosition => lastCursorWorldPosition;
public static bool IsHovering { get; private set; }
private void Start()
{
renderCamera = Camera.main;
SceneManager.activeSceneChanged += (Scene s, Scene ss) => { renderCamera = Camera.main; };
}
public static void SetControllerReference(Transform t)
{
controllerReference = t;
}
private void RebuildCurrentPosition()
{
bool TryReadRightStick(out Vector2 input)
{
input = Vector2.zero;
if (controllerReference != null && Gamepad.current != null)
{
input = Gamepad.current.rightStick.ReadValue();
}
return input.magnitude >= 0.25f;
}
if (TryReadRightStick(out Vector2 stick))
{
IsHovering = true;
IsPressed = true;
stick = stick.normalized;
lastControllerInput = stick;
lastCursorWorldPosition = (Vector2)controllerReference.position + stick;
ClickDown.Invoke(lastCursorWorldPosition, PointerButton.Left);
return;
}
else
{
if (lastControllerInput.magnitude >= 0.25f)
{
IsPressed = false;
IsHovering = internalWasHovering;
lastControllerInput = Vector2.zero;
ClickUp.Invoke((Vector2)controllerReference.position + lastControllerInput, PointerButton.Left);
return;
}
}
if (lastPointerData != null && RenderTextureContainsMousePosition(out Vector2 click, lastPointerData, renderTexture))
{
ScaleRenderClickToCameraWorldPosition(out Vector2 w, click, Camera.main);
lastCursorWorldPosition = w;
}
}
private void Update()
{
RebuildCurrentPosition();
}
private void Awake()
{
IsPressed = false;
}
public void OnPointerMove(PointerEventData eventData)
{
if (RenderTextureContainsMousePosition(out Vector2 click, eventData, renderTexture))
{
ScaleRenderClickToCameraWorldPosition(out Vector2 worldPosition, click, Camera.main);
lastCursorWorldPosition = worldPosition;
lastPointerData = eventData;
}
}
public void OnPointerExit(PointerEventData eventData)
{
IsHovering = false;
if (IsPressed)
{
TriggerPressEvent(eventData, ClickUp);
}
}
public void OnPointerEnter(PointerEventData eventData)
{
IsHovering = true;
}
public void OnPointerUp(PointerEventData eventData)
{
TriggerPressEvent(eventData, ClickUp);
IsPressed = false;
}
public void OnPointerDown(PointerEventData eventData)
{
TriggerPressEvent(eventData, ClickDown);
IsPressed = true;
}
private void TriggerPressEvent(PointerEventData eventData, OnClick action)
{
if (RenderTextureContainsMousePosition(out Vector2 click, eventData, renderTexture))
{
ScaleRenderClickToCameraWorldPosition(out Vector2 worldPosition, click, Camera.main);
PointerButton pressType = PointerButton.Left;
switch (eventData.button)
{
case PointerEventData.InputButton.Left:
break;
case PointerEventData.InputButton.Right:
pressType = PointerButton.Right;
break;
case PointerEventData.InputButton.Middle:
pressType = PointerButton.Middle;
break;
default:
break;
}
action?.Invoke(worldPosition, pressType);
}
}
private void ScaleRenderClickToCameraWorldPosition(out Vector2 worldPosition, Vector2 normalizedClick, Camera fallbackCamera)
{
if (renderCamera == null)
{
renderCamera = fallbackCamera;
}
if (renderCamera == null)
{
worldPosition = lastCursorWorldPosition;
return;
}
Vector2 cameraSize = Vector2.zero;
cameraSize.y = renderCamera.orthographicSize * 2f;
cameraSize.x = cameraSize.y * renderCamera.aspect;
worldPosition = new Vector2(normalizedClick.x * cameraSize.x, normalizedClick.y * cameraSize.y) + (Vector2)renderCamera.transform.position;
worldPosition -= cameraSize * 0.5f;
}
private bool RenderTextureContainsMousePosition(out Vector2 normalizedPosition, PointerEventData pointer, RectTransform rendererRect)
{
internalWasHovering = false;
normalizedPosition = Vector2.zero;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rendererRect, pointer.position, pointer.pressEventCamera, out var localPosition))
{
return false;
}
normalizedPosition = Rect.PointToNormalized(rendererRect.rect, localPosition);
internalWasHovering = true;
return true;
}
}
}