protected static SteeringVelocity DoReachOrientation(Entity <Game> owner, Fix targetOrientation)
        {
            var tolerance    = owner.Get <AlignTolerance>();
            var steering     = SteeringVelocity.Zero;
            var orientation  = owner.Get <Orientation>().Value;
            var rotation     = ArithmeticUtils.WrapAngleAroundZero(targetOrientation - orientation);
            var rotationSize = FixMath.Abs(rotation);

            if (rotationSize <= tolerance.Angle)
            {
                return(steering);
            }

            var maxAngularVelocity = owner.Get <MaxAngularVelocity>().Value;
            var angular            = maxAngularVelocity * rotation / rotationSize;
            var decelerationAngle  = tolerance.DecelerationAngle;

            if (rotationSize <= decelerationAngle)
            {
                angular *= rotationSize / decelerationAngle;
            }

            steering.Angular = angular;

            return(steering);
        }
Exemplo n.º 2
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;
                }
            }
        }
    }
Exemplo n.º 3
0
        public Mat22 Abs()
        {
            Mat22 m = new Mat22();

            m.m00 = FixMath.Abs(m00);
            m.m01 = FixMath.Abs(m01);
            m.m10 = FixMath.Abs(m10);
            m.m11 = FixMath.Abs(m11);
            return(m);
        }
Exemplo n.º 4
0
        /// Wrap a vector to a bounding box.
        public static FixVec2 WrapVect(AABB aabb, FixVec2 v)
        {
            // wrap a vector to a bbox
            var ix   = FixMath.Abs(aabb.R - aabb.L);
            var modx = (v.X - aabb.L) % ix;
            var x    = (modx > 0) ? modx : modx + ix;

            var iy   = FixMath.Abs(aabb.T - aabb.B);
            var mody = (v.Y - aabb.B) % iy;
            var y    = (mody > 0) ? mody : mody + iy;

            return(new FixVec2(x + aabb.L, y + aabb.B));
        }
Exemplo n.º 5
0
    /// <summary>
    /// this should be called anytime you have to modify the BoxCollider2D at runtime. It will recalculate the distance between the rays used for collision detection.
    /// It is also used in the skinWidth setter in case it is changed at runtime.
    /// </summary>
    public void recalculateDistanceBetweenRays()
    {
        FixVec2 size = boxCollider.Size;
        // figure out the distance between our rays in both directions
        // horizontal
        var colliderUseableHeight = size.y * FixMath.Abs(tfTransform.LocalScale.y) - (2 * _skinWidth);

        _verticalDistanceBetweenRays = colliderUseableHeight / (totalHorizontalRays - Fix.one);

        // vertical
        var colliderUseableWidth = size.x * FixMath.Abs(tfTransform.LocalScale.x) - (2 * _skinWidth);

        _horizontalDistanceBetweenRays = colliderUseableWidth / (totalVerticalRays - Fix.one);
    }
Exemplo n.º 6
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 FixVec3 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.
        }
    }
        public bool CheckInterrupt()
        {
            GameInfo gi = cController.cacheGM.gameInfo;

            if (cController.CheckForAttack())
            {
                return(true);
            }
            else if (FixMath.Abs(cInput.LeftStick().axis.X) >= gi.walkSensitivity)
            {
                cController.ChangeState("Walk");
                return(true);
            }
            return(false);
        }
        public void OnUpdate()
        {
            if (!CheckInterrupt())
            {
                float perc = (float)((FixMath.Abs(cInput.LeftStick().axis.X) - cController.cacheGM.gameInfo.walkSensitivity) / (Fix.One - cController.cacheGM.gameInfo.walkSensitivity));

                Vector2 wantedSpeed = new Vector2();
                wantedSpeed.x = (cController.vars.facingRight ? 1 : -1) * Mathf.Lerp((float)cController.cInfo.attributes.minWalkSpeed, (float)cController.cInfo.attributes.walkSpeed, perc);

                Vector2 currentSpeed = (Vector2)cController.kineticEnergies.horizontal;
                currentSpeed = Vector2.Lerp(currentSpeed, wantedSpeed, (float)cController.cInfo.attributes.walkAcceleration);

                cController.kineticEnergies.horizontal = (FixVec2)currentSpeed;

                cController.HandleForces();
            }
        }
