예제 #1
0
    void moveVertically(ref FixVec2 deltaMovement)
    {
        var isGoingUp        = deltaMovement.y > 0;
        var rayDistance      = FixMath.Abs(deltaMovement.y) + _skinWidth;
        var rayDirection     = isGoingUp ? FixVec2.up : -FixVec2.up;
        var initialRayOrigin = isGoingUp ? _raycastOrigins.topLeft : _raycastOrigins.bottomLeft;

        // apply our horizontal deltaMovement here so that we do our raycast from the actual position we would be in if we had moved
        initialRayOrigin.x += deltaMovement.x;

        // if we are moving up, we should ignore the layers in oneWayPlatformMask
        var mask = platformMask;

        if ((isGoingUp && !collisionState.wasGroundedLastFrame) || ignoreOneWayPlatformsThisFrame)
        {
            mask &= ~oneWayPlatformMask;
        }

        for (var i = 0; i < totalVerticalRays; i++)
        {
            FixVec2 ray = new FixVec2(initialRayOrigin.x + i * _horizontalDistanceBetweenRays, initialRayOrigin.y);

            DrawRay((Vector3)ray, (Vector3)(rayDirection * rayDistance), Color.red);
            _raycastHit = TFPhysics.Raycast(ray, rayDirection, rayDistance, mask);
            if (_raycastHit)
            {
                // set our new deltaMovement and recalculate the rayDistance taking it into account
                deltaMovement.y = _raycastHit.point.y - ray.y;
                rayDistance     = FixMath.Abs(deltaMovement.y);

                // remember to remove the skinWidth from our deltaMovement
                if (isGoingUp)
                {
                    deltaMovement.y     -= _skinWidth;
                    collisionState.above = true;
                }
                else
                {
                    deltaMovement.y     += _skinWidth;
                    collisionState.below = true;
                }

                _raycastHitsThisFrame.Add(_raycastHit);

                // this is a hack to deal with the top of slopes. if we walk up a slope and reach the apex we can get in a situation
                // where our ray gets a hit that is less then skinWidth causing us to be ungrounded the next frame due to residual velocity.
                if (!isGoingUp && deltaMovement.y > Fix.zero)
                {
                    _isGoingUpSlope = true;
                }

                // we add a small fudge factor for the float operations here. if our rayDistance is smaller
                // than the width + fudge bail out because we have a direct impact
                if (rayDistance < _skinWidth + kSkinWidthFloatFudgeFactor)
                {
                    break;
                }
            }
        }
    }
예제 #2
0
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var v3 = Input.mousePosition;
            v3.z = 0;
            v3   = Camera.main.ScreenToWorldPoint(v3);

            FixVec2 pointB = new FixVec2((Fix)v3.x, (Fix)v3.y);

            TFRaycastHit2D h = TFPhysics.Raycast((FixVec2)tfTransform.Position, (FixVec2)(pointB - tfTransform.Position).Normalized(), 5, platformMask);
        }
    }
예제 #3
0
    /// <summary>
    /// checks the center point under the BoxCollider2D for a slope. If it finds one then the deltaMovement is adjusted so that
    /// the player stays grounded and the slopeSpeedModifier is taken into account to speed up movement.
    /// </summary>
    /// <param name="deltaMovement">Delta movement.</param>
    private void handleVerticalSlope(ref FixVec2 deltaMovement)
    {
        // slope check from the center of our collider
        Fix     centerOfCollider = (_raycastOrigins.bottomLeft.x + _raycastOrigins.bottomRight.x) * (Fix.one / 2);
        FixVec2 rayDirection     = -FixVec2.up;

        // the ray distance is based on our slopeLimit
        Fix slopeCheckRayDistance = _slopeLimitTangent * (_raycastOrigins.bottomRight.x - centerOfCollider);

        FixVec2 slopeRay = new FixVec2(centerOfCollider, _raycastOrigins.bottomLeft.y);

        _raycastHit = TFPhysics.Raycast(slopeRay, rayDirection, slopeCheckRayDistance, platformMask);
        if (_raycastHit)
        {
            // bail out if we have no slope
            var angle = FixVec2.Angle(_raycastHit.normal, FixVec2.up);
            if (angle == 0)
            {
                return;
            }

            // we are moving down the slope if our normal and movement direction are in the same x direction
            var isMovingDownSlope = FixMath.Sign(_raycastHit.normal.x) == FixMath.Sign(deltaMovement.x);
            if (isMovingDownSlope)
            {
                // going down we want to speed up in most cases so the slopeSpeedMultiplier curve should be > 1 for negative angles
                Fix slopeModifier = (Fix)slopeSpeedMultiplier.Evaluate((float)-angle);
                // we add the extra downward movement here to ensure we "stick" to the surface below
                deltaMovement.y += _raycastHit.point.y - slopeRay.y - skinWidth;
                deltaMovement    = new FixVec2(deltaMovement.x, deltaMovement.y)
                                   + new FixVec2(deltaMovement.x * slopeModifier * (1 - (angle / 90)), (deltaMovement.x * slopeModifier * (angle / 90)));
                collisionState.movingDownSlope = true;
                collisionState.slopeAngle      = angle;
            }
        }
    }
