You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
8.8 KiB
C#
261 lines
8.8 KiB
C#
6 months ago
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Events;
|
||
|
using UnityEngine.EventSystems;
|
||
|
|
||
|
namespace Autohand
|
||
|
{
|
||
|
[Serializable]
|
||
|
public class UnityCanvasPointerEvent : UnityEvent<Vector3, GameObject> { }
|
||
|
|
||
|
[HelpURL("https://app.gitbook.com/s/5zKO0EvOjzUDeT2aiFk3/auto-hand/extras/ui-interaction")]
|
||
|
public class HandCanvasPointer : MonoBehaviour
|
||
|
{
|
||
|
[Header("References")]
|
||
|
public GameObject hitPointMarker;
|
||
|
private LineRenderer lineRenderer;
|
||
|
|
||
|
|
||
|
[Header("Ray settings")]
|
||
|
public float raycastLength = 8.0f;
|
||
|
public bool autoShowTarget = true;
|
||
|
public LayerMask UILayer;
|
||
|
|
||
|
|
||
|
[Header("Events")]
|
||
|
public UnityCanvasPointerEvent StartSelect;
|
||
|
public UnityCanvasPointerEvent StopSelect;
|
||
|
public UnityCanvasPointerEvent StartPoint;
|
||
|
public UnityCanvasPointerEvent StopPoint;
|
||
|
|
||
|
|
||
|
|
||
|
public GameObject _currTarget;
|
||
|
public GameObject currTarget
|
||
|
{
|
||
|
get { return _currTarget; }
|
||
|
}
|
||
|
|
||
|
|
||
|
public RaycastHit lastHit { get; private set; }
|
||
|
|
||
|
// Internal variables
|
||
|
private bool hover = false;
|
||
|
AutoInputModule inputModule = null;
|
||
|
float lineSegements = 10f;
|
||
|
|
||
|
static Camera cam = null;
|
||
|
public static Camera UICamera
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (cam == null)
|
||
|
{
|
||
|
cam = new GameObject("Camera Canvas Pointer (I AM CREATED AT RUNTIME FOR UI CANVAS INTERACTION, I AM NOT RENDERING ANYTHING, I AM NOT CREATING ADDITIONAL OVERHEAD)").AddComponent<Camera>();
|
||
|
cam.clearFlags = CameraClearFlags.Nothing;
|
||
|
cam.stereoTargetEye = StereoTargetEyeMask.None;
|
||
|
cam.orthographic = true;
|
||
|
cam.orthographicSize = 0.001f;
|
||
|
cam.cullingMask = 0;
|
||
|
cam.nearClipPlane = 0.01f;
|
||
|
cam.depth = 0f;
|
||
|
cam.allowHDR = false;
|
||
|
cam.enabled = false;
|
||
|
cam.fieldOfView = 0.00001f;
|
||
|
cam.transform.parent = AutoHandExtensions.transformParent;
|
||
|
|
||
|
#if (UNITY_2020_3_OR_NEWER)
|
||
|
var canvases = AutoHandExtensions.CanFindObjectsOfType<Canvas>(true);
|
||
|
#else
|
||
|
var canvases = FindObjectsOfType<Canvas>();
|
||
|
#endif
|
||
|
foreach (var canvas in canvases)
|
||
|
if (canvas.renderMode == RenderMode.WorldSpace)
|
||
|
canvas.worldCamera = cam;
|
||
|
}
|
||
|
return cam;
|
||
|
}
|
||
|
}
|
||
|
int pointerIndex;
|
||
|
|
||
|
void OnEnable()
|
||
|
{
|
||
|
|
||
|
lineRenderer.positionCount = (int)lineSegements;
|
||
|
if (inputModule.Instance != null)
|
||
|
pointerIndex = inputModule.Instance.AddPointer(this);
|
||
|
ShowRay(false);
|
||
|
}
|
||
|
|
||
|
void OnDisable()
|
||
|
{
|
||
|
if(inputModule) inputModule.Instance?.RemovePointer(this);
|
||
|
}
|
||
|
|
||
|
public void SetIndex(int index)
|
||
|
{
|
||
|
pointerIndex = index;
|
||
|
}
|
||
|
|
||
|
internal void Preprocess()
|
||
|
{
|
||
|
UICamera.transform.position = transform.position;
|
||
|
UICamera.transform.forward = transform.forward;
|
||
|
}
|
||
|
|
||
|
public void Press()
|
||
|
{
|
||
|
// Handle the UI events
|
||
|
if(inputModule) inputModule.ProcessPress(pointerIndex);
|
||
|
|
||
|
// Show the ray when they attemp to press
|
||
|
if (!autoShowTarget && hover) ShowRay(true);
|
||
|
|
||
|
if (lastHit.collider != null)
|
||
|
{
|
||
|
// Fire the Unity event
|
||
|
StartSelect?.Invoke(lastHit.point, lastHit.transform.gameObject);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PointerEventData data = inputModule.GetData(pointerIndex);
|
||
|
float targetLength = data.pointerCurrentRaycast.distance == 0 ? raycastLength : data.pointerCurrentRaycast.distance;
|
||
|
StartSelect?.Invoke(transform.position + (transform.forward * targetLength), null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Release()
|
||
|
{
|
||
|
// Handle the UI events
|
||
|
if(inputModule) inputModule.ProcessRelease(pointerIndex);
|
||
|
|
||
|
if (lastHit.collider != null)
|
||
|
{
|
||
|
// Fire the Unity event
|
||
|
StopSelect?.Invoke(lastHit.point, lastHit.transform.gameObject);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PointerEventData data = inputModule.GetData(pointerIndex);
|
||
|
float targetLength = data.pointerCurrentRaycast.distance == 0 ? raycastLength : data.pointerCurrentRaycast.distance;
|
||
|
StopSelect?.Invoke(transform.position + (transform.forward * targetLength), null);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private void Awake()
|
||
|
{
|
||
|
if (lineRenderer == null)
|
||
|
gameObject.CanGetComponent(out lineRenderer);
|
||
|
|
||
|
if (inputModule == null)
|
||
|
{
|
||
|
if (gameObject.CanGetComponent<AutoInputModule>(out var inputMod))
|
||
|
{
|
||
|
inputModule = inputMod;
|
||
|
}
|
||
|
else if (!(inputModule = AutoHandExtensions.CanFindObjectOfType<AutoInputModule>()))
|
||
|
{
|
||
|
EventSystem system = AutoHandExtensions.CanFindObjectOfType<EventSystem>();
|
||
|
if(system == null) {
|
||
|
system = new GameObject().AddComponent<EventSystem>();
|
||
|
system.name = "UI Input Event System";
|
||
|
}
|
||
|
inputModule = system.gameObject.AddComponent<AutoInputModule>();
|
||
|
inputModule.transform.parent = AutoHandExtensions.transformParent;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Update()
|
||
|
{
|
||
|
UpdateLine();
|
||
|
}
|
||
|
|
||
|
private void UpdateLine()
|
||
|
{
|
||
|
PointerEventData data = inputModule.GetData(pointerIndex);
|
||
|
float targetLength = data.pointerCurrentRaycast.distance == 0 ? raycastLength : data.pointerCurrentRaycast.distance;
|
||
|
|
||
|
if (targetLength > 0)
|
||
|
_currTarget = data.pointerCurrentRaycast.gameObject;
|
||
|
else
|
||
|
_currTarget = null;
|
||
|
|
||
|
if (data.pointerCurrentRaycast.distance != 0 && !hover)
|
||
|
{
|
||
|
lastHit = CreateRaycast(targetLength);
|
||
|
Vector3 endPosition = transform.position + (transform.forward * targetLength);
|
||
|
if (lastHit.collider) endPosition = lastHit.point;
|
||
|
|
||
|
|
||
|
if (lastHit.collider != null)
|
||
|
StartPoint?.Invoke(lastHit.point, lastHit.transform.gameObject);
|
||
|
else
|
||
|
StartPoint?.Invoke(endPosition, null);
|
||
|
|
||
|
|
||
|
// Show the ray if autoShowTarget is on when they enter the canvas
|
||
|
if (autoShowTarget) ShowRay(true);
|
||
|
|
||
|
hover = true;
|
||
|
}
|
||
|
else if (data.pointerCurrentRaycast.distance == 0 && hover)
|
||
|
{
|
||
|
lastHit = CreateRaycast(targetLength);
|
||
|
Vector3 endPosition = transform.position + (transform.forward * targetLength);
|
||
|
if (lastHit.collider) endPosition = lastHit.point;
|
||
|
|
||
|
if (lastHit.collider != null)
|
||
|
StopPoint?.Invoke(lastHit.point, lastHit.transform.gameObject);
|
||
|
else
|
||
|
StopPoint?.Invoke(endPosition, null);
|
||
|
|
||
|
// Hide the ray when they leave the canvas
|
||
|
ShowRay(false);
|
||
|
|
||
|
hover = false;
|
||
|
}
|
||
|
|
||
|
if(hover) {
|
||
|
lastHit = CreateRaycast(targetLength);
|
||
|
|
||
|
Vector3 endPosition = transform.position + (transform.forward * targetLength);
|
||
|
|
||
|
if(lastHit.collider) endPosition = lastHit.point;
|
||
|
|
||
|
//Handle the hitmarker
|
||
|
hitPointMarker.transform.position = endPosition;
|
||
|
hitPointMarker.transform.forward = data.pointerCurrentRaycast.worldNormal;
|
||
|
|
||
|
if(lastHit.collider) {
|
||
|
hitPointMarker.transform.forward = lastHit.collider.transform.forward;
|
||
|
hitPointMarker.transform.position = endPosition + hitPointMarker.transform.forward * 0.002f;
|
||
|
}
|
||
|
|
||
|
//Handle the line renderer
|
||
|
for(int i = 0; i < lineSegements; i++) {
|
||
|
lineRenderer.SetPosition(i, Vector3.Lerp(transform.position, endPosition, i/ lineSegements));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private RaycastHit CreateRaycast(float dist)
|
||
|
{
|
||
|
RaycastHit hit;
|
||
|
Ray ray = new Ray(transform.position, transform.forward);
|
||
|
Physics.Raycast(ray, out hit, dist, UILayer);
|
||
|
|
||
|
return hit;
|
||
|
}
|
||
|
|
||
|
private void ShowRay(bool show)
|
||
|
{
|
||
|
hitPointMarker.SetActive(show);
|
||
|
lineRenderer.enabled = show;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|