private Vector3 CalculateVerticalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            Vector3 newVelocity = currentVelocity.y * Vector3.up;

            if (newVelocity.y <= 0 || GroundingStatus.FoundAnyGround)  //Falling
            {
                newVelocity.y += gravity * (FallMultiplier.Value - 1) * Time.deltaTime;
            }
            else if (newVelocity.y > 0 && !JumpPressed.Value)    //Short jump
            {
                newVelocity.y -= LowJumpDrag.Value * Time.deltaTime;
                newVelocity.y += gravity * Time.deltaTime;
            }
            else
            {
                newVelocity.y += gravity * Time.deltaTime;
            }

            if (newVelocity.y < -Mathf.Abs(MaxFallSpeed.Value))   //Cap Speed
            {
                newVelocity.y = -Mathf.Abs(MaxFallSpeed.Value);
            }

            return(newVelocity);
        }
    private void UpdateVelocity(VelocityInfo velocityInfo)
    {
        SetMoveDirection();

        Vector3 newVelocity;
        CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
        CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

        //Take move input direction directly and flatten (Dont do turn smoothing for now)
        float slopeMoveSpeed = 10f;

        newVelocity = moveDirection.xoz() * slopeMoveSpeed;

        //Project velocity sideways along slope
        Vector3 slopeRight = Vector3.Cross(Vector3.up, GroundingStatus.GroundNormal);
        Vector3 slopeOut   = Vector3.Cross(slopeRight, Vector3.up);

        newVelocity = Vector3.ProjectOnPlane(newVelocity, slopeOut).xoz();

        //Add velocity down slope
        float   slopeFallSpeed = 20f;
        Vector3 fallVelocity   = slopeFallSpeed * Vector3.down;

        newVelocity += Vector3.ProjectOnPlane(fallVelocity, GroundingStatus.GroundNormal);

        NewVelocityOut.Value = newVelocity;
        UpdateSlopeSlidePivot();
    }
        private Vector3 CalculateVerticalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            //Return if standing on flat ground
            if (GroundingStatus.FoundAnyGround && GroundingStatus.GroundNormal == Vector3.up)
            {
                return(Vector3.zero);
            }

            #region Airborn

            Vector3 newVelocity = currentVelocity.y * Vector3.up;

            if (!GroundingStatus.FoundAnyGround)
            {
                if (newVelocity.y <= 0)  //Falling
                {
                    newVelocity.y += gravity * (FallMultiplier.Value - 1) * Time.deltaTime;
                }
                else if (newVelocity.y > 0f) //Drag when moving up (Note: Affects going up slopes)
                {
                    var drag = -(newVelocity.y * newVelocity.y) * DragCoefficientVertical.Value * Time.deltaTime;
                    newVelocity.y += drag + gravity * Time.deltaTime;
                }
                else
                {
                    newVelocity.y += gravity * Time.deltaTime;
                }

                if (newVelocity.y < -Mathf.Abs(MaxFallSpeed.Value))   //Cap Speed
                {
                    newVelocity.y = -Mathf.Abs(MaxFallSpeed.Value);
                }
            }

            #endregion

            #region Grounded (slope)

            //Each frame, add gravity to velocity on slope
            if (GroundingStatus.FoundAnyGround)
            {
                newVelocity.y = gravity * SlopeVerticalGravityFactor.Value * Time.deltaTime;
                newVelocity   = Vector3.ProjectOnPlane(newVelocity, GroundingStatus.GroundNormal);
            }

            #endregion

            return(newVelocity);
        }
        private void InitRollParticles()
        {
            //Init particles based on grounded or not
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            if (GroundingStatus.FoundAnyGround)
            {
                PlayParticlesGameEvent.Raise();
            }
            else
            {
                StopParticlesGameEvent.Raise();
            }
        }
        private Vector3 CalculateVerticalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            Vector3 newVelocity = Vector3.zero;

            //Project onto ground plane (sloped to some degree)
            if (GroundingStatus.FoundAnyGround)
            {
                newVelocity.y = gravity * Time.deltaTime;
                newVelocity   = Vector3.ProjectOnPlane(newVelocity, GroundingStatus.GroundNormal);
                newVelocity  *= HorizontalGravityFactor.Value;
            }

            return(newVelocity);
        }
        private void HandleUpdateParticles()
        {
            //Update particles when grounding status changes
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            //If became grounded
            if (GroundingStatus.FoundAnyGround && !LastGroundingStatus.FoundAnyGround)
            {
                PlayParticlesGameEvent.Raise();
            }
            //If became airborn
            else if (!GroundingStatus.FoundAnyGround && LastGroundingStatus.FoundAnyGround)
            {
                StopParticlesGameEvent.Raise();
            }
        }
