using UnityEngine; using Mirror; [RequireComponent(typeof(Rigidbody))] public class Movement : NetworkBehaviour { [Header("Movement")] public float walkSpeed = 5f; public float sprintSpeed = 8f; public float crouchSpeed = 2.5f; public float jumpForce = 7f; public float airControl = 0.5f; public float groundDrag = 5f; public float airDrag = 1f; [Header("Ground Check")] public Transform groundCheck; public float groundDistance = 0.4f; public LayerMask groundMask; [Header("References")] public PlayerCameraController cameraController; public Transform orientation; private Rigidbody rb; private Vector3 moveDirection; private bool isGrounded; private float originalHeight; private Vector3 originalScale; private bool isCursorLocked = true; private void Start() { if (!isLocalPlayer) return; rb = GetComponent(); rb.freezeRotation = true; originalHeight = transform.localScale.y; originalScale = transform.localScale; if (cameraController == null) cameraController = GetComponentInChildren(); if (orientation == null) CreateOrientation(); UpdateCursorState(); } private void CreateOrientation() { orientation = new GameObject("Orientation").transform; orientation.parent = transform; orientation.localPosition = Vector3.zero; orientation.localRotation = Quaternion.identity; } private void Update() { if (!isLocalPlayer) return; HandleCursorToggle(); isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); if (cameraController != null) orientation.rotation = Quaternion.Euler(0, cameraController.transform.eulerAngles.y, 0); HandleJump(); HandleCrouch(); SpeedControl(); ApplyDrag(); } private void FixedUpdate() { if (!isLocalPlayer) return; MovePlayer(); } private void HandleCursorToggle() { if (Input.GetKeyDown(KeyCode.LeftAlt) || Input.GetKeyDown(KeyCode.RightAlt)) { ToggleCursor(); } } private void ToggleCursor() { isCursorLocked = !isCursorLocked; UpdateCursorState(); } private void UpdateCursorState() { Cursor.lockState = isCursorLocked ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = !isCursorLocked; if (cameraController != null) cameraController.enabled = isCursorLocked; } private void MovePlayer() { float horizontal = Input.GetAxisRaw("Horizontal"); float vertical = Input.GetAxisRaw("Vertical"); moveDirection = orientation.forward * vertical + orientation.right * horizontal; moveDirection = Vector3.ProjectOnPlane(moveDirection, Vector3.up).normalized; float currentSpeed = GetCurrentSpeed(); float speedMultiplier = isGrounded ? 1f : airControl; rb.AddForce(moveDirection * currentSpeed * 10f * speedMultiplier, ForceMode.Force); } private float GetCurrentSpeed() { if (Input.GetKey(KeyCode.LeftControl)) return crouchSpeed; if (Input.GetKey(KeyCode.LeftShift)) return sprintSpeed; return walkSpeed; } private void HandleJump() { if (Input.GetKeyDown(KeyCode.Space) && isGrounded) { rb.linearVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z); rb.AddForce(transform.up * jumpForce, ForceMode.Impulse); if (cameraController != null) cameraController.JumpEffect(); } } private void HandleCrouch() { bool shouldCrouch = Input.GetKey(KeyCode.LeftControl); float targetHeight = shouldCrouch ? originalHeight * 0.5f : originalHeight; Vector3 newScale = new Vector3(originalScale.x, targetHeight, originalScale.z); transform.localScale = Vector3.Lerp(transform.localScale, newScale, 10f * Time.deltaTime); if (cameraController != null) cameraController.SetCrouch(shouldCrouch); } private void SpeedControl() { Vector3 flatVel = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z); float currentMaxSpeed = GetCurrentSpeed(); if (flatVel.magnitude > currentMaxSpeed) { Vector3 limitedVel = flatVel.normalized * currentMaxSpeed; rb.linearVelocity = new Vector3(limitedVel.x, rb.linearVelocity.y, limitedVel.z); } if (rb.linearVelocity.y > 10f) rb.linearVelocity = new Vector3(rb.linearVelocity.x, 10f, rb.linearVelocity.z); } private void ApplyDrag() => rb.linearDamping = isGrounded ? groundDrag : airDrag; private void OnDrawGizmosSelected() { if (groundCheck != null) { Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(groundCheck.position, groundDistance); } } }