using System; using Unity.VisualScripting; using UnityEngine; namespace OnlyScove.Scripts { public class PlayerController : MonoBehaviour { private static readonly int MoveAmount = Animator.StringToHash("moveAmount"); [SerializeField] private InputReader inputReader; [SerializeField] private float rotationSpeed = 500f; [SerializeField] private float moveSpeed = 10f; [SerializeField] private float jumpHeight = 2f; [SerializeField] private float animationDamping = 0.2f; [SerializeField] private float groundCheckRadius = 0.2f; [SerializeField] private Vector3 groundCheckOffset; [SerializeField] private LayerMask groundMask; CameraController cameraController; Animator animator; private CharacterController characterController; Quaternion targetRotation; private float horizontal; private float vertical; bool isGrounded; private bool wasGrounded; private bool hasControl = true; private float ySpeed; private void Awake() { if (Camera.main != null) cameraController = Camera.main.GetComponent(); animator = GetComponent(); characterController = GetComponent(); } private void OnEnable() { inputReader.OnJumpEvent += HandleJump; } private void OnDisable() { inputReader.OnJumpEvent -= HandleJump; } private void HandleJump() { if (isGrounded && hasControl) { // Công thức tính vận tốc nhảy: v = sqrt(h * -2 * g) ySpeed = Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y); } } private void Update() { horizontal = inputReader.MoveInput.x; vertical = inputReader.MoveInput.y; float moveAmount = Mathf.Clamp01(Math.Abs(horizontal) + Math.Abs(vertical)); var moveInput = (new Vector3(horizontal, 0, vertical)).normalized; var moveDirection = cameraController.PlanarRotation * moveInput; if (!hasControl) return; wasGrounded = isGrounded; GroundCheck(); // Phát hiện tiếp đất (Landing) if (isGrounded && !wasGrounded && ySpeed < -1f) { // Rung camera khi tiếp đất mạnh if (cameraController != null) { cameraController.Shake(0.2f, 0.15f); } } if (isGrounded && ySpeed < 0) { ySpeed = -2f; // Giữ nhân vật dính xuống mặt đất } else { ySpeed += Physics.gravity.y * Time.deltaTime; } var velocity = moveDirection * moveSpeed; velocity.y = ySpeed; characterController.Move(velocity * Time.deltaTime); if (moveAmount > 0) { targetRotation = Quaternion.LookRotation(moveDirection); } transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed); animator.SetFloat(MoveAmount, moveAmount, animationDamping, Time.deltaTime); } void GroundCheck() { isGrounded = Physics.CheckSphere(transform.TransformPoint(groundCheckOffset), groundCheckRadius, groundMask); } public void SetControl(bool control) { this.hasControl = control; characterController.enabled = hasControl; if (!hasControl) { animator.SetFloat(MoveAmount, 0f); targetRotation = transform.rotation; } } private void OnDrawGizmosSelected() { Gizmos.color = new Color(0, 1, 0, 0.5f); Gizmos.DrawSphere(transform.TransformPoint(groundCheckOffset), groundCheckRadius); } } }