Пример #1
0
        //Checks our vertical collisions, and either stops us from moving or enables us to continue moving
        private void CheckVerticalCollisions(float velocityToCheck, bool isTranslatingDirectly = false)
        {
            if (!willStickToMovingPlatforms)
            {
                movingPlatform = null;
            }

            box = GetRectAtPosition(properties.position);

            Direction.Vertical direction = (velocityToCheck <= 0.0f) ? Direction.Vertical.Down : Direction.Vertical.Up;

            if (velocityToCheck == 0.0f)
            {
                return;
            }

            //The edge buffer prevents you from standing on a ledge with the very corner of your hitbox
            //This fixes problems where you jump straight up *next to* a ledge and the end up resting on the ledge itself on the way down
            float   edgeBuffer = 0.025f;
            Vector2 startPoint = new Vector2(box.xMin + edgeBuffer, box.center.y);
            Vector2 endPoint   = new Vector2(box.xMax - edgeBuffer, box.center.y);

            RaycastHit2D[] raycastHits = new RaycastHit2D[raycastAmounts.vertical];

            float rayLength      = box.height / 2.0f + (((properties.isGrounded && direction == Direction.Vertical.Down) || (properties.isAgainstCeiling && direction == Direction.Vertical.Up)) ? slopeDetectionMargin : Mathf.Abs(velocityToCheck));
            float lowestFraction = Mathf.Infinity;
            int   savedIndex     = 0;

            bool didCollide = false;

            for (int i = 0; i < raycastAmounts.vertical; i++)
            {
                float   raycastSpacing = (float)i / (float)(raycastAmounts.vertical - 1);
                Vector2 rayOrigin      = Vector2.Lerp(startPoint, endPoint, raycastSpacing);
                Vector2 rayDirection   = (direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up;
                //Debug.DrawRay(rayOrigin, rayDirection * rayLength, Color.red);

                int mask = ((direction == Direction.Vertical.Down && gravitySettings.gravityScale > 0.0f) || (direction == Direction.Vertical.Up && gravitySettings.gravityScale <= 0.0f)) ? collisionLayerMaskDown : collisionLayerMask;

                raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, mask);
                if (raycastHits[i].fraction > 0)
                {
                    didCollide = true;
                    if (raycastHits[i].fraction < lowestFraction)
                    {
                        savedIndex     = i;
                        lowestFraction = raycastHits[i].fraction;
                    }
                }
            }

            //This prevents you from walking off a one-way platform, holding left or right to be back inside it as you fall, and clipping back up on top of it
            if (didCollide && raycastHits[savedIndex].collider.gameObject.layer == LayerMask.NameToLayer("PassThroughBottom"))
            {
                float buffer = 0.1f;
                if ((gravitySettings.gravityScale > 0.0f && box.yMin < raycastHits[savedIndex].collider.bounds.max.y - buffer) || (gravitySettings.gravityScale <= 0.0f && box.yMax > raycastHits[savedIndex].collider.bounds.min.y + buffer))
                {
                    didCollide = false;
                }
            }

            //In rare instances, if the actor is already on top of a PassThroughBottom collider when they land on the ground, the above raycast can fail to detect the terrain; this is a failsafe
            if (!didCollide && raycastAmounts.enableRedundantVerticalCollisions)
            {
                int adjustedVerticalRaycasts = Mathf.CeilToInt(raycastAmounts.vertical * 0.5f);
                for (int i = 0; i < adjustedVerticalRaycasts; i++)
                {
                    float   raycastSpacing = (float)i / (float)(adjustedVerticalRaycasts - 1);
                    Vector2 rayOrigin      = Vector2.Lerp(startPoint, endPoint, raycastSpacing);
                    Vector2 rayDirection   = (direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up;
                    int     mask           = collisionLayerMask;
                    raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, mask);
                    if (raycastHits[i].fraction > 0)
                    {
                        didCollide = true;
                        if (raycastHits[i].fraction < lowestFraction)
                        {
                            savedIndex     = i;
                            lowestFraction = raycastHits[i].fraction;
                        }
                    }
                }
            }

            if (didCollide)
            {
                properties.velocity         = new Vector2(properties.velocity.x, 0);
                properties.externalVelocity = new Vector2(properties.externalVelocity.x, 0);

                if (direction == Direction.Vertical.Down)
                {
                    properties.isGrounded  = true;
                    willSnapToFloorOnStart = false;
                    properties.isFalling   = false;

                    properties.isAgainstCeiling = false;
                    properties.position        += Vector2.down * (raycastHits[savedIndex].fraction * rayLength - box.height / 2);

                    MovingPlatform platform = raycastHits[savedIndex].collider.GetComponent <MovingPlatform>();
                    if (platform != null)
                    {
                        movingPlatform = platform;
                        movingPlatform.NotifyOfObjectOnTop();
                    }
                    else
                    {
                        movingPlatform = null;
                    }
                }
                else
                {
                    if (willStickToMovingPlatforms)
                    {
                        MovingPlatform platform = raycastHits[savedIndex].collider.GetComponent <MovingPlatform>();
                        if (platform != null)
                        {
                            movingPlatform = platform;
                        }
                        else
                        {
                            movingPlatform = null;
                        }
                    }

                    properties.isAgainstCeiling = true;
                    if (gravitySettings.gravityScale > 0.0f)                    //Hit your head on the ceiling; stop your jump
                    {
                        properties.isFalling = true;
                    }
                    else
                    {
                        properties.isFalling = false;
                    }

                    properties.position += Vector2.up * (raycastHits[savedIndex].fraction * rayLength - box.height / 2);
                }

                if (DidLandThisFrame())
                {
                    if (gravitySettings.gravityScale >= 0.0f)
                    {
                        NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Bottom, RexObject.CollisionType.Enter);
                    }
                    else
                    {
                        NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Top, RexObject.CollisionType.Enter);
                    }
                }

                if (DidHitCeilingThisFrame())
                {
                    if (gravitySettings.gravityScale >= 0.0f)
                    {
                        NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Top, RexObject.CollisionType.Enter);
                    }
                    else
                    {
                        NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Bottom, RexObject.CollisionType.Enter);
                    }
                }
            }
            else
            {
                properties.isAgainstCeiling = false;
                properties.isGrounded       = false;

                if (isTranslatingDirectly)
                {
                    properties.position = new Vector2(transform.position.x, properties.position.y + velocityToCheck);
                }
            }
        }