Example #7
0
        private void AccumulateSlingForce()
        {
            CharacterGroundingReport groundingStatus = playerController.GroundingStatus;
            Vector3 slingDirection;

            //If no move input, just launch forward
            if (Mathf.Approximately(0f, moveInputCameraRelative.sqrMagnitude))
            {
                slingDirection = Vector3.ProjectOnPlane(PlayerCameraTransform.Value.forward.xoz(), groundingStatus.GroundNormal);
            }
            else
            {
                slingDirection = Vector3.ProjectOnPlane(moveInputCameraRelative.normalized, groundingStatus.GroundNormal);
            }

            slingshotTargetSceneReference.Value = null;

            if (currentTargetSceneReference.Value != null)
            {
                Vector3 playerToTarget =
                    (currentTargetSceneReference.Value.position - playerController.transform.position).normalized;

                if (Vector3.Dot(moveInputCameraRelative.xoz().normalized, playerToTarget.xoz().normalized) > HomingDotProductMin.Value)
                {
                    slingDirection = playerToTarget;
                    slingshotTargetSceneReference.Value = currentTargetSceneReference.Value;
                }
            }

            float timePassed   = Time.time - enterTime;
            float percentToMax = Mathf.Clamp01(timePassed / TimeToMaxCharge.Value);
            float accumulatedForceMagnitude = Mathf.Lerp(MinForce.Value, MaxForce.Value, percentToMax);

            accumulatedForce = slingDirection * accumulatedForceMagnitude;

            float maxArowLine = 15f;

            playerController.SetSlingshotArrow(percentToMax * maxArowLine * slingDirection);
            SlingshotDirection.Value = slingDirection;
        }
