Skip to content

Instantly share code, notes, and snippets.

@OwenMagelssen
Last active July 3, 2022 17:05
Show Gist options
  • Save OwenMagelssen/b3390a3da0446480fe9989496d54ca25 to your computer and use it in GitHub Desktop.
Save OwenMagelssen/b3390a3da0446480fe9989496d54ca25 to your computer and use it in GitHub Desktop.
Provides missing functionality from Unity's new input system for MonoBehaviour.OnMouseDown/Drag/Enter/Exit/Over/Up/UpButton events
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Events;
public class CursorRaycaster : MonoBehaviour
{
public UnityEvent onClickNothing;
private const float DragThreshold = 1.0f;
private Ray ray;
private RaycastHit hit;
private Camera cam;
private GameObject previousHitObject;
private GameObject clickedObject;
private float dragDistance;
private bool dragging;
private const string MouseDown = "OnMouseDown";
private const string MouseDrag = "OnMouseDrag";
private const string MouseEnter = "OnMouseEnter";
private const string MouseExit = "OnMouseExit";
private const string MouseOver = "OnMouseOver";
private const string MouseUp = "OnMouseUp";
private const string MouseUpAsButton = "OnMouseUpAsButton";
private bool clicked;
private bool released;
private bool down;
private Vector2 delta;
private Vector2 screenspaceRayOrigin;
public BindInputActions(InputAction clickAction, InputAction moveDeltaAction)
{
clickAction.performed += Click;
clickAction.canceled += Release;
move = moveDeltaAction;
moveDeltaAction.performed += Move;
}
private void Click(InputAction.CallbackContext context)
{
clicked = true;
down = true;
}
private void Release(InputAction.CallbackContext context)
{
released = true;
down = false;
}
private void Move(InputAction.CallbackContext context) => delta += context.ReadValue<Vector2>();
private void UpdateCursorPosition() => screenspaceRayOrigin = Mouse.current.position.ReadValue();
private void Awake() => cam = Camera.main;
private void ConsumeInputs()
{
clicked = false;
released = false;
delta = Vector2.zero;
}
private void OnDownNoHit()
{
Debug.Log("Clicked Nothing");
onClickNothing?.Invoke();
}
private void OnDown(GameObject go) => previousHitObject.SendMessage(MouseDown, SendMessageOptions.DontRequireReceiver);
private void OnDrag()
{
if (dragging)
{
clickedObject.SendMessage(MouseDrag, SendMessageOptions.DontRequireReceiver);
return;
}
dragDistance += delta.sqrMagnitude;
dragging = dragDistance > DragThreshold;
}
private void OnEnter(GameObject go)
{
go.SendMessage(MouseEnter, SendMessageOptions.DontRequireReceiver);
previousHitObject = go;
}
private void OnExit()
{
previousHitObject.SendMessage(MouseExit, SendMessageOptions.DontRequireReceiver);
previousHitObject = null;
}
private void OnOver() => previousHitObject.SendMessage(MouseOver, SendMessageOptions.DontRequireReceiver);
private void OnUp() => previousHitObject.SendMessage(MouseUp, SendMessageOptions.DontRequireReceiver);
private void OnUpButton() => previousHitObject.SendMessage(MouseUpAsButton, SendMessageOptions.DontRequireReceiver);
public void FixedUpdate()
{
UpdateCursorPosition();
if (down && clickedObject)
OnDrag();
ray = cam.ScreenPointToRay(screenspaceRayOrigin);
if (Physics.Raycast(ray, out hit, cam.farClipPlane))
{
var hitObject = hit.collider.gameObject;
if (clicked)
{
OnDown(hitObject);
clickedObject = hitObject;
}
if (released)
{
OnUp();
if (clickedObject && ReferenceEquals(clickedObject, hitObject))
OnUpButton();
clickedObject = null;
dragging = false;
dragDistance = 0;
}
if (!previousHitObject)
{
OnEnter(hitObject);
ConsumeInputs();
return;
}
if (ReferenceEquals(previousHitObject, hitObject))
{
OnOver();
ConsumeInputs();
return;
}
OnExit();
OnEnter(hitObject);
}
else if (previousHitObject)
{
OnExit();
}
if (clicked)
OnDownNoHit();
ConsumeInputs();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment