Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Movement_Player.cs
- using TMPro;
- using UnityEngine;
- using UnityEngine.InputSystem;
- using UnityEngine.UI;
- using System.Collections;
- using System;
- using System.Runtime.CompilerServices;
- public class Movement_Player : MonoBehaviour
- {
- // ───────────────────────────────── Player Settings ─────────────────────────────────
- [Header("Movement Settings")]
- public float walkSpeed = 4f;
- public float sprintSpeed = 6f;
- public float crouchSpeed = 2f;
- public float crouchHeight = 0.5f;
- public float slideSpeed = 10f;
- public float airControl = 0.5f;
- public float groundBrakeSpeed = 10f; // just for smoothing the stopping phase of character
- public float jumpfactor = 1f;
- public float gravity = -20;
- public float jumpSlopeAngleThreshold = 25f; // Angle in degrees to consider a slope for jumping
- public enum CrouchMode
- {
- Toggle,
- Hold
- }
- public CrouchMode crouchMode = CrouchMode.Toggle; // Toggle or Hold
- public float thresholdSlideSpeed = 4f; // Speed threshold to start sliding
- public float steepSlopeThreshold = 15f; // Angle in degrees to consider a slope steep
- public float slideTimeOnGround = 0.5f; // Time to slide on ground before stopping
- public float SlopeSlideForceFactor = 30f; // Factor to apply when sliding down a slope
- public float slideHeight = 0.25f;
- [Header("Camera Settings")]
- public float minViewAngle = -45f;
- public float maxViewAngle = 45f;
- public float sens = 1f;
- public float smoothTime = 0.05f;
- public float transitionSpeed = 0.7f;
- public Camera playerCamera;
- [Header("Debug ")]
- public TextMeshProUGUI debugText1;
- public TextMeshProUGUI debugText2;
- public TextMeshProUGUI debugText3;
- public Button resetButton;
- public float calculatedSlideSpeed = 0f;
- // ───────────────────────────────── Runtime Variables ─────────────────────────────────
- private CharacterController characterController;
- private Vector2 input = Vector2.zero;
- private Vector2 look = Vector2.zero;
- private Vector2 smoothedLookInput;
- private float pitch = 0f;
- private bool isSprinting = false;
- private bool isJumping = false;
- private bool isMovingForward = false;
- private bool isCrouching = false;
- private bool isSliding = false;
- private float originalHeight = 0f;
- private int crouchCounter = 0;
- public float slopeAngle = 0f;
- private float slideTimer = 0f;
- private Vector3 slopeDir = Vector3.zero;
- private Vector3 slopeNormal = Vector3.up;
- private float speed = 0f;
- private Vector3 velocity = Vector3.zero;
- private Vector3 horizontalVelocity = Vector3.zero;
- private Vector3 currentVelocity = Vector3.zero;
- private Vector3 lastPosition = Vector3.zero;
- private float velAvg = 0f;
- private float totalDistance = 0f;
- private float totalTime = 0f;
- // ───────────────────────────────── Unity Methods ─────────────────────────────────
- void Start()
- {
- characterController = GetComponent<CharacterController>();
- Cursor.lockState = CursorLockMode.Locked;
- Cursor.visible = false;
- lastPosition = transform.position;
- if (resetButton != null)
- {
- resetButton.onClick.AddListener(() =>
- {
- totalDistance = 0f;
- totalTime = 0f;
- velAvg = 0f;
- });
- }
- originalHeight = playerCamera.transform.localPosition.y;
- }
- void Update()
- {
- HandleJump();
- HandleSlopes();
- ApplyGravity();
- AdjustVelocityToSlope();
- HandleSlide();
- HandleMovement();
- characterController.Move(velocity * Time.deltaTime);
- }
- void LateUpdate()
- {
- UpdateCamera();
- UpdateDebug();
- }
- // ───────────────────────────────── Movement ─────────────────────────────────
- void HandleMovement()
- {
- Vector3 moveInput = transform.right * input.x + transform.forward * input.y;
- if (moveInput.magnitude > 1f) moveInput.Normalize();
- float forwardAmount = Vector3.Dot(moveInput.normalized, transform.forward);
- bool isMovingForward = forwardAmount > 0.7f;
- speed =
- (isSliding && horizontalVelocity.magnitude >= thresholdSlideSpeed) ? calculatedSlideSpeed :
- (isCrouching) ? crouchSpeed :
- (isSprinting && isMovingForward) ? sprintSpeed :
- walkSpeed;
- Vector3 desiredVelocity = moveInput * speed;
- if (characterController.isGrounded)
- {
- if (input == Vector2.zero)
- horizontalVelocity = Vector3.Lerp(horizontalVelocity, Vector3.zero, groundBrakeSpeed * Time.deltaTime);
- else
- horizontalVelocity = desiredVelocity;
- }
- else
- {
- float lerpFactor = Mathf.Clamp01(airControl * Time.deltaTime);
- horizontalVelocity = Vector3.Lerp(horizontalVelocity, desiredVelocity, lerpFactor);
- }
- }
- void HandleJump()
- {
- isMovingForward = Vector3.Dot(-slopeDir, transform.forward) > 0.7f;
- if (slopeAngle > jumpSlopeAngleThreshold && isMovingForward)
- {
- // Don't allow jumping on steep slopes
- isJumping = false;
- return;
- }
- if (characterController.isGrounded && velocity.y < 0)
- velocity.y = -2f; // Stick to ground
- if (isJumping && characterController.isGrounded)
- {
- velocity.y += Mathf.Sqrt(jumpfactor * -2f * gravity);
- }
- }
- void HandleSlide()
- {
- if (isSliding && horizontalVelocity.magnitude >= thresholdSlideSpeed && characterController.isGrounded)
- {
- isCrouching = false;
- float slopeMultiplier = 1f + (Mathf.Clamp(-slopeAngle, 15f, 75f) - 15f) / 30f;
- calculatedSlideSpeed = slideSpeed * slopeMultiplier;
- if (Math.Abs(slopeAngle) < steepSlopeThreshold)
- {
- isSliding = true;
- slideTimer += Time.deltaTime;
- if (slideTimer >= slideTimeOnGround)
- {
- isSliding = false;
- slideTimer = 0f;
- }
- return;
- }
- else if (slopeAngle > 0)
- {
- isSliding = false;
- slideTimer = 0f;
- return;
- }
- else
- {
- isSliding = true;
- slideTimer = 0f;
- }
- // Slide vector, projected onto slope
- Vector3 rawSlide = slopeDir * calculatedSlideSpeed * Time.deltaTime;
- Vector3 adjustedSlide = Vector3.ProjectOnPlane(rawSlide, slopeNormal); // Keeps you stuck to slope
- // FIX: Only modify horizontal velocity, don't overwrite entire velocity
- horizontalVelocity += new Vector3(adjustedSlide.x, 0f, adjustedSlide.z);
- }
- else if (isSliding)
- {
- // FIX: Stop sliding if conditions aren't met
- isSliding = false;
- slideTimer = 0f;
- }
- }
- void HandleSlopes()
- {
- if (Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit, 2f))
- {
- Vector3 slopeNormalHit = hit.normal;
- slopeNormal = slopeNormalHit;
- float angle = Vector3.Angle(Vector3.up, slopeNormal);
- slopeDir = Vector3.ProjectOnPlane(Vector3.down, slopeNormal).normalized;
- float alignment = Vector3.Dot(transform.forward, slopeDir);
- slopeAngle = angle * -Mathf.Sign(alignment);
- }
- else
- {
- slopeAngle = 0f;
- }
- }
- void ApplyGravity()
- {
- velocity.y += gravity * Time.deltaTime;
- velocity = new Vector3(horizontalVelocity.x, velocity.y, horizontalVelocity.z);
- }
- void AdjustVelocityToSlope()
- {
- if (!characterController.isGrounded) return;
- Vector3 moveDir = new Vector3(velocity.x, 0f, velocity.z);
- Vector3 slopeMove = Vector3.ProjectOnPlane(moveDir, slopeNormal);
- if (Mathf.Abs(slopeAngle) > steepSlopeThreshold && !isJumping)
- {
- Vector3 slideDir = Vector3.ProjectOnPlane(Vector3.down, slopeNormal).normalized;
- velocity += slideDir * slideSpeed;
- }
- else
- {
- velocity = new Vector3(slopeMove.x, velocity.y, slopeMove.z);
- }
- }
- // ───────────────────────────────── Camera ─────────────────────────────────
- void UpdateCamera()
- {
- smoothedLookInput = Vector2.Lerp(smoothedLookInput, look, smoothTime);
- float mouseX = smoothedLookInput.x * sens * Time.deltaTime;
- float mouseY = smoothedLookInput.y * sens * Time.deltaTime;
- transform.Rotate(Vector3.up * mouseX);
- pitch -= mouseY;
- pitch = Mathf.Clamp(pitch, minViewAngle, maxViewAngle);
- playerCamera.transform.localRotation = Quaternion.Euler(pitch, 0f, 0f);
- }
- void UpdateCameraDuringMotionStates()
- {
- if (isSliding)
- {
- playerCamera.transform.localPosition =
- Vector3.Lerp(playerCamera.transform.localPosition,
- new Vector3(0f, slideHeight, 0f),
- Time.deltaTime * transitionSpeed);
- }
- else if (isCrouching)
- {
- playerCamera.transform.localPosition =
- Vector3.Lerp(playerCamera.transform.localPosition,
- new Vector3(0f, crouchHeight, 0f),
- Time.deltaTime * transitionSpeed);
- }
- else
- {
- playerCamera.transform.localPosition =
- Vector3.Lerp(playerCamera.transform.localPosition,
- new Vector3(0f, originalHeight, 0f),
- Time.deltaTime * transitionSpeed);
- }
- }
- // ───────────────────────────────── Debug ─────────────────────────────────
- void UpdateDebug()
- {
- currentVelocity = (transform.position - lastPosition) / Time.deltaTime;
- if (currentVelocity.magnitude > 0f)
- {
- totalDistance += currentVelocity.magnitude * Time.deltaTime;
- totalTime += Time.deltaTime;
- }
- velAvg = totalDistance / Mathf.Max(totalTime, 0.01f);
- lastPosition = transform.position;
- Debug.Log(currentVelocity.y);
- if (debugText1 != null) debugText1.text = "Current Vel: " + currentVelocity.ToString("F2") + " m/s";
- if (debugText2 != null) debugText2.text = "Avg Vel: " + velAvg.ToString("F2") + " m/s";
- //if (debugText1 != null) debugText1.text = isSliding ? "Sliding" : "";
- //if (debugText2 != null) debugText2.text = isCrouching ? "Crouching" : "";
- //if (debugText3 != null) debugText3.text = isSprinting ? "Walking/ Sprinting" : "";
- //Debug.Log(GetRealisticSlideMultiplier(Mathf.Abs(slopeAngle)));
- }
- // ───────────────────────────────── Input Actions ─────────────────────────────────
- public void Move(InputAction.CallbackContext context)
- {
- if (context.performed || context.canceled)
- input = context.ReadValue<Vector2>();
- }
- public void Look(InputAction.CallbackContext context)
- {
- look = context.ReadValue<Vector2>() * sens;
- }
- public void Jump(InputAction.CallbackContext context)
- {
- isJumping = context.performed;
- }
- public void Sprint(InputAction.CallbackContext context)
- {
- isSprinting = context.performed;
- }
- public void Crouch(InputAction.CallbackContext context)
- {
- if (context.started && crouchMode == CrouchMode.Toggle)
- {
- crouchCounter++;
- crouchCounter %= 2; // Toggle between 0 and 1
- if (crouchCounter == 1)
- isCrouching = true;
- else
- isCrouching = false;
- isSliding = true;
- return;
- }
- else if (context.performed && crouchMode == CrouchMode.Hold)
- isCrouching = true;
- else if (context.canceled && crouchMode == CrouchMode.Hold)
- isCrouching = false;
- }
- // ───────────────────────────────── Misc ─────────────────────────────────
- }
Advertisement
Add Comment
Please, Sign In to add comment