示例#1
0
        /// <summary>
        /// Pulls an object from the pool.
        /// </summary>
        /// <returns></returns>
        public static BodyShapeHit Allocate(BodyShapeHit rInstance)
        {
            if (rInstance == null)
            {
                return(sPool.Allocate());
            }
            else
            {
                BodyShapeHit lInstance = sPool.Allocate();
                lInstance.Shape           = rInstance.Shape;
                lInstance.StartPosition   = rInstance.StartPosition;
                lInstance.EndPosition     = rInstance.EndPosition;
                lInstance.HitCollider     = rInstance.HitCollider;
                lInstance.HitOrigin       = rInstance.HitOrigin;
                lInstance.HitPoint        = rInstance.HitPoint;
                lInstance.HitNormal       = rInstance.HitNormal;
                lInstance.HitDistance     = rInstance.HitDistance;
                lInstance.HitRootDistance = rInstance.HitRootDistance;
                lInstance.HitPenetration  = rInstance.HitPenetration;
                lInstance.IsPlatformHit   = rInstance.IsPlatformHit;
                lInstance.Hit             = rInstance.Hit;

                return(lInstance);
            }
        }
        /// <summary>
        /// Checks if the shape currently overlaps any colliders
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Boolean that says if a hit occured or not</returns>
        public override List <BodyShapeHit> CollisionOverlap(Vector3 rPositionDelta, Quaternion rRotationDelta, int rLayerMask)
        {
            List <BodyShapeHit> lHits = new List <BodyShapeHit>();

            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _Offset) : _Transform.position + ((_Transform.rotation * rRotationDelta) * _Offset));
            Vector3 lBodyShapePos2 = rPositionDelta + (_EndTransform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _EndOffset) : _EndTransform.position + ((_EndTransform.rotation * rRotationDelta) * _EndOffset));
            Vector3 lPosition      = lBodyShapePos1 + ((lBodyShapePos2 - lBodyShapePos1) / 2f);

            float lOverlapRadius = (Vector3.Distance(lBodyShapePos1, lBodyShapePos2) / 2f) + _Radius;

            GeometryExt.Ignore = _Parent;

            Collider[] lColliders    = null;
            int        lColliderHits = RaycastExt.SafeOverlapSphere(lPosition, lOverlapRadius, out lColliders, rLayerMask, _Parent);

            for (int i = 0; i < lColliderHits; i++)
            {
                Transform lCurrentTransform = lColliders[i].transform;
                if (lCurrentTransform == _Transform)
                {
                    continue;
                }
                if (lCurrentTransform == _EndTransform)
                {
                    continue;
                }

                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(lColliders[i]))
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                Vector3 lLinePoint     = Vector3.zero;
                Vector3 lColliderPoint = Vector3.zero;
                GeometryExt.ClosestPoints(lBodyShapePos1, lBodyShapePos2, _Radius, lColliders[i], ref lLinePoint, ref lColliderPoint, rLayerMask);

                if (lLinePoint != Vector3Ext.Null && lColliderPoint != Vector3Ext.Null)
                {
                    float lDistance = Vector3.Distance(lLinePoint, lColliderPoint);
                    if (lDistance < _Radius + 0.001f)
                    {
                        BodyShapeHit lHit = BodyShapeHit.Allocate();
                        lHit.StartPosition = lBodyShapePos1;
                        lHit.EndPosition   = lBodyShapePos2;
                        lHit.HitCollider   = lColliders[i];
                        lHit.HitOrigin     = lLinePoint;
                        lHit.HitPoint      = lColliderPoint;
                        lHit.HitDistance   = lDistance - _Radius - 0.001f;

                        lHits.Add(lHit);
                    }
                }
            }

            GeometryExt.Ignore      = null;
            GeometryExt.IgnoreArray = null;

            return(lHits);
        }
示例#3
0
        /// <summary>
        /// Pulls an object from the pool.
        /// </summary>
        /// <returns></returns>
        public static BodyShapeHit Allocate()
        {
            // Grab the next available object
            BodyShapeHit lInstance = sPool.Allocate();

            // Return it
            return(lInstance);
        }
