using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMovement : MonoBehaviour { [Header("Movement")] private float moveSpeed; public float walkSpeed; public float sprintSpeed; public float slideSpeed; PlayerStamina playerStamina; private float desiredMoveSpeed; private float lastDesiredMoveSpeed; public float speedIncreaseMultiplier; public float slopeIncreaseMultiplier; public float groundDrag; public float jumpForce; public float jumpCooldown; public float airMultiplier; bool readyToJump = true; public float jumpStaminaCost = 10; [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; private RaycastHit slopeHit; private bool exitingSlope; public Transform orientation; float horizontalInput; float verticalInput; Vector3 moveDirection; Rigidbody rb; public MovementState state; public bool cansprint = true; public enum MovementState { walking, sprinting, crouching, sliding, air, } public bool sliding; private void Start() { playerStamina = GetComponent(); rb = GetComponent(); rb.freezeRotation = true; readyToJump = true; startYScale = transform.localScale.y; } private void Update() { grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.1f, whatIsGround); MyInput(); SpeedControl(); StateHandler(); if (grounded) rb.drag = groundDrag; else rb.drag = 0; } private void StateHandler() { if(sliding) { state = MovementState.sliding; if (OnSlope() && rb.velocity.y < 0.1f) desiredMoveSpeed = slideSpeed; else desiredMoveSpeed = sprintSpeed; } else if (Input.GetKey(crouchKey)) { state = MovementState.crouching; desiredMoveSpeed = crouchSpeed; } else if (grounded && cansprint && Input.GetKey(sprintKey)) { state = MovementState.sprinting; desiredMoveSpeed = sprintSpeed; playerStamina.DecreaseStamina(); } else if (grounded) { state = MovementState.walking; desiredMoveSpeed = walkSpeed; } else { state = MovementState.air; } if(Mathf.Abs(desiredMoveSpeed - lastDesiredMoveSpeed) > 4f && moveSpeed !=0) { StopAllCoroutines(); StartCoroutine(SmoothlyLerpMoveSpeed()); } else { moveSpeed = desiredMoveSpeed; } lastDesiredMoveSpeed = desiredMoveSpeed; } private IEnumerator SmoothlyLerpMoveSpeed() { float time = 0; float difference = Mathf.Abs(desiredMoveSpeed - moveSpeed); float startValue = moveSpeed; while (time < difference) { moveSpeed = Mathf.Lerp(startValue, desiredMoveSpeed, time / difference); if (OnSlope()) { float slopeAngle = Vector3.Angle(Vector3.up, slopeHit.normal); float slopeAngleIncrease = 1 + (slopeAngle / 90f); time += Time.deltaTime * speedIncreaseMultiplier * slopeIncreaseMultiplier * slopeAngleIncrease; } else time += Time.deltaTime * speedIncreaseMultiplier; yield return null; } moveSpeed = desiredMoveSpeed; } private void FixedUpdate() { MovePlayer(); } private void MyInput() { horizontalInput = Input.GetAxisRaw("Horizontal"); verticalInput = Input.GetAxisRaw("Vertical"); if(Input.GetKey(jumpKey) && readyToJump && grounded && playerStamina.DecreaseByChunk(jumpStaminaCost)) { readyToJump = false; Jump(); Invoke(nameof(ResetJump), jumpCooldown); } if (Input.GetKeyDown(crouchKey)) { transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z); rb.AddForce(Vector3.down * 5f, ForceMode.Impulse); } if(Input.GetKeyUp(crouchKey)) { transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z); } } private void MovePlayer() { moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput; if (OnSlope() && !exitingSlope) { rb.AddForce(GetSlopeMoveDirection(moveDirection) * moveSpeed * 20f, ForceMode.Force); } if(grounded) rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force); else if(!grounded) rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force); // if (rb.velocity.y > 0) //rb.AddForce(Vector3.down * 80f, ForceMode.Force); } private void SpeedControl() { if (OnSlope() && !exitingSlope) { if (rb.velocity.magnitude > moveSpeed) rb.velocity = rb.velocity.normalized * moveSpeed; } else { Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z); if(flatVel.magnitude > moveSpeed) { Vector3 limitedVel = flatVel.normalized * moveSpeed; rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z); } } //text_speed.SetText("Speed: " + flatVel.magnitude); } private void Jump() { exitingSlope = true; rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z); rb.AddForce(transform.up * jumpForce, ForceMode.Impulse); } private void ResetJump() { readyToJump = 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 directon) { return Vector3.ProjectOnPlane(directon, slopeHit.normal).normalized; } }