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(); } }
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; }
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); }
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; } }