Exemplo n.º 9
0
    void moveVertically(ref FixVec3 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++)
        {
            var ray = new FixVec2(initialRayOrigin.x + i * _horizontalDistanceBetweenRays, initialRayOrigin.y);
        }
    }
Exemplo n.º 10
0
        internal void Raycast(ITreeRaycastCallback callback, FixVec2 pointA, FixVec2 pointB)
        {
            FixVec2 r = pointB - pointA;

            if (r.GetMagnitudeSquared() <= Fix.zero)
            {
                return;
            }
            r.Normalize();

            // v is perpendicular to the segment.
            FixVec2 v     = FixVec2.Cross(Fix.one, r);
            FixVec2 abs_v = FixVec2.Abs(v);

            // Separating axis for segment (Gino, p80).
            // |dot(v, p1 - c)| > dot(|v|, h)

            Fix maxFraction = Fix.one;

            // Build a bounding box for the segment.
            AABB    segmentAABB = new AABB();
            FixVec2 t           = pointA + maxFraction * (pointB - pointA);

            segmentAABB.min = FixVec2.Min(pointA, t);
            segmentAABB.max = FixVec2.Max(pointA, t);

            Stack <int> stack = new Stack <int>();

            stack.Push(rootIndex);

            while (stack.Count > 0)
            {
                var nodeId = stack.Pop();
                if (nodeId == nullNode)
                {
                    continue;
                }

                var node = nodes[nodeId];

                if (!node.aabb.Overlaps(segmentAABB))
                {
                    continue;
                }

                // Separating axis for segment (Gino, p80).
                // |dot(v, p1 - c)| > dot(|v|, h)
                var c          = node.aabb.GetCenter();
                var h          = node.aabb.GetExtents();
                var separation = FixMath.Abs(FixVec2.Dot(v, pointA - c)) - FixVec2.Dot(abs_v, h);
                if (separation > Fix.zero)
                {
                    continue;
                }

                if (node.IsLeaf())
                {
                    Fix value = callback.RayCastCallback(pointA, pointB, maxFraction, nodeId);

                    if (value == Fix.zero)
                    {
                        // The client has terminated the ray cast.
                        return;
                    }

                    if (value > Fix.zero)
                    {
                        // Update segment bounding box.
                        maxFraction = value;
                        FixVec2 g = pointA + maxFraction * (pointB - pointA);
                        segmentAABB.min = FixVec2.Min(pointA, g);
                        segmentAABB.max = FixVec2.Max(pointA, g);
                    }
                }
                else
                {
                    stack.Push(node.leftChildIndex);
                    stack.Push(node.rightChildIndex);
                }
            }
        }
Exemplo n.º 11
0
 public static Fix Proximity(AABB a, AABB b)
 {
     return(FixMath.Abs(a.L + a.R - b.L - b.R) + FixMath.Abs(a.B + a.T - b.B - b.T));
 }
Exemplo n.º 12
0
        public void ApplyImpulse()
        {
            // Early out and positional correct if both objects have infinite mass
            if (A.invMass + B.invMass == 0)
            {
                InfiniteMassCorrection();
                return;
            }

            for (int i = 0; i < contactCount; ++i)
            {
                // Calculate radii from COM to contact
                FixVec2 ra = contacts[i] - A.Position;
                FixVec2 rb = contacts[i] - B.Position;

                //Relative velocity
                FixVec2 rv = B.info.velocity + FixVec2.Cross(B.info.angularVelocity, rb) - A.info.velocity - FixVec2.Cross(A.info.angularVelocity, ra);

                //Relative velocity along the normal
                Fix contactVel = rv.Dot(normal);

                if (contactVel > 0)
                {
                    return;
                }

                Fix raCrossN   = FixVec2.Cross(ra, normal);
                Fix rbCrossN   = FixVec2.Cross(rb, normal);
                Fix invMassSum = A.invMass + B.invMass
                                 + (raCrossN * raCrossN) * A.invInertia
                                 + (rbCrossN * rbCrossN) * B.invInertia;

                // Calculate impulse scalar
                Fix j = -(Fix.one + e) * contactVel;
                j /= invMassSum;
                j /= contactCount;

                // Apply impulse
                FixVec2 impulse = normal * j;
                A.ApplyImpulse(-impulse, ra);
                B.ApplyImpulse(impulse, rb);

                // Friction Impulse
                rv = B.info.velocity + FixVec2.Cross(B.info.angularVelocity, rb)
                     - A.info.velocity - FixVec2.Cross(A.info.angularVelocity, ra);

                FixVec2 t = rv - (normal * FixVec2.Dot(rv, normal));
                t = t.Normalized();

                // j tangent magnitude
                Fix jt = -FixVec2.Dot(rv, t);
                jt /= invMassSum;
                jt /= contactCount;

                //Don't apply tiny friction impulses
                if (FixMath.Abs(jt) <= Fix.zero)
                {
                    return;
                }

                // Coulumb's law
                FixVec2 tangentImpulse;
                if (FixMath.Abs(jt) < j * sf)
                {
                    tangentImpulse = t * jt;
                }
                else
                {
                    tangentImpulse = t * -j * df;
                }

                // Apply friction impulse
                A.ApplyImpulse(-tangentImpulse, ra);
                B.ApplyImpulse(tangentImpulse, rb);
            }
        }
