Пример #1
0
    public static bool GetAimTarget(out RaycastHit hit, Vector2 minMax, Vector3 source, Transform aim, LayerMask layerMask, string m_IgnoreTag)
    {
        var aimPos     = aim.position;
        var aimForward = aim.forward;
        //var pos = source.position;

        var posDist = Vector3.Distance(aimPos, source);

        aimPos += aimForward * posDist;
        Debug.DrawLine(aim.position, aimPos, Color.red);
        //hit.point = aimPos + (aimForward * minMax.y);

        Ray ray = new Ray(aimPos, aimForward);

        if (RuntimeUtility.RaycastIgnoreTag(ray, out hit, minMax.y, layerMask, m_IgnoreTag))
        {
            //target = hit.point;
            Debug.DrawLine(aimPos, hit.point, Color.green);
        }
        else if (Physics.Raycast(aimPos + (aimForward * minMax.y), Vector3.down, out hit, minMax.y, layerMask, QueryTriggerInteraction.Ignore))
        {
            Debug.DrawLine(aimPos, hit.point, Color.yellow);
            //target = hit.point;
        }
        else
        {
            hit.point = aimPos + (aimForward * minMax.y);
            return(false);
        }

        var dist = Vector3.Distance(source, hit.point);

        return(dist > minMax.x);
    }
