From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001
From: miepzerino <o.skotnik@gmail.com>
Date: Sun, 30 Mar 2025 18:50:27 +0000
Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop

---
 Assets/Flexalon/Runtime/Interaction/FlexalonRaycaster.cs |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/Assets/Flexalon/Runtime/Interaction/FlexalonRaycaster.cs b/Assets/Flexalon/Runtime/Interaction/FlexalonRaycaster.cs
new file mode 100644
index 0000000..8db4421
--- /dev/null
+++ b/Assets/Flexalon/Runtime/Interaction/FlexalonRaycaster.cs
@@ -0,0 +1,104 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Flexalon
+{
+    internal class FlexalonRaycaster
+    {
+        public Vector3 hitPosition;
+
+        private int _raycastFrame = 0;
+        private FlexalonInteractable _hitInteractable;
+        private readonly Dictionary<GameObject, FlexalonInteractable> _handles = new Dictionary<GameObject, FlexalonInteractable>();
+
+#if UNITY_UI
+        private List<UnityEngine.EventSystems.RaycastResult> _graphicRaycastResult = new List<UnityEngine.EventSystems.RaycastResult>();
+#endif
+
+#if UNITY_PHYSICS
+        private RaycastHit[] _raycastHits = new RaycastHit[10];
+#endif
+
+        public void Register(FlexalonInteractable interactable)
+        {
+            _handles.Add(interactable.Handle, interactable);
+        }
+
+        public void Unregister(FlexalonInteractable interactable)
+        {
+            _handles.Remove(interactable.Handle);
+        }
+
+        public bool IsHit(Vector3 uiPointer, Ray ray, FlexalonInteractable interactable)
+        {
+            // Check if we've already casted this frame.
+            if (_raycastFrame != Time.frameCount)
+            {
+                _hitInteractable = null;
+                _raycastFrame = Time.frameCount;
+                float minDistance = float.MaxValue;
+                RaycastUI(uiPointer, ref minDistance);
+                RaycastPhysics(ray, ref minDistance);
+            }
+
+            return _hitInteractable == interactable;
+        }
+
+        private void RaycastUI(Vector3 uiPointer, ref float minDistance)
+        {
+#if UNITY_UI
+                var eventSystem = UnityEngine.EventSystems.EventSystem.current;
+                if (eventSystem)
+                {
+                    eventSystem.RaycastAll(new UnityEngine.EventSystems.PointerEventData(eventSystem)
+                    {
+                        position = uiPointer
+                    }, _graphicRaycastResult);
+
+                    for (int i = 0; i < _graphicRaycastResult.Count; i++)
+                    {
+                        var hit = _graphicRaycastResult[i];
+                        if (hit.distance < minDistance)
+                        {
+                            if (_handles.TryGetValue(hit.gameObject, out var hitInteractable))
+                            {
+                                _hitInteractable = hitInteractable;
+                                minDistance = hit.distance;
+
+                                hitInteractable.UpdateCanvas();
+
+                                if (hitInteractable.Canvas?.renderMode == UnityEngine.RenderMode.ScreenSpaceOverlay)
+                                {
+                                    hitPosition = hit.screenPosition;
+                                }
+                                else
+                                {
+                                    hitPosition = hit.worldPosition;
+                                }
+                            }
+                        }
+                    }
+                }
+#endif
+        }
+
+        private void RaycastPhysics(Ray ray, ref float minDistance)
+        {
+#if UNITY_PHYSICS
+            int hits = Physics.RaycastNonAlloc(ray, _raycastHits, 1000);
+
+            // Find the nearest hit interactable.
+            for (int i = 0; i < hits; i++)
+            {
+                var hit = _raycastHits[i];
+                if (hit.distance < minDistance && _handles.TryGetValue(hit.collider.gameObject, out var hitInteractable))
+                {
+                    _hitInteractable = hitInteractable;
+                    minDistance = hit.distance;
+                    hitPosition = hit.point;
+                }
+            }
+#endif
+        }
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3