示例#4
0
        /// <summary>
        /// Checks if the shape currently overlaps any colliders
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Boolean that says if a hit occured or not</returns>
        public override List <BodyShapeHit> CollisionOverlap(Vector3 rPositionDelta, Quaternion rRotationDelta, int rLayerMask)
        {
            List <BodyShapeHit> lHits = new List <BodyShapeHit>();

            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _Offset) : _Transform.position + ((_Transform.rotation * rRotationDelta) * _Offset));

            Collider[] lColliders    = null;
            int        lColliderHits = RaycastExt.SafeOverlapSphere(lBodyShapePos1, _Radius, out lColliders, -1, _Parent);

            for (int i = 0; i < lColliderHits; i++)
            {
                if (lColliders[i].transform == _Transform)
                {
                    continue;
                }
                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(lColliders[i]))
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                Vector3 lLinePoint     = lBodyShapePos1;
                Vector3 lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, _Radius, lColliders[i]);

                float lDistance = Vector3.Distance(lLinePoint, lColliderPoint);
                if (lDistance < _Radius + 0.001f)
                {
                    BodyShapeHit lHit = BodyShapeHit.Allocate();
                    lHit.StartPosition = lBodyShapePos1;
                    lHit.HitCollider   = lColliders[i];
                    lHit.HitOrigin     = lLinePoint;
                    lHit.HitPoint      = lColliderPoint;
                    lHit.HitDistance   = lDistance - _Radius - 0.001f;

                    lHits.Add(lHit);
                }
            }

            return(lHits);
        }
示例#5
0
        /// <summary>
        /// Returns an element back to the pool.
        /// </summary>
        /// <param name="rEdge"></param>
        public static void Release(BodyShapeHit rInstance)
        {
            if (rInstance == null)
            {
                return;
            }

            // Clear the object
            rInstance.Shape          = null;
            rInstance.StartPosition  = Vector3.zero;
            rInstance.EndPosition    = Vector3.zero;
            rInstance.HitCollider    = null;
            rInstance.HitOrigin      = Vector3.zero;
            rInstance.HitPoint       = Vector3.zero;
            rInstance.HitNormal      = Vector3.zero;
            rInstance.HitDistance    = 0f;
            rInstance.HitPenetration = false;
            rInstance.Hit            = RaycastExt.EmptyHitInfo;

            // Allow it to be reused
            sPool.Release(rInstance);
        }
示例#6
0
        /// <summary>
        /// Casts out a shape to see if a collision will occur. The resulting array
        /// should NOT be persisted. It is re-used by this function over and over to
        /// reduce memory allocation.
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rDirection">Direction of the cast</param>
        /// <param name="rDistance">Distance of the case</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Returns an array of BodyShapeHit values representing all the hits that take place</returns>
        public override BodyShapeHit[] CollisionCastAll(Vector3 rPositionDelta, Vector3 rDirection, float rDistance, int rLayerMask)
        {
            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + (_Parent.rotation * _Offset) : _Transform.position + (_Transform.rotation * _Offset));

            // Clear any existing body shape hits. They are released by the calloer
            for (int i = 0; i < mBodyShapeHitArray.Length; i++)
            {
                mBodyShapeHitArray[i] = null;
            }

            // Use the non-allocating version if we can
            int lHitCount = 0;

#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
            mRaycastHitArray = UnityEngine.Physics.SphereCastAll(lBodyShapePos1, _Radius, rDirection, rDistance + EPSILON, rLayerMask);
            if (mRaycastHitArray != null)
            {
                lHitCount          = mRaycastHitArray.Length;
                mBodyShapeHitArray = new BodyShapeHit[lHitCount];
            }
#else
            lHitCount = UnityEngine.Physics.SphereCastNonAlloc(lBodyShapePos1, _Radius, rDirection, mRaycastHitArray, rDistance + EPSILON, rLayerMask, QueryTriggerInteraction.Ignore);