Пример #2
0
        public bool GetTarget(out Vector3 target, float min, float max, Transform source, Transform aim, out Transform lockon)
        {
            lockon = null;
            var aimPos     = aim.transform.position;
            var aimForward = aim.transform.forward;
            var pos        = source.position;

            var posDist = Vector3.Distance(aimPos, pos);

            aimPos += aimForward * posDist;
            RaycastHit hit;

            target = aimPos + (aimForward * max);

            if (RuntimeUtility.SphereCastIgnoreTag(aimPos, targetRadius, cam.forward, out hit, max, targetLayerMask, m_IgnoreTag))
            {
                var heading   = hit.point - aimPos;
                Ray headinRay = new Ray(aimPos, heading.normalized);

                if (RuntimeUtility.RaycastIgnoreTag(headinRay, out hit, max, layerMask, m_IgnoreTag))
                {
                    target = hit.point;
                    if ((targetLayerMask & 1 << hit.collider.gameObject.layer) == 1 << hit.collider.gameObject.layer)
                    {
                        if (hit.collider.TryGetComponent(out Animator animator) && animator.isHuman)
                        {
                            lockon = animator.GetBoneTransform(HumanBodyBones.Head);
                            target = lockon.position;
                        }
                    }
                }
            }

            if (!lockon)
            {
                Ray ray = new Ray(aimPos, cam.forward);

                if (RuntimeUtility.RaycastIgnoreTag(ray, out hit, max, layerMask, m_IgnoreTag))
                {
                    target = hit.point;
                    if ((targetLayerMask & 1 << hit.collider.gameObject.layer) == 1 << hit.collider.gameObject.layer)
                    {
                        if (hit.collider.TryGetComponent(out Animator animator) && animator.isHuman)
                        {
                            lockon = animator.GetBoneTransform(HumanBodyBones.Head);
                            target = lockon.position;
                        }
                    }
                }
                else if (Physics.Raycast(aimPos + (cam.forward * max), Vector3.down, out hit, max, layerMask, QueryTriggerInteraction.Ignore))
                {
                    target = hit.point;
                }
            }

            var dist = Vector3.Distance(aimPos, target);

            return(dist > min);
        }
        private Vector3 PullCameraInFrontOfNearestObstacle(
            Vector3 cameraPos, Vector3 lookAtPos, int layerMask, ref RaycastHit hitInfo)
        {
            Vector3 displacement   = Vector3.zero;
            Vector3 dir            = cameraPos - lookAtPos;
            float   targetDistance = dir.magnitude;

            if (_cinemachineCameraOffset)
            {
                targetDistance -= _cinemachineCameraOffset.m_Offset.z;
            }

            if (targetDistance > Epsilon)
            {
                dir /= targetDistance;
                float minDistanceFromTarget = Mathf.Max(m_MinimumDistanceFromTarget, Epsilon);
                if (targetDistance < minDistanceFromTarget + Epsilon)
                {
                    displacement = dir * (minDistanceFromTarget - targetDistance);
                }
                else
                {
                    float rayLength = targetDistance - minDistanceFromTarget;
                    if (m_DistanceLimit > Epsilon)
                    {
                        rayLength = Mathf.Min(m_DistanceLimit, rayLength);
                    }

                    // Make a ray that looks towards the camera, to get the obstacle closest to target
                    Ray ray = new Ray(cameraPos - rayLength * dir, dir);
                    rayLength += PrecisionSlush;
                    if (rayLength > Epsilon)
                    {
                        if (RuntimeUtility.RaycastIgnoreTag(
                                ray, out hitInfo, rayLength, layerMask, m_IgnoreTag))
                        {
                            // Pull camera forward in front of obstacle
                            float adjustment = Mathf.Max(0, hitInfo.distance - PrecisionSlush);
                            displacement = ray.GetPoint(adjustment) - cameraPos;
                        }
                    }
                }
            }

            return(displacement);
        }
        private bool CheckForTargetObstructions(CameraState state)
        {
            if (state.HasLookAt)
            {
                Vector3 lookAtPos = state.ReferenceLookAt;
                Vector3 pos       = state.CorrectedPosition;
                Vector3 dir       = lookAtPos - pos;
                float   distance  = dir.magnitude;
                if (distance < Mathf.Max(m_MinimumDistanceFromTarget, Epsilon))
                {
                    return(true);
                }
                Ray        ray = new Ray(pos, dir.normalized);
                RaycastHit hitInfo;
                if (RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo,
                                                    distance - m_MinimumDistanceFromTarget,
                                                    m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
                {
                    return(true);
                }
            }

            return(false);
        }
        private Vector3 RespectCameraRadius(Vector3 cameraPos, ref CameraState state)
        {
            Vector3 result = Vector3.zero;

            if (m_CameraRadius < Epsilon || m_CollideAgainst == 0)
            {
                return(result);
            }

            Vector3 dir      = state.HasLookAt ? (cameraPos - state.ReferenceLookAt) : Vector3.zero;
            Ray     ray      = new Ray();
            float   distance = dir.magnitude;

            if (distance > Epsilon)
            {
                dir /= distance;
                ray  = new Ray(state.ReferenceLookAt, dir);
            }

            // Pull it out of any intersecting obstacles
            RaycastHit hitInfo;
            int        numObstacles = Physics.OverlapSphereNonAlloc(
                cameraPos, m_CameraRadius, mColliderBuffer,
                m_CollideAgainst, QueryTriggerInteraction.Ignore);

            if (numObstacles == 0 && m_TransparentLayers != 0 &&
                distance > m_MinimumDistanceFromTarget + Epsilon)
            {
                // Make sure the camera position isn't completely inside an obstacle.
                // OverlapSphereNonAlloc won't catch those.
                float   d         = distance - m_MinimumDistanceFromTarget;
                Vector3 targetPos = state.ReferenceLookAt + dir * m_MinimumDistanceFromTarget;
                if (RuntimeUtility.RaycastIgnoreTag(new Ray(targetPos, dir),
                                                    out hitInfo, d, m_CollideAgainst, m_IgnoreTag))
                {
                    // Only count it if there's an incoming collision but not an outgoing one
                    Collider c = hitInfo.collider;
                    if (!c.Raycast(new Ray(cameraPos, -dir), out hitInfo, d))
                    {
                        mColliderBuffer[numObstacles++] = c;
                    }
                }
            }

            if (numObstacles > 0 && distance == 0 || distance > m_MinimumDistanceFromTarget)
            {
                if (mCameraColliderGameObject == null)
                {
                    mCameraColliderGameObject                    = new GameObject("CinemachineCollider Collider");
                    mCameraColliderGameObject.hideFlags          = HideFlags.HideAndDontSave;
                    mCameraColliderGameObject.transform.position = Vector3.zero;
                    mCameraColliderGameObject.SetActive(true);
                    mCameraCollider           = mCameraColliderGameObject.AddComponent <SphereCollider>();
                    mCameraCollider.isTrigger = true;
                    var rb = mCameraColliderGameObject.AddComponent <Rigidbody>();
                    rb.detectCollisions = false;
                    rb.isKinematic      = true;
                }

                mCameraCollider.radius = m_CameraRadius;
                Vector3 offsetDir;
                float   offsetDistance;
                Vector3 newCamPos = cameraPos;
                for (int i = 0; i < numObstacles; ++i)
                {
                    Collider c = mColliderBuffer[i];
                    if (m_IgnoreTag.Length > 0 && c.CompareTag(m_IgnoreTag))
                    {
                        continue;
                    }

                    // If we have a lookAt target, move the camera to the nearest edge of obstacle
                    if (distance > m_MinimumDistanceFromTarget)
                    {
                        dir = newCamPos - state.ReferenceLookAt;
                        float d = dir.magnitude;
                        if (d > Epsilon)
                        {
                            dir /= d;
                            ray  = new Ray(state.ReferenceLookAt, dir);
                            if (c.Raycast(ray, out hitInfo, d + m_CameraRadius))
                            {
                                newCamPos = ray.GetPoint(hitInfo.distance) - (dir * PrecisionSlush);
                            }
                        }
                    }

                    if (Physics.ComputePenetration(
                            mCameraCollider, newCamPos, Quaternion.identity,
                            c, c.transform.position, c.transform.rotation,
                            out offsetDir, out offsetDistance))
                    {
                        newCamPos += offsetDir * offsetDistance;
                    }
                }

                result = newCamPos - cameraPos;
            }

            // Respect the minimum distance from target - push camera back if we have to
            if (distance > Epsilon)
            {
                float   minDistance = Mathf.Max(m_MinimumDistanceFromTarget, m_CameraRadius) + PrecisionSlush;
                Vector3 newOffset   = cameraPos + result - state.ReferenceLookAt;
                if (newOffset.magnitude < minDistance)
                {
                    result = state.ReferenceLookAt - cameraPos + dir * minDistance;
                }
            }

            return(result);
        }
        private Vector3 PushCameraBack(
            Vector3 currentPos, Vector3 pushDir, RaycastHit obstacle,
            Vector3 lookAtPos, Plane startPlane, float targetDistance, int iterations,
            ref VcamExtraState extra)
        {
            // Take a step along the wall.
            Vector3 pos = currentPos;
            Vector3 dir = Vector3.zero;

            if (!GetWalkingDirection(pos, pushDir, obstacle, ref dir))
            {
                return(pos);
            }

            Ray   ray      = new Ray(pos, dir);
            float distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);

            if (distance <= Epsilon)
            {
                return(pos);
            }

            // Check only as far as the obstacle bounds
            float clampedDistance = ClampRayToBounds(ray, distance, obstacle.collider.bounds);

            distance = Mathf.Min(distance, clampedDistance + PrecisionSlush);

            RaycastHit hitInfo;

            if (RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo, distance,
                                                m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
            {
                // We hit something.  Stop there and take a step along that wall.
                float adjustment = hitInfo.distance - PrecisionSlush;
                pos = ray.GetPoint(adjustment);
                extra.AddPointToDebugPath(pos);
                if (iterations > 1)
                {
                    pos = PushCameraBack(
                        pos, dir, hitInfo,
                        lookAtPos, startPlane,
                        targetDistance, iterations - 1, ref extra);
                }

                return(pos);
            }

            // Didn't hit anything.  Can we push back all the way now?
            pos = ray.GetPoint(distance);

            // First check if we can still see the target.  If not, abort
            dir = pos - lookAtPos;
            float      d = dir.magnitude;
            RaycastHit hitInfo2;

            if (d < Epsilon || RuntimeUtility.RaycastIgnoreTag(
                    new Ray(lookAtPos, dir), out hitInfo2, d - PrecisionSlush,
                    m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
            {
                return(currentPos);
            }

            // All clear
            ray = new Ray(pos, dir);
            extra.AddPointToDebugPath(pos);
            distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);
            if (distance > Epsilon)
            {
                if (!RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo, distance,
                                                     m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
                {
                    pos = ray.GetPoint(distance); // no obstacles - all good
                    extra.AddPointToDebugPath(pos);
                }
                else
                {
                    // We hit something.  Stop there and maybe take a step along that wall
                    float adjustment = hitInfo.distance - PrecisionSlush;
                    pos = ray.GetPoint(adjustment);
                    extra.AddPointToDebugPath(pos);
                    if (iterations > 1)
                    {
                        pos = PushCameraBack(
                            pos, dir, hitInfo, lookAtPos, startPlane,
                            targetDistance, iterations - 1, ref extra);
                    }
                }
            }

            return(pos);
        }