Example #8
0
    public override void PostGroundingUpdate(float deltaTime)
    {
        if (_lastGroundingReport.FoundAnyGround && !Motor.GroundingStatus.FoundAnyGround)
        {
            //Left ground
        }
        if (!_lastGroundingReport.FoundAnyGround && Motor.GroundingStatus.FoundAnyGround)
        {
            //Landed on ground

            //Preserve current velocity
            //TODO Maybe do some actual ground normal calculations for the internal velocity calculations
            Debug.Log("PostGroundingUpdate");
            _internalVelocity = _lastVelocity;
            Vector3 groundNorm = Motor.GroundingStatus.GroundNormal;
            _internalVelocity  = Vector3.ProjectOnPlane(_internalVelocity, groundNorm).normalized;
            _internalVelocity *= (_lastVelocity - _internalVelocity).magnitude * LandingReduction * Mathf.Clamp01(Vector3.Dot(_lastVelocity, groundNorm) * -1f);
        }

        _lastGroundingReport = Motor.GroundingStatus;
        _lastVelocity        = Motor.Velocity;
    }
        private Vector3 CalculateHorizontalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport GroundingStatus = playerController.GroundingStatus;

            #region Get New Move Direction

            newDirection = FlattenMoveInputOntoSlope(MoveInput.Value.xoy(), GroundingStatus.GroundNormal);

            #endregion

            #region Get New Move Speed

            velocityAlongSlope = Vector3.ProjectOnPlane(currentVelocity, GroundingStatus.GroundNormal);
            float speedAlongSlope = velocityAlongSlope.magnitude;

            var drag = speedAlongSlope * DragCoefficient.Value * Time.deltaTime;

            newSpeed = velocityAlongSlope.magnitude - drag;

            #endregion

            return(newDirection * newSpeed);
        }
        private Vector3 CalculateHorizontalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport GroundingStatus = playerController.GroundingStatus;

            #region Determine if Fast Turning

            //Dont allow fast turn on slopes
            if (EnableFastTurn)
            {
                CheckForFastTurn(currentVelocity);
            }

            float   currentTurnSpeed;
            Vector2 horizontalVelocity = currentVelocity.xz();

            //Update turn speed based on isFastTurning
            if (IsFastTurning.Value)
            {
                currentTurnSpeed = FastTurnSpeed.Value;
            }
            else
            {
                currentTurnSpeed = TurnSpeed.Value;
            }

            #endregion

            #region Get New Move Direction

            //Rotate current vel towards target vel to get new direction
            Vector2 dummyVel = Vector3.zero;
            Vector2 dir      = Vector2.SmoothDamp(horizontalVelocity.normalized, moveInputCameraRelative.xz(),
                                                  ref dummyVel, currentTurnSpeed);

            newDirection = dir.xoy().normalized;

            #endregion

            #region Get New Move Speed

            //Accelerate/DeAccelerate from current Speed to target speed
            float dummySpeed = 0f;
            float currentSpeed;
            float targetSpeed;

            currentSpeed = currentVelocity.xoz().magnitude;
            targetSpeed  = MoveInput.Value.magnitude * MoveSpeed.Value;

            if (targetSpeed > currentSpeed)
            {
                newSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed,
                                            ref dummySpeed, Acceleration.Value);
            }
            else
            {
                newSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed,
                                            ref dummySpeed, Deacceleration.Value);
            }

            #endregion

            #region Override Speed and Direction if Fast Turning

            dummySpeed = 0f;

            //If fast turning, DeAccelerate to 0 to brake
            if (IsFastTurning.Value)
            {
                newSpeed = Mathf.SmoothDamp(horizontalVelocity.magnitude, 0f,
                                            ref dummySpeed, FastTurnBrakeDeacceleration.Value);

                newDirection = fastTurnStartDir;

                //If finished stopping, turn to face moveDir
                if (newSpeed < FastTurnBrakeSpeedThreshold.Value)
                {
                    newDirection = moveInputCameraRelative.xoz().normalized;
                }
            }
            else if (IsSlideTurning.Value)
            {
                newSpeed = Mathf.SmoothDamp(horizontalVelocity.magnitude, 0f,
                                            ref dummySpeed, SlideTurnBrakeDeacceleration.Value);

                newDirection = fastTurnStartDir;

                //If finished stopping, turn to face moveDir
                if (newSpeed < FastTurnBrakeSpeedThreshold.Value)
                {
                    newDirection = moveInputCameraRelative.xoz().normalized;
                }
            }

            #endregion

            //Cache moveInput value
            //Dont cache values in deadzone
            if (MoveInput.Value.magnitude > FastTurnInputDeadZone.Value)
            {
                lastMoveInputDirection = MoveInput.Value.normalized;
            }


            return(newDirection * newSpeed);
        }
        private Vector3 CalculateHorizontalVelocity(Vector3 currentVelocity)
        {
            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;

            if (!Mathf.Approximately(0f, storedDeflectVelocity.sqrMagnitude))
            {
                currentVelocity = storedDeflectVelocity;
            }

            velocityAlongSlope = Vector3.ProjectOnPlane(currentVelocity, GroundingStatus.GroundNormal);
            float currentSpeed = (GroundingStatus.FoundAnyGround)
                ? velocityAlongSlope.magnitude
                : currentVelocity.xoz().magnitude;

            //If just became grounded, redirect velocity and overwrite speed (dont slow down)
            if (!LastGroundingStatus.FoundAnyGround && GroundingStatus.FoundAnyGround)
            {
                currentSpeed = previousVelocityOutput.magnitude;
            }

            #region Get New Move Direction


            //Rotate current vel towards target vel to get new direction
            Vector3 dummyVel = Vector3.zero;
            Vector3 dir;

            var slowTurnSpeed          = TurnSpeed.Value * SlowTurnFactor.Value;
            var slowTurnThreshold      = SlowTurnThreshold.Value;
            var percentToSlowTurnSpeed = Mathf.InverseLerp(0f, slowTurnThreshold, currentSpeed);


            float currentTurnSpeed;

            //If grounded, lerp from turn speed to slow turn speed based on current velocity
            if (GroundingStatus.FoundAnyGround)
            {
                currentTurnSpeed = Mathf.Lerp(TurnSpeed.Value, slowTurnSpeed, percentToSlowTurnSpeed);

                Vector3 dirOnSlope = Vector3.ProjectOnPlane(currentVelocity.normalized,
                                                            GroundingStatus.GroundNormal).normalized;

                //If ground is flat, just take flattened move input
                if (GroundingStatus.GroundNormal == Vector3.up)
                {
                    moveInputOnSlope = moveInputCameraRelative.xoz().normalized;
                }
                else if (Mathf.Approximately(MoveInput.Value.magnitude, 0f))
                {
                    moveInputOnSlope = Vector3.zero;
                }
                else
                {
                    moveInputOnSlope = FlattenMoveInputOntoSlope(MoveInput.Value, GroundingStatus.GroundNormal);
                }

                dir = Vector3.SmoothDamp(dirOnSlope, moveInputOnSlope,
                                         ref dummyVel, currentTurnSpeed).normalized;

                dirOnSlopeGizmo = dirOnSlope;
            }
            else
            {
                currentTurnSpeed = TurnSpeedAir.Value;
                dir = Vector3.SmoothDamp(currentVelocity.xoz().normalized, moveInputCameraRelative.normalized,
                                         ref dummyVel, currentTurnSpeed).normalized;
            }

            newDirection = dir;

            #endregion

            #region Get New Speed

            var steeringDir   = moveInputCameraRelative;
            var steeringAngle = Vector3.Angle(dir, steeringDir);
            var steeringFac   = steeringAngle / 180;

            //TurnFactor.Value = Vector3.SignedAngle(horizontalDir, steeringDir, Vector3.up) / 30;

            var   rollingFriction = 6 * CoefficientOfRollingFriction.Value;//TODO: 6 was for medium size before
            var   turningFriction = (1 + (CoefficientOfTurningFriction.Value * steeringFac));
            float friction        = (GroundingStatus.FoundAnyGround) ?
                                    rollingFriction * turningFriction * Time.deltaTime : 0f;

            var drag = currentSpeed * DragCoefficientHorizontal.Value * Time.deltaTime;

            #region Accelerate to target speed

            float targetMagnitude;

            //If projected move input is in same direction as velocity, set target speed
            //Otherwise, assume player wants to stop and turn around
            if (Vector3.Dot(dir, moveInputOnSlope) > 0f)
            {
                targetMagnitude = moveInputOnSlope.magnitude;
            }
            else
            {
                targetMagnitude = 0f;
            }

            var targetSpeed = BaseSpeed.Value * targetMagnitude;
            if (newSpeed < targetSpeed && GroundingStatus.FoundAnyGround)
            {
                var timeToTargetSpeed = 2f;    //Time to get to target speed from 0
                newSpeed  = currentSpeed + targetSpeed * Time.deltaTime / timeToTargetSpeed;
                newSpeed -= friction;
            }
            else
            {
                //Only apply drag if not accelerating to base speed
                newSpeed = currentSpeed - friction - drag;
            }


            #endregion

            #endregion

            HorizontalSpeedOut.Value = newSpeed;
            storedDeflectVelocity    = Vector3.zero;
            return(newDirection * newSpeed);
        }
        protected override Vector3 CalculateVelocity(VelocityInfo velocityInfo)
        {
            Vector3 currentVelocity            = velocityInfo.currentVelocity;
            Vector3 impulseVelocity            = velocityInfo.impulseVelocity;
            Vector3 impulseVelocityRedirectble = velocityInfo.impulseVelocityRedirectble;

            Vector3 totalImpulse = impulseVelocity;
            Vector3 resultingVelocity;
            Vector3 horizontalVelocity = CalculateHorizontalVelocity(currentVelocity);
            Vector3 verticalVelocity   = CalculateVerticalVelocity(currentVelocity);

            //Redirect impulseVelocityRedirectble if conditions met
            if (EnableRedirect && CheckRedirectConditions(impulseVelocityRedirectble))
            {
                totalImpulse += CalculateRedirectedImpulse(impulseVelocityRedirectble);
            }
            else
            {
                totalImpulse += impulseVelocityRedirectble;
            }

            resultingVelocity  = horizontalVelocity + verticalVelocity;
            resultingVelocity += totalImpulse;

            CharacterGroundingReport          GroundingStatus     = playerController.GroundingStatus;
            CharacterTransientGroundingReport LastGroundingStatus = playerController.LastGroundingStatus;


            #region Bounce

            //Bounce if just became grounded
            Vector3 velocityIntoGround = Vector3.Project(previousVelocityOutput, -GroundingStatus.GroundNormal);

            float velocityGroundDot = Vector3.Dot(previousVelocityOutput.normalized, GroundingStatus.GroundNormal);

            if (EnableBounce && !LastGroundingStatus.FoundAnyGround && GroundingStatus.FoundAnyGround &&
                velocityIntoGround.magnitude >= BounceThresholdVelocity.Value &&
                -velocityGroundDot > BounceGroundDotThreshold.Value)
            {
                playerController.UngroundMotor();
                BounceGameEvent.Raise();

                //Reflect velocity perfectly then dampen the y based on dot with normal
                Vector3 reflectedVelocity = Vector3.Reflect(previousVelocityOutput, GroundingStatus.GroundNormal);
                reflectedVelocity.y *= BounceFactor.Value;

                //Redirect bounce if conditions met
                if (EnableRedirect && CheckRedirectConditions(reflectedVelocity))
                {
                    reflectedVelocity = CalculateRedirectedImpulse(reflectedVelocity);
                }

                resultingVelocity = reflectedVelocity;
            }

            #endregion

            previousVelocityOutput = resultingVelocity;

            return(resultingVelocity);
        }