#endif

            int lBodyShapeHitsIndex = 0;
            for (int i = 0; i < lHitCount; i++)
            {
                if (mRaycastHitArray[i].collider.isTrigger)
                {
                    continue;
                }
                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(mRaycastHitArray[i].collider))
                {
                    continue;
                }

                Transform lCurrentTransform = mRaycastHitArray[i].collider.transform;
                if (lCurrentTransform == _Transform)
                {
                    continue;
                }

                // Ensure we're not colliding with a transform in our chain
                bool lIsValidHit = true;
                while (lCurrentTransform != null)
                {
                    if (lCurrentTransform == _Parent)
                    {
                        lIsValidHit = false;
                        break;
                    }

                    lCurrentTransform = lCurrentTransform.parent;
                }

                if (!lIsValidHit)
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                BodyShapeHit lBodyShapeHit = BodyShapeHit.Allocate();
                lBodyShapeHit.StartPosition = lBodyShapePos1;
                lBodyShapeHit.Shape         = this;
                lBodyShapeHit.Hit           = mRaycastHitArray[i];
                lBodyShapeHit.HitOrigin     = lBodyShapePos1;
                lBodyShapeHit.HitCollider   = mRaycastHitArray[i].collider;
                lBodyShapeHit.HitPoint      = mRaycastHitArray[i].point;
                lBodyShapeHit.HitNormal     = mRaycastHitArray[i].normal;

                // This distance is the distance between the surfaces and not the start!
                lBodyShapeHit.HitDistance = mRaycastHitArray[i].distance;

                // With the sphere cast all, we can recieve hits for colliders that
                // start by intruding on the sphere. In this case, the distance is "0". So,
                // we'll find the true distance ourselves.
                if (mRaycastHitArray[i].distance == 0f)
                {
                    Vector3 lColliderPoint = Vector3.zero;

                    //if (lBodyShapeHit.HitCollider is TerrainCollider)
                    //{
                    //    lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, rDirection * rDistance, _Radius, (TerrainCollider)lBodyShapeHit.HitCollider, rLayerMask);
                    //}
                    //else
                    //{
                    lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, _Radius, lBodyShapeHit.HitCollider, rLayerMask);
                    //}

                    // If we don't have a valid point, we will skip
                    if (lColliderPoint == Vector3.zero)
                    {
                        BodyShapeHit.Release(lBodyShapeHit);
                        continue;
                    }

                    // If the hit is further than our radius, we can skip
                    Vector3 lHitVector = lColliderPoint - lBodyShapePos1;
                    //if (lHitVector.magnitude > _Radius + EPSILON)
                    //{
                    //    BodyShapeHit.Release(lBodyShapeHit);
                    //    continue;
                    //}

                    // Setup the remaining info
                    lBodyShapeHit.HitOrigin = lBodyShapePos1;
                    lBodyShapeHit.HitPoint  = lColliderPoint;

                    // We want distance between the surfaces. We have the start point and
                    // surface collider point. So, we remove our radius to get to the surface.
                    lBodyShapeHit.HitDistance    = lHitVector.magnitude - _Radius;
                    lBodyShapeHit.HitPenetration = (lBodyShapeHit.HitDistance < 0f);

                    // Shoot a ray for the normal
                    RaycastHit lRaycastHitInfo;
                    if (RaycastExt.SafeRaycast(lBodyShapePos1, lHitVector.normalized, out lRaycastHitInfo, Mathf.Max(lBodyShapeHit.HitDistance + _Radius, _Radius + 0.01f)))
                    {
                        lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                    }
                    // If the ray is so close that we can't get a result we can end up here
                    else if (lBodyShapeHit.HitDistance < EPSILON)
                    {
                        lBodyShapeHit.HitNormal = (lBodyShapePos1 - lColliderPoint).normalized;
                    }
                }

                // Add the collision info
                if (lBodyShapeHit != null)
                {
                    // We can't really trust the hit normal we have since it probably came from an edge. So, we'll
                    // shoot a ray along our movement path. This will give us a better angle to look at. However, if we're
                    // falling (probably from gravity), we don't want to replace the edge value.
                    if (rDirection != Vector3.down)
                    {
                        RaycastHit lRaycastHitInfo;
                        if (RaycastExt.SafeRaycast(lBodyShapeHit.HitPoint - (rDirection * rDistance), rDirection, out lRaycastHitInfo, rDistance + _Radius, -1, _Parent))
                        {
                            lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                        }
                    }

                    // Store the distance between the hit point and our character's root
                    lBodyShapeHit.HitRootDistance = _Parent.InverseTransformPoint(lBodyShapeHit.HitPoint).y;

                    // Add the valid hit to our array
                    mBodyShapeHitArray[lBodyShapeHitsIndex] = lBodyShapeHit;
                    lBodyShapeHitsIndex++;
                }
            }

            // Return this array. The array should not be kept
            return(mBodyShapeHitArray);
        }