Exemplo n.º 13
0
        // Check if polygon A is going to collide with polygon B for the given velocity
        public static PolygonCollisionResult CheckCollision(FixPolygon polygonA, FixPolygon polygonB, FixVec2 velocity)
        {
            var result = new PolygonCollisionResult {
                Intersect = true, WillIntersect = true
            };

            var edgeCountA          = polygonA.Edges.Length;
            var edgeCountB          = polygonB.Edges.Length;
            var minIntervalDistance = Fix.MaxValue;
            var translationAxis     = new FixVec2();

            // Loop through all the edges of both polygons
            for (var edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++)
            {
                var edge = edgeIndex < edgeCountA ? polygonA.Edges[edgeIndex] : polygonB.Edges[edgeIndex - edgeCountA];

                // ===== 1. Find if the polygons are currently intersecting =====

                // Find the axis perpendicular to the current edge
                var axis = new FixVec2(-edge.Y, edge.X).Normalize();

                // Find the projection of the polygon on the current axis
                Fix minA;
                Fix maxA;
                Fix minB;
                Fix maxB;
                ProjectPolygon(axis, polygonA, out minA, out maxA);
                ProjectPolygon(axis, polygonB, out minB, out maxB);

                // Check if the polygon projections are currently intersecting
                if (IntervalDistance(minA, maxA, minB, maxB) > 0)
                {
                    result.Intersect = false;
                }

                // ===== 2. Now find if the polygons *will* intersect =====

                // Project the velocity on the current axis
                var velocityProjection = axis.Dot(velocity);

                // Get the projection of polygon A during the movement
                if (velocityProjection < 0)
                {
                    minA += velocityProjection;
                }
                else
                {
                    maxA += velocityProjection;
                }

                // Do the same test as above for the new projection
                var intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0)
                {
                    result.WillIntersect = false;
                }

                // If the polygons are not intersecting and won't intersect, exit the loop
                if (!result.Intersect && !result.WillIntersect)
                {
                    break;
                }

                // Check if the current interval distance is the minimum one. If so store
                // the interval distance and the current distance.
                // This will be used to calculate the minimum translation FixVec2
                intervalDistance = FixMath.Abs(intervalDistance);
                if (intervalDistance < minIntervalDistance)
                {
                    minIntervalDistance = intervalDistance;
                    translationAxis     = axis;

                    var d = polygonA.Center - polygonB.Center;
                    if (d.Dot(translationAxis) < 0)
                    {
                        translationAxis = -translationAxis;
                    }
                }
            }

            // The minimum translation FixVec2 can be used to push the polygons apart.
            // First moves the polygons by their velocity
            // then move polygonA by MinimumTranslationVector.
            if (result.WillIntersect)
            {
                result.MinimumTranslationVector = translationAxis * minIntervalDistance;
            }

            return(result);
        }
