private ILaserPointerTarget FindHitTarget()
        {
            ILaserPointerTarget newTarget = null;

            Ray = new Ray(transform.position, transform.forward);

            int        uiLayerMask = LayerMask.GetMask("_AnnotationUI");
            RaycastHit uiHit       = new RaycastHit();
            var        hasUIHit    = (Physics.Raycast(Ray, out uiHit, 1000, uiLayerMask));

            int        notUILayerMask = ~uiLayerMask;
            RaycastHit physicsHit     = new RaycastHit();
            var        hasPhysicsHit  = (Physics.Raycast(Ray, out physicsHit, 1000, notUILayerMask));

            var nodeHit    = (_nodeSelector != null) ? _nodeSelector.FindHit(Ray) : null;
            var hasNodeHit = (nodeHit != null);

            // var hitGizmo = physicsHit.collider.GetComponent<IClickableLaserPointerTarget>();

            // Physics ray wins
            if (hasUIHit)
            {
                LastHitPoint     = uiHit.point;
                _lastHitDistance = uiHit.distance;

                var hitCollider        = uiHit.collider;
                var newTargetInterface = hitCollider.attachedRigidbody
                                     ? hitCollider.attachedRigidbody.GetComponent <ILaserPointerTarget>()
                                     : hitCollider.gameObject.GetComponent <ILaserPointerTarget>();
                newTarget = newTargetInterface as ILaserPointerTarget;
            }
            else if (hasPhysicsHit && (!hasNodeHit || physicsHit.distance < nodeHit.HitDistance - 0.1f))
            {
                LastHitPoint     = physicsHit.point;
                _lastHitDistance = physicsHit.distance;

                var hitCollider        = physicsHit.collider;
                var newTargetInterface = hitCollider.attachedRigidbody
                                     ? hitCollider.attachedRigidbody.GetComponent <ILaserPointerTarget>()
                                     : hitCollider.gameObject.GetComponent <ILaserPointerTarget>();
                newTarget = newTargetInterface as ILaserPointerTarget;
            }
            // NodeHit wins...
            else if (hasNodeHit)
            {
                _nodeSelector.LastNodeHitByRay = nodeHit;
                LastHitPoint     = Ray.origin + Ray.direction * nodeHit.HitDistance;
                _lastHitDistance = nodeHit.HitDistance;
                newTarget        = _nodeSelector as ILaserPointerTarget;
            }
            // Nothing hit
            else
            {
                _lastHitDistance = 100;
                LastHitPoint     = Ray.direction * 100;
            }

            return(newTarget);
        }
        private void Update()
        {
            if (!_laserIsEnabled)
            {
                return;
            }

            ILaserPointerTarget newTarget = FindHitTarget();

            SetNewHitTarget(newTarget);
            SetLaserLength(_lastHitDistance);
            _laserHitSphere.transform.position = LastHitPoint;
        }
        private void SetNewHitTarget(ILaserPointerTarget newTarget)
        {
            var targetIsSame = (newTarget == PointingAt || IsLockedAtTarget);

            if (targetIsSame)
            {
                // Update position on Target
                if (PointingAt != null)
                {
                    PointingAt.PointerUpdate(this);
                }
                return;
            }

            if (Controller.ActiveState == InteractiveController.States.PointerCapturedOnClickable)
            {
                return;
            }

            // Exit old target
            if (PointingAt != null && !PointingAt.Equals(null)) // Also checking with .Equals because ==Operator is not overridden from MonoBehaviour
            {
                PointingAt.PointerExit(this);
            }

            PointingAt = newTarget;
            UpdateStyleIfTargetChanged();

            if (NewTargetEnteredEvent != null)
            {
                NewTargetEnteredEvent(this, new PointingAtChangedEventArgs(PointingAt, newTarget));
            }

            if (newTarget != null)
            {
                newTarget.PointerEnter(this);
            }
        }
 public PointingAtChangedEventArgs(ILaserPointerTarget oldTarget, ILaserPointerTarget newTarget)
 {
     OldTarget = oldTarget;
     NewTarget = newTarget;
 }