示例#7
0
        /// <summary>
        /// Casts out a shape to see if a collision will occur.
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rDirection">Direction of the cast</param>
        /// <param name="rDistance">Distance of the case</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Returns an array of BodyShapeHit values representing all the hits that take place</returns>
        public override BodyShapeHit[] CollisionCastAll(Vector3 rPositionDelta, Vector3 rDirection, float rDistance, int rLayerMask)
        {
            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + (_Parent.rotation * _Offset) : _Transform.position + (_Transform.rotation * _Offset));

            // Add the additional epsilon to the distance so we can get where we really want to test.
            RaycastHit[] lRaycastHits = UnityEngine.Physics.SphereCastAll(lBodyShapePos1, _Radius, rDirection, rDistance + EPSILON, rLayerMask);

            int lBodyShapeHitsIndex = 0;
            BodyShapeHit[] lBodyShapeHits = new BodyShapeHit[lRaycastHits.Length];
            for (int i = 0; i < lRaycastHits.Length; i++)
            {
                Transform lCurrentTransform = lRaycastHits[i].collider.transform;
                if (lCurrentTransform == _Transform) { continue; }

                // Ensure we're not colliding with a transform in our chain
                bool lIsValidHit = true;
                while (lCurrentTransform != null)
                {
                    if (lCurrentTransform == _Parent)
                    {
                        lIsValidHit = false;
                        break;
                    }

                    lCurrentTransform = lCurrentTransform.parent;
                }

                if (!lIsValidHit) { continue; }

                // Once we get here, we have a valid collider
                BodyShapeHit lBodyShapeHit = BodyShapeHit.Allocate();
                lBodyShapeHit.StartPosition = lBodyShapePos1;
                lBodyShapeHit.Shape = this;
                lBodyShapeHit.Hit = lRaycastHits[i];
                lBodyShapeHit.HitOrigin = lBodyShapePos1;
                lBodyShapeHit.HitCollider = lRaycastHits[i].collider;
                lBodyShapeHit.HitPoint = lRaycastHits[i].point;
                lBodyShapeHit.HitNormal = lRaycastHits[i].normal;

                // This distance is the distance between the surfaces and not the start!
                lBodyShapeHit.HitDistance = lRaycastHits[i].distance;

                // With the sphere cast all, we can recieve hits for colliders that
                // start by intruding on the sphere. In this case, the distance is "0". So,
                // we'll find the true distance ourselves.
                if (lRaycastHits[i].distance == 0f)
                {
                    Vector3 lColliderPoint = Vector3.zero;

                    if (lBodyShapeHit.HitCollider is TerrainCollider)
                    {
                        lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, rDirection * rDistance, _Radius, (TerrainCollider)lBodyShapeHit.HitCollider);
                    }
                    else
                    {
                        lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, _Radius, lBodyShapeHit.HitCollider);
                    }

                    // If we don't have a valid point, we will skip
                    if (lColliderPoint == Vector3.zero)
                    {
                        BodyShapeHit.Release(lBodyShapeHit);
                        continue;
                    }

                    // If the hit is further than our radius, we can skip
                    Vector3 lHitVector = lColliderPoint - lBodyShapePos1;
                    //if (lHitVector.magnitude > _Radius + EPSILON)
                    //{
                    //    BodyShapeHit.Release(lBodyShapeHit);
                    //    continue;
                    //}

                    // Setup the remaining info
                    lBodyShapeHit.HitOrigin = lBodyShapePos1;
                    lBodyShapeHit.HitPoint = lColliderPoint;

                    // We want distance between the surfaces. We have the start point and
                    // surface collider point. So, we remove our radius to get to the surface.
                    lBodyShapeHit.HitDistance = lHitVector.magnitude - _Radius;
                    lBodyShapeHit.HitPenetration = (lBodyShapeHit.HitDistance < 0f);

                    // Shoot a ray for the normal
                    RaycastHit lRaycastHitInfo;
                    if (RaycastExt.SafeRaycast(lBodyShapePos1, lHitVector.normalized, Mathf.Max(lBodyShapeHit.HitDistance + _Radius, _Radius + 0.01f), out lRaycastHitInfo))
                    {
                        lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                    }
                    // If the ray is so close that we can't get a result we can end up here
                    else if (lBodyShapeHit.HitDistance < EPSILON)
                    {
                        lBodyShapeHit.HitNormal = (lBodyShapePos1 - lColliderPoint).normalized;
                    }
                }

                // Add the collision info
                if (lBodyShapeHit != null)
                {
                    // We can't really trust the hit normal we have since it probably came from an edge. So, we'll
                    // shoot a ray along our movement path. This will give us a better angle to look at. However, if we're
                    // falling (probably from gravity), we don't want to replace the edge value.
                    if (rDirection != Vector3.down)
                    {
                        RaycastHit lRaycastHitInfo;
                        if (RaycastExt.SafeRaycast(lBodyShapeHit.HitPoint - (rDirection * rDistance), rDirection, rDistance + _Radius, _Parent, out lRaycastHitInfo))
                        {
                            lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                        }
                    }

                    // Store the distance between the hit point and our character's root
                    lBodyShapeHit.HitRootDistance = _Parent.InverseTransformPoint(lBodyShapeHit.HitPoint).y;

                    lBodyShapeHits[lBodyShapeHitsIndex]= lBodyShapeHit;
                    lBodyShapeHitsIndex++;
                }
            }

            return lBodyShapeHits;
        }
        /// <summary>
        /// Returns an element back to the pool.
        /// </summary>
        /// <param name="rEdge"></param>
        public static void Release(BodyShapeHit rInstance)
        {
            // Clear the object
            rInstance.Shape = null;
            rInstance.StartPosition = Vector3.zero;
            rInstance.EndPosition = Vector3.zero;
            rInstance.HitCollider = null;
            rInstance.HitOrigin = Vector3.zero;
            rInstance.HitPoint = Vector3.zero;
            rInstance.HitNormal = Vector3.zero;
            rInstance.HitDistance = 0f;
            rInstance.HitPenetration = false;
            rInstance.Hit = RaycastExt.EmptyHitInfo;

            // Allow it to be reused
            sPool.Release(rInstance);
        }