Exemplo n.º 14
0
    public override void OnEnable()
    {
        base.OnEnable();

        PlayerControlComponents.OnAdd()
        .Where(entity => !entity.HasComponent <NetworkPlayerComponent>())
        .Subscribe(entity =>
        {
            var playerControlComponent = entity.GetComponent <PlayerControlComponent>();
            var characterController    = entity.GetComponent <CharacterController>();
            var viewComponent          = entity.GetComponent <ViewComponent>();

            Observable.EveryUpdate().Subscribe(_ =>
            {
                if (characterController.isGrounded)
                {
                    var angle = Vector3.Angle(viewComponent.Transforms[0].forward, mainCamera.transform.forward);
                    if (angle < InvertRange.Min || angle > InvertRange.Max)
                    {
                        playerControlComponent.motion = new FixVector3(Input.GetAxis(InputParameters.Horizontal), 0, Input.GetAxis(InputParameters.Vertical));
                    }
                    else
                    {
                        playerControlComponent.motion = new FixVector3(Input.GetAxis(InputParameters.Vertical), 0, Input.GetAxis(InputParameters.Horizontal));
                    }
                    playerControlComponent.motion  = (FixVector3)viewComponent.Transforms[0].TransformDirection((Vector3)playerControlComponent.motion);
                    playerControlComponent.motion *= playerControlComponent.Run;

                    if (Input.GetButton(InputParameters.Jump))
                    {
                        playerControlComponent.motion.y = playerControlComponent.Jump;
                    }
                }

                playerControlComponent.motion.y -= playerControlComponent.Gravity * Time.deltaTime;
                characterController.Move((Vector3)playerControlComponent.motion * Time.deltaTime);
            }).AddTo(this.Disposer).AddTo(playerControlComponent.Disposer);
        }).AddTo(this.Disposer);

        NetwrokTimeline.OnReverse((entity, result) =>
        {
            var playerControlComponent = entity.GetComponent <PlayerControlComponent>();
            var viewComponent          = entity.GetComponent <ViewComponent>();
            var playerControlResult    = (PlayerControlResult)result[0];

            viewComponent.Transforms[0].rotation   = playerControlResult.Rotation;
            playerControlComponent.Follow.rotation = playerControlResult.Follow;
            viewComponent.Transforms[0].position   = playerControlResult.Position;
        }).AddTo(this.Disposer);

        NetwrokTimeline.OnForward((entity, userInputData, deltaTime) =>
        {
            var playerControlComponent = entity.GetComponent <PlayerControlComponent>();
            var characterController    = entity.GetComponent <CharacterController>();
            var viewComponent          = entity.GetComponent <ViewComponent>();
            var animator            = entity.GetComponent <Animator>();
            var axisInput           = userInputData[0].GetInput <AxisInput>();
            var keyInput            = userInputData[1].GetInput <KeyInput>();
            var mouseInput          = userInputData[2].GetInput <MouseInput>();
            var playerControlResult = new PlayerControlResult();
            var smoothTime          = playerControlComponent.smoothTime;
            var yAngle = Fix64.Zero;

            playerControlResult.Rotation = viewComponent.Transforms[0].rotation;
            playerControlResult.Follow   = playerControlComponent.Follow.rotation;
            playerControlResult.Position = viewComponent.Transforms[0].position;

            if (mouseInput != null && keyInput != null && axisInput != null)
            {
                var rotLeftRight = mouseInput.Delta.x * playerControlComponent.MouseSensivity.x * deltaTime;
                var rotUpDown    = mouseInput.Delta.y * playerControlComponent.MouseSensivity.y * deltaTime;

                if (mouseInput.MouseButtons.Contains(1))
                {
                    playerControlComponent.aimTime += deltaTime;
                    if (playerControlComponent.Aim.Value == AimMode.Free && playerControlComponent.aimTime > ShoulderAimTime)
                    {
                        playerControlComponent.Aim.Value = AimMode.Shoulder;
                    }
                }
                else
                {
                    if (playerControlComponent.Aim.Value == AimMode.Free)
                    {
                        if (playerControlComponent.aimTime > 0)
                        {
                            playerControlComponent.Aim.Value = AimMode.AimDownSight;
                        }
                    }
                    else if (playerControlComponent.aimTime > 0)
                    {
                        playerControlComponent.Aim.Value = AimMode.Free;
                    }
                    playerControlComponent.aimTime = 0;
                }

                if (playerControlComponent.Aim.Value == AimMode.Free && keyInput.KeyCodes.Contains((int)KeyCode.LeftAlt))
                {
                    playerControlComponent.Follow.rotation = (Quaternion)((FixQuaternion)playerControlComponent.Follow.rotation * FixQuaternion.Euler(-rotUpDown, rotLeftRight, 0));
                    animator.SetFloat(Head_Vertical_f, 0);
                    animator.SetFloat(Body_Vertical_f, 0);
                    smoothTime = SmoothTime;
                }
                else
                {
                    if (smoothTime > 0)
                    {
                        playerControlComponent.Follow.localRotation = (Quaternion)FixQuaternion.Lerp(FixQuaternion.identity, (FixQuaternion)playerControlComponent.Follow.localRotation, FixMath.Clamp01(smoothTime / SmoothTime));
                        animator.SetFloat(Head_Vertical_f, 0);
                        animator.SetFloat(Body_Vertical_f, 0);
                        smoothTime -= deltaTime;
                    }
                    else
                    {
                        yAngle = ClampAngle(playerControlComponent.Follow.localEulerAngles.x, playerControlComponent.YAngleLimit.Min, playerControlComponent.YAngleLimit.Max);
                        yAngle = ClampAngle(yAngle - rotUpDown, playerControlComponent.YAngleLimit.Min, playerControlComponent.YAngleLimit.Max);

                        var vertical = 2 * (0.5f - FixMath.Abs(yAngle - playerControlComponent.YAngleLimit.Min) / FixMath.Abs(playerControlComponent.YAngleLimit.Max - playerControlComponent.YAngleLimit.Min));
                        animator.SetFloat(Head_Vertical_f, 0.5f * (float)vertical);
                        animator.SetFloat(Body_Vertical_f, (float)vertical);
                        viewComponent.Transforms[0].rotation           = (Quaternion)((FixQuaternion)viewComponent.Transforms[0].rotation * FixQuaternion.Euler(0, rotLeftRight, 0));
                        playerControlComponent.Follow.localEulerAngles = (Vector3) new FixVector3(yAngle, 0, 0);
                    }
                }

                if (characterController.isGrounded)
                {
                    playerControlComponent.motion = new FixVector3((float)axisInput.Horizontal, 0, (float)axisInput.Vertical);
                    playerControlComponent.motion = (FixVector3)viewComponent.Transforms[0].TransformDirection((Vector3)playerControlComponent.motion);

                    Fix64 t          = 0.75f;
                    Fix64 speed      = playerControlComponent.Walk;
                    Fix64 h          = FixMath.Abs(axisInput.Horizontal);
                    Fix64 sum        = h + FixMath.Abs(axisInput.Vertical);
                    Fix64 horizontal = sum == 0 ? 0 : axisInput.Horizontal * (h / sum);
                    if (playerControlComponent.Aim.Value == AimMode.Shoulder)
                    {
                        t = 0.5f;
                    }
                    else if (playerControlComponent.Aim.Value == AimMode.AimDownSight)
                    {
                        t = 0.25f;
                    }
                    else if (keyInput != null && keyInput.KeyCodes.Contains((int)KeyCode.LeftShift))
                    {
                        t     = 1f;
                        speed = playerControlComponent.Run;
                    }

                    playerControlComponent.Crouched = keyInput.KeyCodes.Contains((int)KeyCode.LeftControl);
                    animator.SetBool(Crouch_b, playerControlComponent.Crouched);
                    if (playerControlComponent.Crouched)
                    {
                        speed = 0;
                    }

                    playerControlComponent.motion *= t * speed;
                    animator.SetFloat(Speed_f, (axisInput.Horizontal != Fix64.Zero || axisInput.Vertical != Fix64.Zero) ? (float)FixMath.Clamp(t, 0.3f, 1f) : 0f);
                    animator.SetFloat(Head_Horizontal_f, 0.25f * (float)horizontal);
                    animator.SetFloat(Body_Horizontal_f, 0.35f * (float)horizontal);
                }

                if (keyInput.KeyCodes.Contains((int)KeyCode.Space) && !playerControlComponent.Crouched)
                {
                    playerControlComponent.motion.y = playerControlComponent.Jump;
                }
            }

            playerControlComponent.motion.y  -= playerControlComponent.Gravity * deltaTime;
            playerControlComponent.smoothTime = smoothTime;
            characterController.Move((Vector3)(playerControlComponent.motion * deltaTime));

            animator.SetBool(Jump_b, playerControlComponent.motion.y > 0);
            animator.SetBool(Grounded, characterController.isGrounded && playerControlComponent.motion.y <= 0);

            return(new IUserInputResult[] { playerControlResult });
        }).AddTo(this.Disposer);
    }
