Пример #1
0
        /// <summary>
        /// Checks if the character size fits at a specific location.
        /// </summary>
        public bool CheckBodySize(Vector3 size, Vector3 position, HitInfoFilter hitInfoFilter)
        {
            Vector3 bottom = characterActor.GetBottomCenter(position, size);
            Vector3 top    = characterActor.GetTopCenter(position, size);
            float   radius = size.x / 2f - CharacterConstants.SkinWidth;

            // GetBottomCenterToTopCenter.normalized ---> Up

            Vector3 castDisplacement = characterActor.GetBottomCenterToTopCenter(size) + characterActor.Up * CharacterConstants.SkinWidth;

            HitInfo hitInfo;

            physicsComponent.SphereCast(
                out hitInfo,
                bottom,
                radius,
                castDisplacement,
                hitInfoFilter
                );


            bool overlap = hitInfo.hit;

            return(!overlap);
        }
Пример #2
0
        /// <summary>
        /// Forces the character to be grounded (isGrounded = true) if possible. The detection distance includes the step down distance.
        /// </summary>
        public void ForceGrounded()
        {
            HitInfoFilter filter = new HitInfoFilter(PhysicsComponent.CollisionLayerMask, false, true);

            CollisionInfo collisionInfo;
            bool          hit = characterCollisions.CheckForGround(
                out collisionInfo,
                Position,
                BodySize.y * 0.8f, // 80% of the height
                stepDownDistance,
                filter
                );



            if (hit)
            {
                ProcessNewGround(collisionInfo.hitInfo.transform, collisionInfo);

                float slopeAngle = Vector3.Angle(Up, GetGroundSlopeNormal(collisionInfo));

                if (slopeAngle <= slopeLimit)
                {
                    // Save the ground collision info
                    characterCollisionInfo.SetGroundInfo(collisionInfo, this);
                    Position += collisionInfo.displacement;
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Checks if the new character size fits in place. If this check is valid then the real size of the character is changed.
        /// </summary>
        public bool SetBodySize(Vector2 size)
        {
            HitInfoFilter filter = new HitInfoFilter(PhysicsComponent.CollisionLayerMask, true, true);

            if (!characterCollisions.CheckBodySize(size, Position, filter))
            {
                return(false);
            }

            targetBodySize = size;

            return(true);
        }
Пример #4
0
        void UpdateEdgeInfo(ref CollisionInfo collisionInfo, Vector3 position, HitInfoFilter hitInfoFilter)
        {
            Vector3 center = characterActor.GetBottomCenter(position, characterActor.StepOffset);

            Vector3 castDirection    = (collisionInfo.hitInfo.point - center).normalized;
            Vector3 castDisplacement = castDirection * CharacterConstants.EdgeRaysCastDistance;

            Vector3 upperHitPosition = center + characterActor.Up * CharacterConstants.EdgeRaysSeparation;
            Vector3 lowerHitPosition = center - characterActor.Up * CharacterConstants.EdgeRaysSeparation;

            HitInfo upperHitInfo;

            physicsComponent.Raycast(
                out upperHitInfo,
                upperHitPosition,
                castDisplacement,
                hitInfoFilter
                );


            HitInfo lowerHitInfo;

            physicsComponent.Raycast(
                out lowerHitInfo,
                lowerHitPosition,
                castDisplacement,
                hitInfoFilter
                );


            collisionInfo.edgeUpperNormal = upperHitInfo.normal;
            collisionInfo.edgeLowerNormal = lowerHitInfo.normal;

            collisionInfo.edgeUpperSlopeAngle = Vector3.Angle(collisionInfo.edgeUpperNormal, characterActor.Up);
            collisionInfo.edgeLowerSlopeAngle = Vector3.Angle(collisionInfo.edgeLowerNormal, characterActor.Up);

            collisionInfo.edgeAngle = Vector3.Angle(collisionInfo.edgeUpperNormal, collisionInfo.edgeLowerNormal);

            collisionInfo.isAnEdge = CustomUtilities.isBetween(collisionInfo.edgeAngle, CharacterConstants.MinEdgeAngle, CharacterConstants.MaxEdgeAngle, true);
            collisionInfo.isAStep  = CustomUtilities.isBetween(collisionInfo.edgeAngle, CharacterConstants.MinStepAngle, CharacterConstants.MaxStepAngle, true);
        }
Пример #5
0
        protected override void Awake()
        {
            base.Awake();

            ledgeHitInfoFilter = new HitInfoFilter(layerMask, true, true);
        }
Пример #6
0
        public void FireRaysArray(out RayArrayInfo rayArrayInfo, ref Vector3 position, float stepUpDistance, float stepDownDistance, HitInfoFilter hitInfoFilter)
        {
            int rings = 3;
            int rotationSubdivisions = 8;

            rayArrayInfo = new RayArrayInfo();

            int hits = 0;

            float   radius           = characterActor.BodySize.x / 2f - CharacterConstants.SkinWidth;
            float   skin             = stepUpDistance + CharacterConstants.SkinWidth;
            float   extraDistance    = Mathf.Max(CharacterConstants.GroundCheckDistance, stepDownDistance);
            Vector3 castDisplacement = -characterActor.Up * (skin + extraDistance);
            HitInfo hitInfo;

            float   deltaRotationAngle = 360f / rotationSubdivisions;
            float   deltaRadius        = radius / rings;
            Vector3 arrayOrigin        = position + characterActor.Up * skin;

            for (int i = 0; i < rings; i++)
            {
                if (i == 0)
                {
                    Vector3 origin = arrayOrigin;

                    physicsComponent.Raycast(
                        out hitInfo,
                        origin,
                        castDisplacement,
                        hitInfoFilter
                        );

                    if (hitInfo.hit)
                    {
                        hits++;
                        rayArrayInfo.averageDistance += hitInfo.distance;
                        rayArrayInfo.averageNormal   += hitInfo.normal;

                        // Debug.DrawLine( origin , hitInfo.point );
                    }
                }
                else
                {
                    Vector3 ray = characterActor.Forward * (i * deltaRadius);
                    for (int j = 0; j < rotationSubdivisions; j++)
                    {
                        ray = Quaternion.AngleAxis(j * deltaRotationAngle, characterActor.Up) * ray;
                        Vector3 origin = arrayOrigin + ray;

                        physicsComponent.Raycast(
                            out hitInfo,
                            origin,
                            castDisplacement,
                            hitInfoFilter
                            );

                        if (hitInfo.hit)
                        {
                            hits++;
                            rayArrayInfo.averageDistance += hitInfo.distance;
                            rayArrayInfo.averageNormal   += hitInfo.normal;

                            // Debug.DrawLine( origin , hitInfo.point );
                        }
                    }
                }
            }

            rayArrayInfo.averageDistance /= hits;
            rayArrayInfo.averageNormal.Normalize();


            position -= characterActor.Up * (rayArrayInfo.averageDistance - (stepUpDistance + CharacterConstants.SkinWidth));
        }
Пример #7
0
        /// <summary>
        /// Checks vertically for the ground using a Raycast.
        /// </summary>
        public bool CheckForGroundRay(out CollisionInfo collisionInfo, Vector3 position, float stepOffset, float stepDownDistance, HitInfoFilter hitInfoFilter)
        {
            collisionInfo = new CollisionInfo();

            float   skin             = stepOffset + CharacterConstants.SkinWidth + characterActor.BodySize.x;
            float   extraDistance    = Mathf.Max(CharacterConstants.GroundCheckDistance, stepDownDistance);
            Vector3 castDisplacement = -characterActor.Up * (skin + extraDistance);
            Vector3 origin           = characterActor.GetBottomCenter(position, stepOffset);

            HitInfo hitInfo;
            int     hits = physicsComponent.Raycast(
                out hitInfo,
                origin,
                castDisplacement,
                hitInfoFilter
                );

            UpdateCollisionInfo(out collisionInfo, position, hitInfo, castDisplacement, skin, false, hitInfoFilter);

            return(collisionInfo.collision);
        }
Пример #8
0
        void UpdateCollisionInfo(out CollisionInfo collisionInfo, Vector3 position, HitInfo hitInfo, Vector3 castDisplacement, float skin, bool calculateEdge = true, HitInfoFilter hitInfoFilter = new HitInfoFilter())
        {
            collisionInfo = new CollisionInfo();

            collisionInfo.collision = hitInfo.hit;

            if (collisionInfo.collision)
            {
                collisionInfo.displacement = castDisplacement.normalized * (hitInfo.distance - skin);

                collisionInfo.hitInfo           = hitInfo;
                collisionInfo.contactSlopeAngle = Vector3.Angle(characterActor.Up, hitInfo.normal);

                if (calculateEdge)
                {
                    UpdateEdgeInfo(ref collisionInfo, position, hitInfoFilter);
                }
            }
            else
            {
                collisionInfo.displacement = castDisplacement.normalized * (castDisplacement.magnitude - skin);
            }
        }
Пример #9
0
 /// <summary>
 /// Checks if the character size fits in place.
 /// </summary>
 public bool CheckBodySize(Vector3 size, HitInfoFilter hitInfoFilter)
 {
     return(CheckBodySize(size, characterActor.Position, hitInfoFilter));
 }
Пример #10
0
        /// <summary>
        /// Checks if the character is currently overlapping with any obstacle from a given layermask.
        /// </summary>
        public bool CheckOverlapWithLayerMask(Vector3 footPosition, float bottomOffset, HitInfoFilter hitInfoFilter)
        {
            Vector3 bottom = characterActor.GetBottomCenter(footPosition, bottomOffset);
            Vector3 top    = characterActor.GetTopCenter(footPosition);
            float   radius = characterActor.BodySize.x / 2f - CharacterConstants.SkinWidth;

            bool overlap = physicsComponent.OverlapCapsule(
                bottom,
                top,
                radius,
                hitInfoFilter
                );

            return(overlap);
        }
Пример #11
0
        public bool CastBodyVertically(out CollisionInfo collisionInfo, Vector3 position, float verticalComponent, float backstepDistance, HitInfoFilter hitInfoFilter, bool ignoreOverlaps)
        {
            collisionInfo = new CollisionInfo();

            float skin = backstepDistance + CharacterConstants.SkinWidth;

            Vector3 castDirection = verticalComponent > 0 ? characterActor.Up : -characterActor.Up;

            Vector3 center = verticalComponent > 0 ?
                             characterActor.GetTopCenter(position) - castDirection * skin :
                             characterActor.GetBottomCenter(position) - castDirection * skin;

            float   castMagnitude    = Mathf.Max(Mathf.Abs(verticalComponent) + skin, 0.02f);
            Vector3 castDisplacement = castDirection * castMagnitude;

            float minimumDistance = ignoreOverlaps ? backstepDistance : 0f;

            HitInfo hitInfo;
            int     hits = physicsComponent.SphereCast(
                out hitInfo,
                center,
                characterActor.BodySize.x / 2f - CharacterConstants.SkinWidth,
                castDisplacement,
                hitInfoFilter
                );

            UpdateCollisionInfo(out collisionInfo, position, hitInfo, castDisplacement, skin, true, hitInfoFilter);

            return(collisionInfo.collision);
        }
Пример #12
0
        public bool CastBody(out CollisionInfo collisionInfo, Vector3 position, Vector3 displacement, float bottomOffset, HitInfoFilter hitInfoFilter)
        {
            collisionInfo = new CollisionInfo();

            float backstepDistance = 0.1f;
            float skin             = CharacterConstants.SkinWidth + backstepDistance;

            Vector3 bottom = characterActor.GetBottomCenter(position, bottomOffset);
            Vector3 top    = characterActor.GetTopCenter(position);

            bottom -= displacement.normalized * backstepDistance;
            top    -= displacement.normalized * backstepDistance;

            float radius = characterActor.BodySize.x / 2f - CharacterConstants.SkinWidth;

            Vector3 castDisplacement = displacement + displacement.normalized * skin;

            HitInfo hitInfo;
            int     hits = 0;

            if (IsASphere)
            {
                hits = physicsComponent.SphereCast(
                    out hitInfo,
                    bottom,
                    radius,
                    castDisplacement,
                    hitInfoFilter
                    );
            }
            else
            {
                hits = physicsComponent.CapsuleCast(
                    out hitInfo,
                    bottom,
                    top,
                    radius,
                    castDisplacement,
                    hitInfoFilter
                    );
            }


            UpdateCollisionInfo(out collisionInfo, position, hitInfo, castDisplacement, skin, true, hitInfoFilter);

            return(collisionInfo.collision);
        }
Пример #13
0
        /// <summary>
        /// Checks for the ground.
        /// </summary>
        public bool CheckForStableGround(out CollisionInfo collisionInfo, Vector3 position, Vector3 direction, float stepOffset, HitInfoFilter hitInfoFilter)
        {
            collisionInfo = new CollisionInfo();


            Vector3 origin           = characterActor.GetBottomCenter(position);
            float   radius           = characterActor.BodySize.x / 2f - CharacterConstants.SkinWidth;
            float   skin             = CharacterConstants.SkinWidth;
            Vector3 castDisplacement = direction * (5f * CharacterConstants.GroundCheckDistance + skin + stepOffset);

            HitInfo hitInfo;
            int     hits = physicsComponent.SphereCast(
                out hitInfo,
                origin,
                radius,
                castDisplacement,
                hitInfoFilter
                );


            UpdateCollisionInfo(out collisionInfo, position, hitInfo, castDisplacement, skin, true, hitInfoFilter);

            return(collisionInfo.collision);
        }
Пример #14
0
        void ProbeGround(ref Vector3 position, float dt)
        {
            Vector3 preProbeGroundPosition = position;

            float groundCheckDistance = edgeCompensation ?
                                        BodySize.x / 2f + CharacterConstants.GroundCheckDistance :
                                        CharacterConstants.GroundCheckDistance;

            Vector3 displacement = -Up *Mathf.Max(groundCheckDistance, stepDownDistance);

            HitInfoFilter filter = new HitInfoFilter(PhysicsComponent.CollisionLayerMask, false, true);


            CollisionInfo collisionInfo;
            bool          hit = characterCollisions.CheckForGround(
                out collisionInfo,
                position,
                StepOffset,
                stepDownDistance,
                filter
                );

            if (hit)
            {
                float slopeAngle = Vector3.Angle(Up, GetGroundSlopeNormal(collisionInfo));

                if (slopeAngle <= slopeLimit)
                {
                    // Stable hit ---------------------------------------------------
                    ProcessNewGround(collisionInfo.hitInfo.transform, collisionInfo);

                    // Save the ground collision info
                    characterCollisionInfo.SetGroundInfo(collisionInfo, this);



                    // Calculate the final position
                    position += collisionInfo.displacement;


                    if (edgeCompensation && IsAStableEdge(collisionInfo))
                    {
                        // calculate the edge compensation and apply that to the final position
                        Vector3 compensation = Vector3.Project((collisionInfo.hitInfo.point - position), Up);
                        position += compensation;
                    }

                    stableProbeGroundVelocity = (position - preProbeGroundPosition) / dt;
                }
                else
                {
                    // Unstable Hit

                    // If the unstable ground is far enough then force not grounded
                    float castSkinDistance = StepOffset + 2f * CharacterConstants.SkinWidth;
                    if (collisionInfo.hitInfo.distance > castSkinDistance)
                    {
                        ForceNotGrounded();
                        return;
                    }


                    if (preventBadSteps)
                    {
                        // If the unstable ground is close enough then do a new collide and slide
                        if (WasGrounded)
                        {
                            position = Position;

                            Vector3 unstableDisplacement = CustomUtilities.ProjectVectorOnPlane(
                                Velocity * dt,
                                GroundStableNormal,
                                Up
                                );

                            CollideAndSlide(ref position, unstableDisplacement, true);
                        }
                    }


                    characterCollisions.CheckForGroundRay(
                        out collisionInfo,
                        position,
                        StepOffset,
                        stepDownDistance,
                        filter
                        );

                    ProcessNewGround(collisionInfo.hitInfo.transform, collisionInfo);

                    characterCollisionInfo.SetGroundInfo(collisionInfo, this);
                    Debug.DrawRay(collisionInfo.hitInfo.point, collisionInfo.hitInfo.normal);
                    stableProbeGroundVelocity = (position - preProbeGroundPosition) / dt;
                }
            }
            else
            {
                ForceNotGrounded();
            }
        }
        public void CollideAndSlide(ref Vector3 position, Vector3 displacement, bool useFullBody)
        {
            Vector3 groundPlaneNormal  = GroundStableNormal;
            Vector3 slidingPlaneNormal = Vector3.zero;

            HitInfoFilter filter = new HitInfoFilter(
                PhysicsComponent.CollisionLayerMask,
                false,
                true
                );

            int iteration = 0;


            while (iteration < CharacterConstants.MaxSlideIterations)
            {
                iteration++;

                CollisionInfo collisionInfo;
                bool          hit = characterCollisions.CastBody(
                    out collisionInfo,
                    position,
                    displacement,
                    useFullBody ? 0f : StepOffset,
                    filter
                    );


                if (hit)
                {
                    //---
                    if (canPushDynamicRigidbodies)
                    {
                        if (collisionInfo.hitInfo.IsRigidbody)
                        {
                            if (!collisionInfo.hitInfo.IsKinematicRigidbody)
                            {
                                bool canPushThisObject = CustomUtilities.BelongsToLayerMask(collisionInfo.hitInfo.transform.gameObject.layer, pushableRigidbodyLayerMask);
                                if (canPushThisObject)
                                {
                                    // Use the entire displacement and stop the collide and slide
                                    position += displacement;
                                    break;
                                }
                            }
                        }
                    }


                    if (slideOnWalls)
                    {
                        position     += collisionInfo.displacement;
                        displacement -= collisionInfo.displacement;

                        // Get the new slide plane
                        bool blocked = UpdateSlidingPlanes(
                            collisionInfo,
                            ref slidingPlaneNormal,
                            ref groundPlaneNormal,
                            ref displacement
                            );
                    }
                    else
                    {
                        if (!WallCollision)
                        {
                            position += collisionInfo.displacement;
                        }

                        break;
                    }
                }
                else
                {
                    position += displacement;
                    break;
                }
            }
        }
        public void CollideAndSlideUnstable(ref Vector3 position, Vector3 displacement)
        {
            HitInfoFilter filter = new HitInfoFilter(
                PhysicsComponent.CollisionLayerMask,
                false,
                true
                );

            int iteration = 0;

            while (iteration < CharacterConstants.MaxSlideIterations || displacement == Vector3.zero)
            {
                iteration++;

                CollisionInfo collisionInfo;
                bool          hit = characterCollisions.CastBody(
                    out collisionInfo,
                    position,
                    displacement,
                    0f,
                    filter
                    );


                if (hit)
                {
                    position += collisionInfo.displacement;

                    if (canPushDynamicRigidbodies)
                    {
                        if (collisionInfo.hitInfo.IsRigidbody)
                        {
                            if (!collisionInfo.hitInfo.IsKinematicRigidbody)
                            {
                                Vector3 remainingVelocity = displacement - collisionInfo.displacement;
                                Vector3 force             = CharacterBody.Mass * (remainingVelocity / Time.deltaTime);

                                collisionInfo.hitInfo.rigidbody3D.AddForceAtPosition(force, position);
                            }
                        }
                    }

                    displacement -= collisionInfo.displacement;

                    displacement = Vector3.ProjectOnPlane(displacement, collisionInfo.hitInfo.normal);
                }
                else
                {
                    position += displacement;
                    break;
                }
            }


            if (!alwaysNotGrounded && forceNotGroundedFrames == 0)
            {
                CollisionInfo groundCheckCollisionInfo;
                characterCollisions.CheckForGround(
                    out groundCheckCollisionInfo,
                    position,
                    stepUpDistance,
                    CharacterConstants.GroundPredictionDistance,
                    filter
                    );

                if (groundCheckCollisionInfo.collision)
                {
                    PredictedGround         = groundCheckCollisionInfo.hitInfo.transform.gameObject;
                    PredictedGroundDistance = groundCheckCollisionInfo.displacement.magnitude;

                    bool validGround = PredictedGroundDistance <= CharacterConstants.GroundCheckDistance;

                    if (validGround)
                    {
                        ProcessNewGround(groundCheckCollisionInfo.hitInfo.transform, groundCheckCollisionInfo);
                        characterCollisionInfo.SetGroundInfo(groundCheckCollisionInfo, this);
                    }
                    else
                    {
                        characterCollisionInfo.ResetGroundInfo();
                    }
                }
                else
                {
                    PredictedGround         = null;
                    PredictedGroundDistance = 0f;

                    characterCollisionInfo.ResetGroundInfo();
                }
            }
        }