5 using System.Collections.Generic;
18 #region MonoBehaviour Implementation 24 if (registeredPointers != null)
26 for (
int iPointer = 0; iPointer < registeredPointers.Length; iPointer++)
28 GameObject owner = registeredPointers[iPointer];
32 Debug.LogError(
"AutoRegisteredPointers contains a null (\"None\") object.");
38 if (pointingSource == null)
40 Debug.LogErrorFormat(
"AutoRegisteredPointers contains object \"{0}\" which is missing its {1} component.",
47 RegisterPointer(pointingSource);
63 UpdateFocusedObjects();
74 private float pointingExtent = 10f;
76 public float GlobalPointingExtent {
get {
return pointingExtent; } }
90 [Tooltip(
"The LayerMasks, in prioritized order, that are used to determine the HitObject when raycasting.")]
91 private LayerMask[] pointingRaycastLayerMasks = { Physics.DefaultRaycastLayers };
94 private GameObject[] registeredPointers = null;
97 private bool autoRegisterGazePointerIfNoPointersRegistered =
true;
100 private bool debugDrawPointingRays =
false;
103 private Color[] debugDrawPointingRayColors = null;
118 if (pointerData == null)
129 PointingSource = pointingSource;
132 [Obsolete(
"Use UpdateHit(RaycastHit hit, RayStep sourceRay, int rayStepIndex) or UpdateHit (float extent)")]
133 public void UpdateHit(RaycastHit hit)
135 throw new NotImplementedException();
138 public void UpdateHit(RaycastHit hit,
RayStep sourceRay,
int rayStepIndex)
140 LastRaycastHit = hit;
141 PreviousEndObject = End.Object;
142 RayStepIndex = rayStepIndex;
144 StartPoint = sourceRay.
Origin;
149 Object = hit.transform.gameObject
153 public void UpdateHit(RaycastResult result, RaycastHit hit,
RayStep sourceRay,
int rayStepIndex)
158 RayStepIndex = rayStepIndex;
159 StartPoint = sourceRay.
Origin;
164 Object = result.gameObject
168 public void UpdateHit(
float extent)
170 PreviousEndObject = End.Object;
172 RayStep firstStep = PointingSource.Rays[0];
173 RayStep finalStep = PointingSource.Rays[PointingSource.Rays.Length - 1];
176 StartPoint = firstStep.
Origin;
185 public void ResetFocusedObjects(
bool clearPreviousObject =
true)
187 if (clearPreviousObject)
189 PreviousEndObject = null;
201 private readonly List<PointerData> pointers =
new List<PointerData>(0);
208 private PointerData gazeManagerPointingData;
210 [Obsolete(
"Use GetGazePointerEventData or GetSpecificPointerEventData")]
213 private readonly HashSet<GameObject> pendingOverallFocusEnterSet =
new HashSet<GameObject>();
214 private readonly HashSet<GameObject> pendingOverallFocusExitSet =
new HashSet<GameObject>();
215 private readonly List<PointerData> pendingPointerSpecificFocusChange =
new List<PointerData>();
221 private Vector3 newUiRaycastPosition = Vector3.zero;
227 private Camera uiRaycastCamera;
233 public Camera UIRaycastCamera
237 if (uiRaycastCamera == null)
239 Debug.LogWarning(
"No UIRaycastCamera assigned! Falling back to the RaycastCamera.\n" +
240 "It's highly recommended to use the RaycastCamera found on the EventSystem of this InputManager.");
241 uiRaycastCamera = GetComponentInChildren<Camera>();
244 return uiRaycastCamera;
254 Debug.Assert(pointingSource != null,
"Can't register a pointer if you give us one.");
259 if (TryGetPointerIndex(pointingSource, out pointerIndex))
267 if (gazeManagerPointingData == null)
269 if (GazeManager.IsInitialized)
271 gazeManagerPointingData =
new PointerData(GazeManager.Instance);
276 Debug.Assert(ReferenceEquals(gazeManagerPointingData.PointingSource, GazeManager.Instance));
277 gazeManagerPointingData.ResetFocusedObjects();
280 Debug.Assert(gazeManagerPointingData != null);
281 pointer = gazeManagerPointingData;
285 pointer =
new PointerData(pointingSource);
288 pointers.Add(pointer);
293 Debug.Assert(pointingSource != null,
"Can't unregister a pointer if you give us one.");
296 TryGetPointerIndex(pointingSource, out pointerIndex);
297 Debug.Assert(pointerIndex >= 0,
"Invalid pointer index!");
300 GetPointerData(pointingSource, out pointer);
301 Debug.Assert(pointer != null,
"Attempting to unregister a pointer that was never registered!");
305 pointers.RemoveAt(pointerIndex);
309 if (pointer.End.Object != null)
311 GameObject unfocusedObject = pointer.End.Object;
313 bool objectIsStillFocusedByOtherPointer =
false;
315 for (
int iOther = 0; iOther < pointers.Count; iOther++)
317 if (pointers[iOther].End.Object == unfocusedObject)
319 objectIsStillFocusedByOtherPointer =
true;
324 if (!objectIsStillFocusedByOtherPointer)
326 RaiseFocusExitedEvents(unfocusedObject);
329 RaisePointerSpecificFocusChangedEvents(pointer.PointingSource, unfocusedObject, null);
335 for (
int i = 0; i < pointers.Count; i++)
337 if (pointers[i].PointingSource.OwnsInput(eventData))
339 return pointers[i].End;
349 TryGetPointingSource(eventData, out pointingSource);
353 if (pointerInputEventData == null)
357 return pointerInputEventData.selectedObject;
363 pointingSource = null;
364 if (eventData == null) {
return false; }
366 for (
int i = 0; i < pointers.Count; i++)
368 if (pointers[i].PointingSource.OwnsInput(eventData))
370 pointingSource = pointers[i].PointingSource;
380 PointerData pointerData;
383 if (GetPointerData(pointingSource, out pointerData))
385 details = pointerData.End;
393 PointerData pointerData;
394 GameObject focusedObject = null;
396 if (GetPointerData(pointingSource, out pointerData))
398 focusedObject = pointerData.End.Object;
401 return focusedObject;
410 if (pointers.Count == 1)
412 pointingSource = pointers[0].PointingSource;
416 pointingSource = null;
420 public delegate
void FocusEnteredMethod(GameObject focusedObject);
423 public delegate
void FocusExitedMethod(GameObject unfocusedObject);
426 public delegate
void PointerSpecificFocusChangedMethod(
IPointingSource pointer, GameObject oldFocusedObject, GameObject newFocusedObject);
429 [Obsolete(
"Use either GetGazePointerEventData or GetSpecificPointerEventData")]
432 return GetGazePointerEventData();
437 return gazeManagerPointingData.UnityUIPointerData;
442 PointerData pointerEventData;
444 if (!GetPointerData(pointer, out pointerEventData)) {
return null; }
446 pointerEventData.UnityUIPointerData.selectedObject = GetFocusedObject(pointer);
447 return pointerEventData.UnityUIPointerData;
459 private void UpdatePointers()
461 bool gazeManagerIsRegistered =
false;
463 for (
int iPointer = 0; iPointer < pointers.Count; iPointer++)
465 PointerData pointer = pointers[iPointer];
467 if (pointer == gazeManagerPointingData)
469 gazeManagerIsRegistered =
true;
472 UpdatePointer(pointer);
474 if (debugDrawPointingRays)
478 if ((debugDrawPointingRayColors != null) && (debugDrawPointingRayColors.Length > 0))
480 rayColor = debugDrawPointingRayColors[iPointer % debugDrawPointingRayColors.Length];
484 rayColor = Color.green;
487 Debug.DrawRay(pointer.StartPoint, (pointer.End.Point - pointer.StartPoint), rayColor);
491 if (gazeManagerPointingData != null)
495 if (!gazeManagerIsRegistered)
497 UpdatePointer(gazeManagerPointingData);
500 GazeManager.
Instance.UpdateHitDetails(gazeManagerPointingData.End, gazeManagerPointingData.LastRaycastHit, gazeManagerIsRegistered);
504 private void UpdatePointer(PointerData pointer)
509 pointer.PointingSource.OnPreRaycast();
512 if (!pointer.PointingSource.InteractionEnabled)
515 pointer.ResetFocusedObjects(
false);
523 if (!pointer.PointingSource.FocusLocked)
526 var prioritizedLayerMasks = (pointer.PointingSource.PrioritizedLayerMasksOverride ?? pointingRaycastLayerMasks);
529 RaycastPhysics(pointer, prioritizedLayerMasks);
532 if (EventSystem.current != null)
535 RaycastUnityUI(pointer, prioritizedLayerMasks);
539 pointer.PointingSource.Result = pointer;
546 pointer.PointingSource.OnPostRaycast();
552 private void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMasks)
555 int rayStepIndex = 0;
557 RaycastHit physicsHit =
default(RaycastHit);
560 Debug.Assert(pointer.PointingSource.Rays != null,
"No valid rays for pointer ");
561 Debug.Assert(pointer.PointingSource.Rays.Length > 0,
"No valid rays for pointer ");
564 for (
int i = 0; i < pointer.PointingSource.Rays.Length; i++)
566 if (RaycastPhysicsStep(pointer.PointingSource.Rays[i], prioritizedLayerMasks, out physicsHit))
570 rayStep = pointer.PointingSource.Rays[i];
579 pointer.UpdateHit(physicsHit, rayStep, rayStepIndex);
583 pointer.UpdateHit(GetPointingExtent(pointer.PointingSource));
587 private bool RaycastPhysicsStep(
RayStep step, LayerMask[] prioritizedLayerMasks, out RaycastHit physicsHit)
590 physicsHit =
default(RaycastHit);
593 if (prioritizedLayerMasks.Length == 1)
595 isHit = Physics.Raycast(step.
Origin, step.
Direction, out physicsHit, step.
Length, prioritizedLayerMasks[0]);
600 RaycastHit? hit = PrioritizeHits(Physics.RaycastAll(step.
Origin, step.
Direction, step.
Length, Physics.AllLayers), prioritizedLayerMasks);
601 isHit = hit.HasValue;
605 physicsHit = hit.Value;
612 private void RaycastUnityUI(PointerData pointer, LayerMask[] prioritizedLayerMasks)
614 Debug.Assert(UIRaycastCamera != null,
"You must assign a UIRaycastCamera on the FocusManager before you can process uGUI raycasting.");
616 RaycastResult uiRaycastResult =
default(RaycastResult);
617 bool overridePhysicsRaycast =
false;
619 int rayStepIndex = 0;
622 Debug.Assert(pointer.PointingSource.Rays != null,
"No valid rays for pointer ");
623 Debug.Assert(pointer.PointingSource.Rays.Length > 0,
"No valid rays for pointer ");
626 for (
int i = 0; i < pointer.PointingSource.Rays.Length; i++)
628 if (RaycastUnityUIStep(pointer, pointer.PointingSource.Rays[i], prioritizedLayerMasks, out overridePhysicsRaycast, out uiRaycastResult))
631 rayStep = pointer.PointingSource.Rays[i];
637 if ((pointer.End.Object == null || overridePhysicsRaycast) && uiRaycastResult.isValid &&
638 uiRaycastResult.module != null && uiRaycastResult.module.eventCamera == UIRaycastCamera)
640 newUiRaycastPosition.x = uiRaycastResult.screenPosition.x;
641 newUiRaycastPosition.y = uiRaycastResult.screenPosition.y;
642 newUiRaycastPosition.z = uiRaycastResult.distance;
644 Vector3 worldPos = UIRaycastCamera.ScreenToWorldPoint(newUiRaycastPosition);
646 var hitInfo =
new RaycastHit
649 normal = -uiRaycastResult.gameObject.transform.forward
652 pointer.UpdateHit(uiRaycastResult, hitInfo, rayStep, rayStepIndex);
656 private bool RaycastUnityUIStep(PointerData pointer,
RayStep step, LayerMask[] prioritizedLayerMasks, out
bool overridePhysicsRaycast, out RaycastResult uiRaycastResult)
659 UIRaycastCamera.transform.position = step.
Origin;
660 UIRaycastCamera.transform.forward = step.
Direction;
663 pointer.UnityUIPointerData.position =
new Vector2(UIRaycastCamera.pixelWidth * 0.5f, UIRaycastCamera.pixelHeight * 0.5f);
666 uiRaycastResult = EventSystem.current.Raycast(pointer.UnityUIPointerData, prioritizedLayerMasks);
667 pointer.UnityUIPointerData.pointerCurrentRaycast = uiRaycastResult;
669 overridePhysicsRaycast =
false;
672 if (uiRaycastResult.gameObject != null)
674 if (pointer.End.Object != null)
677 if (prioritizedLayerMasks.Length > 1)
680 int uiLayerIndex = uiRaycastResult.gameObject.layer.FindLayerListIndex(prioritizedLayerMasks);
681 int threeDLayerIndex = pointer.LastRaycastHit.collider.gameObject.layer.FindLayerListIndex(prioritizedLayerMasks);
683 if (threeDLayerIndex > uiLayerIndex)
685 overridePhysicsRaycast =
true;
687 else if (threeDLayerIndex == uiLayerIndex)
689 if (pointer.LastRaycastHit.distance > uiRaycastResult.distance)
691 overridePhysicsRaycast =
true;
697 if (pointer.LastRaycastHit.distance > uiRaycastResult.distance)
699 overridePhysicsRaycast =
true;
710 private void UpdateFocusedObjects()
712 Debug.Assert(pendingPointerSpecificFocusChange.Count == 0);
713 Debug.Assert(pendingOverallFocusExitSet.Count == 0);
714 Debug.Assert(pendingOverallFocusEnterSet.Count == 0);
720 for (
int iPointer = 0; iPointer < pointers.Count; iPointer++)
722 PointerData pointer = pointers[iPointer];
724 if (pointer.PreviousEndObject != pointer.End.Object)
726 pendingPointerSpecificFocusChange.Add(pointer);
731 if (pointer.PreviousEndObject != null)
733 pendingOverallFocusExitSet.Add(pointer.PreviousEndObject);
736 if (pointer.End.Object != null)
738 pendingOverallFocusEnterSet.Add(pointer.End.Object);
745 for (
int iPointer = 0; iPointer < pointers.Count; iPointer++)
747 PointerData pointer = pointers[iPointer];
749 pendingOverallFocusExitSet.Remove(pointer.End.Object);
751 pendingOverallFocusEnterSet.Remove(pointer.PreviousEndObject);
756 foreach (GameObject exit
in pendingOverallFocusExitSet)
758 RaiseFocusExitedEvents(exit);
761 foreach (GameObject enter
in pendingOverallFocusEnterSet)
763 RaiseFocusEnteredEvents(enter);
766 for (
int iChange = 0; iChange < pendingPointerSpecificFocusChange.Count; iChange++)
768 PointerData change = pendingPointerSpecificFocusChange[iChange];
770 RaisePointerSpecificFocusChangedEvents(change.PointingSource, change.PreviousEndObject, change.End.Object);
773 pendingOverallFocusEnterSet.Clear();
774 pendingOverallFocusExitSet.Clear();
775 pendingPointerSpecificFocusChange.Clear();
778 private void RaiseFocusExitedEvents(GameObject unfocusedObject)
782 if (FocusExited != null)
784 FocusExited(unfocusedObject);
788 private void RaiseFocusEnteredEvents(GameObject focusedObject)
792 if (FocusEntered != null)
794 FocusEntered(focusedObject);
798 private void RaisePointerSpecificFocusChangedEvents(
IPointingSource pointer, GameObject oldFocusedObject, GameObject newFocusedObject)
800 InputManager.
Instance.RaisePointerSpecificFocusChangedEvents(pointer, oldFocusedObject, newFocusedObject);
802 if (PointerSpecificFocusChanged != null)
804 PointerSpecificFocusChanged(pointer, oldFocusedObject, newFocusedObject);
808 private bool GetPointerData(
IPointingSource pointingSource, out PointerData pointerData)
812 if (TryGetPointerIndex(pointingSource, out pointerIndex))
814 pointerData = pointers[pointerIndex];
822 private bool TryGetPointerIndex(
IPointingSource pointingSource, out
int pointerIndex)
824 for (
int i = 0; i < pointers.Count; i++)
826 if (pointingSource == pointers[i].PointingSource)
837 private RaycastHit? PrioritizeHits(RaycastHit[] hits, LayerMask[] layerMasks)
839 if (hits.Length == 0)
846 for (
int layerMaskIdx = 0; layerMaskIdx < layerMasks.Length; layerMaskIdx++)
848 RaycastHit? minHit = null;
850 for (
int hitIdx = 0; hitIdx < hits.Length; hitIdx++)
852 RaycastHit hit = hits[hitIdx];
853 if (hit.transform.gameObject.layer.IsInLayerMask(layerMasks[layerMaskIdx]) &&
854 (minHit == null || hit.distance < minHit.Value.distance))
875 Debug.Assert(UIRaycastCamera != null,
"You must assign a UIRaycastCamera on the FocusManager before updating your canvases.");
879 var sceneCanvases = Resources.FindObjectsOfTypeAll<Canvas>();
881 for (var i = 0; i < sceneCanvases.Length; i++)
883 if (sceneCanvases[i].isRootCanvas && sceneCanvases[i].renderMode == RenderMode.WorldSpace)
885 sceneCanvases[i].worldCamera = UIRaycastCamera;