Ejemplo n.º 1
0
        float GetSubmergedHeight(Collidable info, float maxLength, float boundingBoxHeight, ref Vector3 rayOrigin, ref Vector3 xSpacing, ref Vector3 zSpacing, int i, int j, out Vector3 volumeCenter)
        {
            Ray ray;

            Vector3.Multiply(ref xSpacing, i, out ray.Position);
            Vector3.Multiply(ref zSpacing, j, out ray.Direction);
            Vector3.Add(ref ray.Position, ref ray.Direction, out ray.Position);
            Vector3.Add(ref ray.Position, ref rayOrigin, out ray.Position);
            ray.Direction = upVector;
            //do a bottom-up raycast.
            RayHit rayHit;

            //Only go up to maxLength.  If it's further away than maxLength, then it's above the water and it doesn't contribute anything.
            if (info.RayCast(ray, maxLength, out rayHit))
            {
                //Position the ray to point from the other side.
                Vector3.Multiply(ref ray.Direction, boundingBoxHeight, out ray.Direction);
                Vector3.Add(ref ray.Position, ref ray.Direction, out ray.Position);
                Vector3.Negate(ref upVector, out ray.Direction);
                float   bottomY        = rayHit.Location.Y;
                float   bottom         = rayHit.T;
                Vector3 bottomPosition = rayHit.Location;
                if (info.RayCast(ray, boundingBoxHeight - rayHit.T, out rayHit))
                {
                    Vector3.Add(ref rayHit.Location, ref bottomPosition, out volumeCenter);
                    Vector3.Multiply(ref volumeCenter, .5f, out volumeCenter);
                    return(Math.Min(surfacePlaneHeight - bottomY, boundingBoxHeight - rayHit.T - bottom));
                }
                //This inner raycast should always hit, but just in case it doesn't due to some numerical problem, give it a graceful way out.
                volumeCenter = Vector3.Zero;
                return(0);
            }
            volumeCenter = Vector3.Zero;
            return(0);
        }
        /// <summary>
        /// Locates the closest support entity by performing a raycast at collected candidates.
        /// </summary>
        /// <param name="supportEntity">The closest supporting entity.</param>
        /// <param name="supportLocation">The support location where the ray hit the entity.</param>
        /// <param name="supportNormal">The normal at the surface where the ray hit the entity.</param>
        /// <param name="supportDistance">Distance from the character to the support location.</param>
        /// <returns>Whether or not a support was located.</returns>
        private bool FindSupport(out BEPUphysics.Entities.Entity supportEntity, out Vector3 supportLocation, out Vector3 supportNormal, out float supportDistance)
        {
            supportEntity   = null;
            supportLocation = Toolbox.NoVector;
            supportNormal   = Toolbox.NoVector;
            supportDistance = float.MaxValue;

            Vector3 rayOrigin = Body.Position + rayOriginOffset;

            for (int i = 0; i < collisionPairCollector.CollisionInformation.Pairs.Count; i++)
            {
                var pair = collisionPairCollector.CollisionInformation.Pairs[i];
                //Determine which member of the collision pair is the possible support.
                Collidable candidate = (pair.BroadPhaseOverlap.EntryA == collisionPairCollector.CollisionInformation ? pair.BroadPhaseOverlap.EntryB : pair.BroadPhaseOverlap.EntryA) as Collidable;
                //Ensure that the candidate is a valid supporting entity.
                if (candidate.CollisionRules.Personal >= CollisionRule.NoSolver)
                {
                    continue; //It is invalid!
                }
                //The maximum length is supportHeight * 2 instead of supportHeight alone because the character should be able to step downwards.
                //This acts like a sort of 'glue' to help the character stick on the ground in general.
                float maximumDistance;
                //The 'glue' effect should only occur if the character has a solid hold on the ground though.
                //Otherwise, the character is falling or sliding around uncontrollably.
                if (HasTraction)
                {
                    maximumDistance = supportHeight * 2;
                }
                else
                {
                    maximumDistance = supportHeight;
                }

                RayHit rayHit;
                //Fire a ray at the candidate and determine some details!
                if (candidate.RayCast(new Ray(rayOrigin, Vector3.Down), maximumDistance, out rayHit))
                {
                    //We want to find the closest support, so compare it against the last closest support.
                    if (rayHit.T < supportDistance)
                    {
                        supportDistance = rayHit.T;
                        supportLocation = rayHit.Location;
                        supportNormal   = rayHit.T > 0 ? rayHit.Normal : Vector3.Up;

                        var entityInfo = candidate as EntityCollidable;
                        if (entityInfo != null)
                        {
                            supportEntity = entityInfo.Entity;
                        }
                        else
                        {
                            supportEntity = null;
                        }
                    }
                }
            }
            supportNormal.Normalize();
            return(supportDistance < float.MaxValue);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Locates the closest support entity by performing a raycast at collected candidates.
        /// </summary>
        /// <param name="supportEntity">The closest supporting entity.</param>
        /// <param name="supportLocation">The support location where the ray hit the entity.</param>
        /// <param name="supportNormal">The normal at the surface where the ray hit the entity.</param>
        /// <param name="supportDistance">Distance from the character to the support location.</param>
        /// <returns>Whether or not a support was located.</returns>
        private bool findSupport(out object supportEntityTag, out BEPUphysics.Entities.Entity supportEntity, out Vector3 supportLocation, out Vector3 supportNormal, out float supportDistance)
        {
            supportEntity    = null;
            supportEntityTag = null;
            supportLocation  = BEPUutilities.Toolbox.NoVector;
            supportNormal    = BEPUutilities.Toolbox.NoVector;
            supportDistance  = float.MaxValue;

            const float fudgeFactor = 0.1f;
            Vector3     rayOrigin   = this.Body.Position;

            rayOrigin.Y += fudgeFactor + this.Height * -0.5f;

            for (int i = 0; i < this.collisionPairCollector.CollisionInformation.Pairs.Count; i++)
            {
                var pair = this.collisionPairCollector.CollisionInformation.Pairs[i];
                //Determine which member of the collision pair is the possible support.
                Collidable candidate = (pair.BroadPhaseOverlap.EntryA == collisionPairCollector.CollisionInformation ? pair.BroadPhaseOverlap.EntryB : pair.BroadPhaseOverlap.EntryA) as Collidable;
                //Ensure that the candidate is a valid supporting entity.
                if (candidate.CollisionRules.Personal >= CollisionRule.NoSolver)
                {
                    continue;                     //It is invalid!
                }
                if (candidate.CollisionRules.Group == Character.NoCollideGroup)
                {
                    continue;
                }

                //The maximum length is supportHeight * 2 instead of supportHeight alone because the character should be able to step downwards.
                //This acts like a sort of 'glue' to help the character stick on the ground in general.
                float maximumDistance;
                //The 'glue' effect should only occur if the character has a solid hold on the ground though.
                //Otherwise, the character is falling or sliding around uncontrollably.
                if (this.HasTraction && !this.IsSwimming)
                {
                    maximumDistance = fudgeFactor + (this.SupportHeight * 2.0f);
                }
                else
                {
                    maximumDistance = fudgeFactor + this.SupportHeight;
                }

                foreach (Vector3 rayStart in this.rayOffsets.Select(x => x + rayOrigin))
                {
                    BEPUutilities.RayHit rayHit;
                    // Fire a ray at the candidate and determine some details!
                    if (candidate.RayCast(new Ray(rayStart, Vector3.Down), maximumDistance, out rayHit))
                    {
                        Vector3 n = Vector3.Normalize(rayHit.Normal);

                        if (n.Y > supportNormal.Y)
                        {
                            supportNormal = n;
                        }

                        // We want to find the closest support, so compare it against the last closest support.
                        if (rayHit.T < supportDistance && n.Y > 0.25f)
                        {
                            supportDistance = rayHit.T - fudgeFactor;
                            supportLocation = rayHit.Location;
                            if (rayHit.T < 0.0f)
                            {
                                supportNormal = Vector3.Up;
                            }

                            var entityInfo = candidate as EntityCollidable;
                            if (entityInfo != null)
                            {
                                supportEntity    = entityInfo.Entity;
                                supportEntityTag = supportEntity != null ? supportEntity.Tag : candidate.Tag;
                            }
                            else
                            {
                                supportEntityTag = candidate.Tag;
                            }
                        }
                    }
                }
            }

            bool isSupported = supportDistance < float.MaxValue;

            return(isSupported);
        }