I am trying to use the following code to prevent the player from jumping up VERY steep parts of a terrain ( X Angle 65 or greater ) and STOP “bouncing” when moving back down the terrain. How WITH THIS CODE do I fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class PlayerMovementAdvanced : MonoBehaviour
{
[Header("Movement")]
private float moveSpeed;
private float desiredMoveSpeed;
private float lastDesiredMoveSpeed;
public float walkSpeed;
public float turnSpeed;
public float sprintSpeed;
public float slideSpeed;
public float wallrunSpeed;
public float climbSpeed;
public float vaultSpeed;
public float airMinSpeed;
public float slopeAngle;
public float slopeAngleIncrease;
public float speedIncreaseMultiplier;
public float slopeIncreaseMultiplier;
public float groundDrag;
[Header("Jumping")]
public int maxJumps = 3;
public int currentJumpCount = 0;
public float jumpForce;
public float jumpCooldown;
public float airMultiplier;
public bool canJump = true;
[Header("Crouching")]
public float crouchSpeed;
public float crouchYScale;
private float startYScale;
[Header("Keybinds")]
public KeyCode jumpKey = KeyCode.Space;
public KeyCode sprintKey = KeyCode.LeftShift;
public KeyCode crouchKey = KeyCode.LeftControl;
[Header("Ground Check")]
public float playerHeight;
public LayerMask whatIsGround;
public bool grounded;
[Header("Slope Handling")]
public float maxSlopeAngle = 65.0f;
// Setting up some values
private Quaternion beforeMovement;
private Quaternion target;
private RaycastHit hit;
private Ray ray;
private LayerMask layer;
private RaycastHit slopeHit;
private bool exitingSlope;
[Header("References")]
public Climbing climbingScript;
private ClimbingDone climbingScriptDone;
public Transform orientation;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
public MovementState state;
public enum MovementState
{
freeze,
unlimited,
walking,
sprinting,
wallrunning,
climbing,
vaulting,
crouching,
sliding,
air
}
public bool sliding;
public bool crouching;
public bool wallrunning;
public bool climbing;
public bool vaulting;
public bool freeze;
public bool unlimited;
public bool restricted;
public TextMeshProUGUI text_speed;
public TextMeshProUGUI text_mode;
private void Start ( ) {
climbingScriptDone = GetComponent <ClimbingDone> ( );
rb = GetComponent <Rigidbody> ( );
rb.freezeRotation = true;
canJump = true;
startYScale = transform.localScale.y;
}
private void Update()
{
// ground check
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
StateHandler();
TextStuff();
// handle drag
if (state == MovementState.walking || state == MovementState.sprinting || state == MovementState.crouching)
rb.drag = groundDrag;
else
rb.drag = 0;
}
private void FixedUpdate()
{
MovePlayer();
}
private IEnumerator CoolDown ( ) {
currentJumpCount = 0;
canJump = false;
yield return new WaitForSeconds ( jumpCooldown );
canJump = true;
}
private void MyInput ( ) {
horizontalInput = Input.GetAxisRaw ( "Horizontal" );
verticalInput = Input.GetAxisRaw ( "Vertical" );
float slopeAngle = Vector3.Angle ( Vector3.up, slopeHit.normal );
// When to Jump
if ( ( Input.GetKeyDown ( jumpKey ) && canJump ) && grounded && currentJumpCount < maxJumps ) {
Jump ( );
}
if ( currentJumpCount == maxJumps ) {
StartCoroutine ( CoolDown ( ) );
}
// start crouch
if (Input.GetKeyDown(crouchKey) && horizontalInput == 0 && verticalInput == 0)
{
transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
crouching = true;
}
// Stop Crouch
if ( Input.GetKeyUp(crouchKey ) ) {
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
crouching = false;
}
}
bool keepMomentum;
private void StateHandler()
{
// Mode - Freeze
if (freeze)
{
state = MovementState.freeze;
rb.velocity = Vector3.zero;
desiredMoveSpeed = 0f;
}
// Mode - Unlimited
else if (unlimited)
{
state = MovementState.unlimited;
desiredMoveSpeed = 999f;
}
// Mode - Vaulting
else if (vaulting)
{
state = MovementState.vaulting;
desiredMoveSpeed = vaultSpeed;
}
// Mode - Climbing
else if (climbing)
{
state = MovementState.climbing;
desiredMoveSpeed = climbSpeed;
}
// Mode - Wallrunning
else if (wallrunning)
{
state = MovementState.wallrunning;
desiredMoveSpeed = wallrunSpeed;
}
// Mode - Sliding
else if (sliding)
{
state = MovementState.sliding;
// increase speed by one every second
if (OnSlope() && rb.velocity.y < 0.1f)
{
desiredMoveSpeed = slideSpeed;
keepMomentum = true;
}
else
desiredMoveSpeed = sprintSpeed;
}
// Mode - Crouching
else if (crouching)
{
state = MovementState.crouching;
desiredMoveSpeed = crouchSpeed;
}
// Mode - Sprinting
else if (grounded && Input.GetKey(sprintKey))
{
state = MovementState.sprinting;
desiredMoveSpeed = sprintSpeed;
}
// Mode - Walking
else if (grounded)
{
state = MovementState.walking;
desiredMoveSpeed = walkSpeed;
}
// Mode - Air
else
{
state = MovementState.air;
if (moveSpeed < airMinSpeed)
desiredMoveSpeed = airMinSpeed;
}
bool desiredMoveSpeedHasChanged = desiredMoveSpeed != lastDesiredMoveSpeed;
if (desiredMoveSpeedHasChanged)
{
if (keepMomentum)
{
StopAllCoroutines();
StartCoroutine(SmoothlyLerpMoveSpeed());
}
else
{
moveSpeed = desiredMoveSpeed;
}
}
lastDesiredMoveSpeed = desiredMoveSpeed;
// deactivate keepMomentum
if (Mathf.Abs(desiredMoveSpeed - moveSpeed) < 0.1f) keepMomentum = false;
}
private IEnumerator SmoothlyLerpMoveSpeed()
{
// smoothly lerp movementSpeed to desired value
float time = 0;
float difference = Mathf.Abs(desiredMoveSpeed - moveSpeed);
float startValue = moveSpeed;
while (time < difference)
{
moveSpeed = Mathf.Lerp(startValue, desiredMoveSpeed, time / difference);
Debug.Log ( $"OnSlope ( ) : { OnSlope ( ) }" );
if (OnSlope())
{
slopeAngle = Vector3.Angle(Vector3.up, slopeHit.normal);
slopeAngleIncrease = 1 + (slopeAngle / 90f);
time += Time.deltaTime * speedIncreaseMultiplier * slopeIncreaseMultiplier * slopeAngleIncrease;
}
else
time += Time.deltaTime * speedIncreaseMultiplier;
yield return null;
}
moveSpeed = desiredMoveSpeed;
}
private void MovePlayer()
{
if (climbingScript.exitingWall) return;
if (climbingScriptDone.exitingWall) return;
if (restricted) return;
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
// on slope
if (OnSlope() && !exitingSlope)
{
rb.drag = groundDrag;
rb.AddForce(GetSlopeMoveDirection(moveDirection) * moveSpeed * 20f, ForceMode.Force);
if (rb.velocity.y > 0)
rb.AddForce(Vector3.down * 80f, ForceMode.Force);
}
// on ground
else if (grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
// in air
else if (!grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
// turn gravity off while on slope
if(!wallrunning) rb.useGravity = !OnSlope();
}
private void SpeedControl()
{
// limiting speed on slope
if (OnSlope() && !exitingSlope)
{
if (rb.velocity.magnitude > moveSpeed)
rb.velocity = rb.velocity.normalized * moveSpeed;
}
// limiting speed on ground or in air
else
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
// limit velocity if needed
if (flatVel.magnitude > moveSpeed)
{
Vector3 limitedVel = flatVel.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
}
}
}
private void Jump ( ) {
canJump = false;
exitingSlope = true;
// Reset Y - Velocity
rb.velocity = new Vector3 (
rb.velocity.x,
0.0f,
rb.velocity.z
);
rb.AddForce (
transform.up * jumpForce,
ForceMode.Impulse
);
canJump = true;
}
private void ResetJump ( ) {
currentJumpCount = 0;
canJump = true;
exitingSlope = false;
}
public bool OnSlope()
{
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.3f))
{
float angle = Vector3.Angle(Vector3.up, slopeHit.normal);
return angle < maxSlopeAngle && angle != 0;
}
return false;
}
public Vector3 GetSlopeMoveDirection(Vector3 direction)
{
return Vector3.ProjectOnPlane(direction, slopeHit.normal).normalized;
}
private void TextStuff()
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
if (OnSlope())
text_speed.SetText("Speed: " + Round(rb.velocity.magnitude, 1) + " / " + Round(moveSpeed, 1));
else
text_speed.SetText("Speed: " + Round(flatVel.magnitude, 1) + " / " + Round(moveSpeed, 1));
text_mode.SetText(state.ToString());
}
public static float Round(float value, int digits)
{
float mult = Mathf.Pow(10.0f, (float)digits);
return Mathf.Round(value * mult) / mult;
}
}
MUCH appreciation and thanks for all of the help!