예제 #4
0
    /// <summary>
    /// handles adjusting deltaMovement if we are going up a slope.
    /// </summary>
    /// <returns><c>true</c>, if horizontal slope was handled, <c>false</c> otherwise.</returns>
    /// <param name="deltaMovement">Delta movement.</param>
    /// <param name="angle">Angle.</param>
    bool handleHorizontalSlope(ref FixVec2 deltaMovement, Fix angle)
    {
        // disregard 90 degree angles (walls)
        if (FixMath.Round(angle) == 90)
        {
            return(false);
        }

        if (angle < slopeLimit)
        {
            // we only need to adjust the deltaMovement if we are not jumping
            // TODO: this uses a magic number which isn't ideal! The alternative is to have the user pass in if there is a jump this frame
            if (deltaMovement.y < jumpingThreshold)
            {
                // apply the slopeModifier to slow our movement up the slope
                Fix slopeModifier = (Fix)slopeSpeedMultiplier.Evaluate((float)angle);
                deltaMovement.x *= slopeModifier;

                // we dont set collisions on the sides for this since a slope is not technically a side collision.
                // smooth y movement when we climb. we make the y movement equivalent to the actual y location that corresponds
                // to our new x location using our good friend Pythagoras
                deltaMovement.y = FixMath.Abs(FixMath.Tan(angle * FixMath.Deg2Rad) * deltaMovement.x);
                var isGoingRight = deltaMovement.x > 0;

                // safety check. we fire a ray in the direction of movement just in case the diagonal we calculated above ends up
                // going through a wall. if the ray hits, we back off the horizontal movement to stay in bounds.
                var            ray = isGoingRight ? _raycastOrigins.bottomRight : _raycastOrigins.bottomLeft;
                TFRaycastHit2D raycastHit;
                if (collisionState.wasGroundedLastFrame)
                {
                    raycastHit = TFPhysics.Raycast((FixVec2)ray, (FixVec2)deltaMovement.Normalized(), deltaMovement.GetMagnitude(), platformMask);
                }
                else
                {
                    raycastHit = TFPhysics.Raycast((FixVec2)ray, (FixVec2)deltaMovement.Normalized(), deltaMovement.GetMagnitude(), platformMask & ~oneWayPlatformMask);
                }

                if (raycastHit)
                {
                    // we crossed an edge when using Pythagoras calculation, so we set the actual delta movement to the ray hit location
                    deltaMovement = raycastHit.point - ray;
                    if (isGoingRight)
                    {
                        deltaMovement.x -= _skinWidth;
                    }
                    else
                    {
                        deltaMovement.x += _skinWidth;
                    }
                }

                _isGoingUpSlope           = true;
                collisionState.below      = true;
                collisionState.slopeAngle = -angle;
            }
        }
        else // too steep. get out of here
        {
            deltaMovement.x = Fix.zero;
        }

        return(true);
    }
예제 #5
0
    /// <summary>
    /// we have to use a bit of trickery in this one. The rays must be cast from a small distance inside of our
    /// collider (skinWidth) to avoid zero distance rays which will get the wrong normal. Because of this small offset
    /// we have to increase the ray distance skinWidth then remember to remove skinWidth from deltaMovement before
    /// actually moving the player
    /// </summary>
    void moveHorizontally(ref FixVec2 deltaMovement)
    {
        var isGoingRight     = deltaMovement.x > 0;
        var rayDistance      = FixMath.Abs(deltaMovement.x) + _skinWidth;
        var rayDirection     = isGoingRight ? FixVec2.right : -FixVec2.right;
        var initialRayOrigin = isGoingRight ? _raycastOrigins.bottomRight : _raycastOrigins.bottomLeft;

        for (var i = 0; i < totalHorizontalRays; i++)
        {
            var ray = new FixVec2(initialRayOrigin.x, initialRayOrigin.y + i * _verticalDistanceBetweenRays);

            // if we are grounded we will include oneWayPlatforms only on the first ray (the bottom one). this will allow us to
            // walk up sloped oneWayPlatforms.
            if (i == 0 && collisionState.wasGroundedLastFrame)
            {
                _raycastHit = TFPhysics.Raycast(ray, rayDirection, rayDistance, platformMask);
            }
            else
            {
                _raycastHit = TFPhysics.Raycast(ray, rayDirection, rayDistance, platformMask & ~oneWayPlatformMask);
            }

            if (_raycastHit)
            {
                // the bottom ray can hit a slope but no other ray can so we have special handling for these cases
                if (i == 0 && handleHorizontalSlope(ref deltaMovement, FixVec2.Angle(_raycastHit.normal, FixVec2.up)))
                {
                    _raycastHitsThisFrame.Add(_raycastHit);
                    // if we weren't grounded last frame, that means we're landing on a slope horizontally.
                    // this ensures that we stay flush to that slope
                    if (!collisionState.wasGroundedLastFrame)
                    {
                        Fix flushDistance = FixMath.Sign(deltaMovement.x) * (_raycastHit.distance - skinWidth);
                        tfTransform.Position += new FixVec2(flushDistance, 0);
                    }
                    break;
                }

                // set our new deltaMovement and recalculate the rayDistance taking it into account
                deltaMovement.x = _raycastHit.point.x - ray.x;
                rayDistance     = FixMath.Abs(deltaMovement.x);

                // remember to remove the skinWidth from our deltaMovement
                if (isGoingRight)
                {
                    deltaMovement.x     -= _skinWidth;
                    collisionState.right = true;
                }
                else
                {
                    deltaMovement.x    += _skinWidth;
                    collisionState.left = true;
                }

                _raycastHitsThisFrame.Add(_raycastHit);

                // we add a small fudge factor for the float operations here. if our rayDistance is smaller
                // than the width + fudge bail out because we have a direct impact
                if (rayDistance < _skinWidth + kSkinWidthFloatFudgeFactor)
                {
                    break;
                }
            }
        }
    }