Example #13
0
    public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
    {
        Vector3 targetMovementVelocity  = Vector3.zero;
        CharacterGroundingReport ground = Motor.GroundingStatus;

        // Ground movement
        if (ground.IsStableOnGround)
        {
            // Reorient current velocity on the ground slope before smoothing (important to avoid velocity loss in slope changes)
            currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, ground.GroundNormal) * currentVelocity.magnitude;

            // Calculate target velocity (still oriented on ground slope)
            Vector3 inputRight      = Vector3.Cross(C.WorldspaceCharacterPlaneMoveInputVector, Motor.CharacterUp);
            Vector3 reorientedInput = Vector3.Cross(ground.GroundNormal, inputRight).normalized *C.WorldspaceCharacterPlaneMoveInputVector.magnitude;
            float   maxSpeed        = GInput.SlowModifier ? MaxStableMoveSpeed / C.SlowSpeedDivider : MaxStableMoveSpeed;
            targetMovementVelocity = reorientedInput * maxSpeed;

            // Smoothly interpolate to target velocity
            currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));

            // Add some gravity if we're grounded but not snapping to ground
            // (this situation can happen when we want to "launch off" ledges or declining slopes)
            //if (Motor.GroundingStatus.IsPreventingSnapping)
            //{
            //currentVelocity += Gravity * deltaTime;
            //}
        }
        // Air movement
        else
        {
            if (C.WorldspaceCharacterPlaneMoveInputVector.sqrMagnitude > 0f)
            {
                // If we want to move, add an acceleration to the velocity
                float maxSpeed = GInput.SlowModifier ? MaxAirMoveSpeed / C.SlowSpeedDivider : MaxAirMoveSpeed;
                targetMovementVelocity = C.WorldspaceCharacterPlaneMoveInputVector * maxSpeed;

                // Prevent climbing on un-stable slopes with air movement
                if (Motor.GroundingStatus.FoundAnyGround)
                {
                    Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
                    targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
                }

                Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, C.Gravity);
                currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
            }

            // Gravity
            currentVelocity += C.Gravity * deltaTime;

            // Drag
            currentVelocity *= (1f / (1f + (Drag * deltaTime)));
        }

        // Handle jumping
        jumpedThisFrame         = false;
        timeSinceJumpRequested += deltaTime;
        if (jumpRequested)
        {
            // Handle double jump
            if (AllowDoubleJump)
            {
                if (jumpConsumed && !doubleJumpConsumed && (AllowJumpingWhenSliding ? !ground.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround))
                {
                    Motor.ForceUnground();

                    // Add to the return velocity and reset jump state
                    currentVelocity   += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
                    jumpRequested      = false;
                    doubleJumpConsumed = true;
                    jumpedThisFrame    = true;
                }
            }

            // See if we actually are allowed to jump
            if (canWallJump ||
                (!jumpConsumed && ((AllowJumpingWhenSliding ? ground.FoundAnyGround : ground.IsStableOnGround) || timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)))
            {
                // Calculate jump direction before ungrounding
                Vector3 jumpDirection = Motor.CharacterUp;
                if (canWallJump)
                {
                    jumpDirection = wallJumpNormal;
                }
                else if (ground.FoundAnyGround && !ground.IsStableOnGround)
                {
                    jumpDirection = ground.GroundNormal;
                }

                // Makes the character skip ground probing/snapping on its next update.
                // If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
                Motor.ForceUnground();

                // Add to the return velocity and reset jump state
                currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
                jumpRequested    = false;
                jumpConsumed     = true;
                jumpedThisFrame  = true;
            }
        }

        // Reset wall jump
        canWallJump = false;

        // Take into account additive velocity
        if (internalVelocityAdd.sqrMagnitude > 0f)
        {
            currentVelocity    += internalVelocityAdd;
            internalVelocityAdd = Vector3.zero;
        }
    }