Exemplo n.º 15
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;
                }
            }
        }
    }
Exemplo n.º 16
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);
    }
Exemplo n.º 17
0
 public static DynValue abs(ScriptExecutionContext executionContext, CallbackArguments args)
 {
     return(exec1(args, "abs", (x) => FixMath.Abs(x)));
 }
Exemplo n.º 18
0
        internal TFRaycastHit2D Raycast(ITreeRaycastCallback callback, FixVec2 pointA, FixVec2 pointB, TFLayerMask mask)
        {
            TFRaycastHit2D hit = new TFRaycastHit2D();
            FixVec2        r   = pointB - pointA;

            if (r.GetMagnitudeSquared() <= Fix.zero)
            {
                return(hit);
            }
            r.Normalize();

            // v is perpendicular to the segment.
            FixVec2 v     = FixVec2.Cross(Fix.one, r);
            FixVec2 abs_v = FixVec2.Abs(v);

            // Separating axis for segment (Gino, p80).
            // |dot(v, p1 - c)| > dot(|v|, h)
            Fix maxFraction = Fix.one;

            // Build a bounding box for the segment.
            AABB    segmentAABB = new AABB();
            FixVec2 t           = pointA + maxFraction * (pointB - pointA);

            segmentAABB.min = FixVec2.Min(pointA, t);
            segmentAABB.max = FixVec2.Max(pointA, t);

            Stack <int> stack = new Stack <int>();

            stack.Push(rootIndex);

            List <TFRaycastOutput> hitNodes = new List <TFRaycastOutput>(2);

            while (stack.Count > 0)
            {
                var nodeId = stack.Pop();
                if (nodeId == nullNode)
                {
                    continue;
                }

                var node = nodes[nodeId];

                if (!node.aabb.Overlaps(segmentAABB))
                {
                    continue;
                }

                // Separating axis for segment (Gino, p80).
                // |dot(v, p1 - c)| > dot(|v|, h)
                var c          = node.aabb.GetCenter();
                var h          = node.aabb.GetExtents();
                var separation = FixMath.Abs(FixVec2.Dot(v, pointA - c)) - FixVec2.Dot(abs_v, h);
                if (separation > Fix.zero)
                {
                    continue;
                }

                if (node.IsLeaf())
                {
                    // If value is >= 0, then we hit the node.
                    TFRaycastHit2D rHit;
                    Fix            value = callback.RayCastCallback(pointA, pointB, maxFraction, nodeId, out rHit, mask);

                    if (value == Fix.zero)
                    {
                        // The client has terminated the ray cast.
                        if (rHit)
                        {
                            // We actually hit the node, add it to the list.
                            hitNodes.Add(new TFRaycastOutput(nodeId, rHit));
                        }
                        break;
                    }

                    if (value == maxFraction)
                    {
                        if (rHit)
                        {
                            // We actually hit the node, add it to the list.
                            hitNodes.Add(new TFRaycastOutput(nodeId, rHit));
                        }
                    }
                    else if (value > Fix.zero)
                    {
                        if (rHit)
                        {
                            // We actually hit the node, add it to the list.
                            hitNodes.Add(new TFRaycastOutput(nodeId, rHit));
                        }
                        // Update segment bounding box.
                        maxFraction = value;
                        FixVec2 g = pointA + maxFraction * (pointB - pointA);
                        segmentAABB.min = FixVec2.Min(pointA, g);
                        segmentAABB.max = FixVec2.Max(pointA, g);
                    }
                }
                else
                {
                    stack.Push(node.leftChildIndex);
                    stack.Push(node.rightChildIndex);
                }
            }

            // Decide which node was the closest to the starting point.
            Fix closestNode = maxFraction;

            for (int i = 0; i < hitNodes.Count; i++)
            {
                if (hitNodes[i].hit.fraction < closestNode)
                {
                    closestNode = hitNodes[i].hit.fraction;
                    hit         = hitNodes[i].hit;
                }
            }
            return(hit);
        }
Exemplo n.º 19
0
 private bool Approximately(Fix a, Fix b)
 {
     return(FixMath.Abs(b - a) < (Fix)0.001);
 }