Пример #2
0
        //Checks our horizontal collisions, and either stops us from moving or enables us to continue moving
        private void CheckHorizontalCollisions(float velocityToCheck, bool isTranslatingDirectly = false)
        {
            properties.isAgainstLeftWall  = false;
            properties.isAgainstRightWall = false;
            box = GetRectAtPosition(properties.position);
            if (velocityToCheck != 0)
            {
                //edgebuffer prevents unintended horizontal collisions with a MovingPlatform you're riding on top of
                float   edgeBuffer = (isTranslatingDirectly) ? 0.05f : 0.0f;
                Vector2 startPoint = new Vector2(box.center.x, box.center.y - box.height * 0.5f + edgeBuffer);
                Vector2 endPoint   = new Vector2(box.center.x, box.center.y + box.height * 0.5f);

                RaycastHit2D[] raycastHits        = new RaycastHit2D[raycastAmounts.horizontal];
                int            numberOfCollisions = 0;
                float          fraction           = 0;

                float   sideRayLength = box.width / 2 + Mathf.Abs(velocityToCheck);
                Vector2 direction     = (velocityToCheck) > 0 ? Vector2.right : -Vector2.right;
                bool    didCollide    = false;

                for (int i = 0; i < raycastAmounts.horizontal; i++)
                {
                    float   raycastSpacing = (float)i / (float)(raycastAmounts.horizontal - 1);
                    Vector2 rayOrigin;

                    if (i == 1 && !willStickToMovingPlatforms)
                    {
                        rayOrigin = Vector2.Lerp(startPoint, endPoint, ((float)(i - 1) / (float)(raycastAmounts.horizontal - 1)) + 0.005f);
                    }
                    else if (i == raycastAmounts.horizontal - 2 && !willStickToMovingPlatforms)
                    {
                        rayOrigin = Vector2.Lerp(startPoint, endPoint, ((float)(i + 1) / (float)(raycastAmounts.horizontal - 1)) - 0.005f);
                    }
                    else
                    {
                        rayOrigin = Vector2.Lerp(startPoint, endPoint, raycastSpacing);
                    }

                    raycastHits[i] = Physics2D.Raycast(rayOrigin, direction, sideRayLength, collisionLayerMask);
                    //Debug.DrawRay(rayOrigin, direction * sideRayLength, Color.red);

                    if (raycastHits[i].fraction > 0)
                    {
                        didCollide = true;
                        if (fraction > 0)
                        {
                            float slopeAngle = Vector2.Angle(raycastHits[i].point - raycastHits[i - 1].point, Vector2.right);
                            if (Mathf.Abs(slopeAngle - 90) < slopeAngleBuffer)                            //If the slope is too steep, treat it as a wall
                            {
                                if (direction == Vector2.right)
                                {
                                    properties.isAgainstRightWall = true;
                                }
                                else
                                {
                                    properties.isAgainstLeftWall = true;
                                }

                                if (willStickToMovingPlatforms)
                                {
                                    MovingPlatform platform = raycastHits[i].collider.GetComponent <MovingPlatform>();
                                    if (platform != null)
                                    {
                                        movingPlatform = platform;
                                    }
                                    else
                                    {
                                        movingPlatform = null;
                                    }
                                }

                                properties.position        += (direction * (raycastHits[i].fraction * sideRayLength - box.width / 2.0f));
                                properties.velocity         = new Vector2(0, properties.velocity.y);
                                properties.externalVelocity = new Vector2(0, properties.externalVelocity.y);

                                RexObject.Side side = (direction == Vector2.right) ? RexObject.Side.Right : RexObject.Side.Left;
                                if (side == RexObject.Side.Left && DidHitLeftWallThisFrame() && velocityToCheck < 0.0f)
                                {
                                    NotifyOfCollision(raycastHits[i].collider, RexObject.Side.Left, RexObject.CollisionType.Enter);
                                }
                                else if (side == RexObject.Side.Right && DidHitRightWallThisFrame() && velocityToCheck > 0.0f)
                                {
                                    NotifyOfCollision(raycastHits[i].collider, RexObject.Side.Right, RexObject.CollisionType.Enter);
                                }

                                break;
                            }
                        }

                        numberOfCollisions++;
                        fraction = raycastHits[i].fraction;
                    }

                    if (!didCollide && isTranslatingDirectly)
                    {
                        properties.position = new Vector2(transform.position.x + velocityToCheck, properties.position.y);
                    }
                }
            }
            else
            {
                CheckForWallContact(Direction.Horizontal.Left);
                CheckForWallContact(Direction.Horizontal.Right);
            }
        }