using Cinemachine; using System.Collections; using TMPro; using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(CharacterController))] public class PlayerControllerNewRohan : MonoBehaviour { [Header("Movement")] [SerializeField] private float walkSpeed = 3f; [SerializeField] private float runSpeed = 6f; [SerializeField] private float rotationSpeed = 10f; private Stamina stamina; [Header("References")] private CharacterController controller; private Animator animator; [Header("State")] private bool isAttacking; private bool canMove = true; [Header("Gravity")] [SerializeField] private float gravity = -9.81f; [SerializeField] private float groundCheckDistance = 0.2f; [Header("Combat")] public float attackRange = 3f; // adjust in inspector private float verticalVelocity; // Input private Vector2 moveInput; private bool sprintInput; private float currentSpeed; public Joystick joystick; public GameObject rightHandPunchHitbox; public GameObject leftHandPunchHitbox; public GameObject rightFootKickHitbox; public GameObject leftFootKickHitbox; public TrailRenderer rightHandTrail; public TrailRenderer leftHandTrail; public TrailRenderer rightFootTrail; public TrailRenderer leftFootTrail; public Transform target; // assign enemy in inspector [Header("Camera FOV")] [SerializeField] private CinemachineFreeLook freeLookCam; [SerializeField] private float normalFOV = 60f; [SerializeField] private float sprintFOV = 75f; [SerializeField] private float fovSpeed = 5f; [SerializeField] private float walkStepInterval = 0.5f; [SerializeField] private float runStepInterval = 0.3f; private float footstepTimer; private Coroutine attackRoutine; private bool isDepositing; private Coroutine depositRoutine; private bool isOpeningVault; [Header("Deposit Effect")] [SerializeField] private ParticleSystem depositAura; void Awake() { controller = GetComponent(); animator = GetComponent(); stamina = GetComponent(); //StopDepositEffect(); } private void Start() { //Cursor.lockState = CursorLockMode.Locked; //Cursor.visible = false; } void Update() { HandleMovement(); } // ---------------- MOVEMENT ---------------- void HandleMovement() { if (!canMove || isAttacking) return; // -------- CAMERA RELATIVE MOVE -------- Vector3 camForward = Camera.main.transform.forward; Vector3 camRight = Camera.main.transform.right; camForward.y = 0; camRight.y = 0; camForward.Normalize(); camRight.Normalize(); Vector3 move = camForward * moveInput.y + camRight * moveInput.x; bool isMoving = move.magnitude > 0.1f; if (isMoving) SetTrails(true); else if (!isAttacking) SetTrails(false); // Sprint only if moving bool isRunning = sprintInput && isMoving && stamina.currentStamina > 0f; if (isRunning) { stamina.UseStamina(20f * Time.deltaTime); } else if (!isAttacking && !sprintInput) // key fix { stamina.RecoverStamina(10f * Time.deltaTime); } HandleFootsteps(isMoving, isRunning); if (freeLookCam != null) { float targetFOV = isRunning ? sprintFOV : normalFOV; // Apply to all rigs (top, middle, bottom) freeLookCam.m_Lens.FieldOfView = Mathf.Lerp( freeLookCam.m_Lens.FieldOfView, targetFOV, Time.deltaTime * fovSpeed ); } currentSpeed = isRunning ? runSpeed : walkSpeed; // -------- GRAVITY -------- if (controller.isGrounded && verticalVelocity < 0) { verticalVelocity = -2f; // keeps player grounded } verticalVelocity += gravity * Time.deltaTime; // -------- FINAL MOVE -------- Vector3 finalMove = move * currentSpeed; finalMove.y = verticalVelocity; controller.Move(finalMove * Time.deltaTime); // -------- ROTATION -------- if (isMoving) { Quaternion targetRotation = Quaternion.LookRotation(move); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); } // -------- ANIMATION -------- float targetSpeed = move.magnitude * (isRunning ? 2f : 1f); animator.SetFloat("Speed", targetSpeed, 0.1f, Time.deltaTime); } // ---------------- INPUT CALLBACKS ---------------- public void OnMove(InputAction.CallbackContext context) { moveInput = context.ReadValue(); } public void OnSprint(InputAction.CallbackContext context) { sprintInput = context.ReadValueAsButton(); } // ---------------- ATTACKS ---------------- public void OnAttack1(InputAction.CallbackContext ctx) { if (ctx.performed) { attackRoutine = StartCoroutine(PlayAttack("Haymaker", 1f)); } } public void OnAttack2(InputAction.CallbackContext ctx) { if (ctx.performed) { if (ctx.performed) StartCoroutine(PlayAttack("LeftKick", 1.5f)); } } public void OnAttack3(InputAction.CallbackContext ctx) { if (ctx.performed) { if (ctx.performed) StartCoroutine(PlayAttack("LowKick", 1.5f)); } } public void OnAttack4(InputAction.CallbackContext ctx) { if (ctx.performed) { if (ctx.performed) StartCoroutine(PlayAttack("ElbowSmash", 0.6f)); } } public void OnAttack5(InputAction.CallbackContext ctx) { if (ctx.performed) { if (ctx.performed) StartCoroutine(PlayAttack("SpinningBackFist", 1f)); } } public void OnAttack6(InputAction.CallbackContext ctx) { if (ctx.performed) { if (ctx.performed) StartCoroutine(PlayAttack("BicycleKick", 1f)); } } public void PunchTap() { StartCoroutine(PlayAttack("Haymaker", 1f)); } public void PunchHold() { StartCoroutine(PlayAttack("ElbowSmash", 0.6f)); } public void KickTap() { StartCoroutine(PlayAttack("LeftKick", 1.5f)); } public void KickHold() { StartCoroutine(PlayAttack("LowKick", 1.5f)); } public void SpecialTap() { StartCoroutine(PlayAttack("SpinningBackFist", 1f)); } public void SpecialHold() { StartCoroutine(PlayAttack("BicycleKick", 1f)); } IEnumerator PlayAttack(string trigger, float distance) { CancelVaultOpening(); if (isAttacking) yield break; if (!stamina.UseStamina(15f)) yield break; isAttacking = true; canMove = false; FindClosestEnemy(); FaceTarget(); SetTrails(true); if (IsTargetInRange()) { SetAttackDistance(distance); } animator.SetTrigger(trigger); yield return new WaitForSeconds(1f); SetTrails(false); canMove = true; isAttacking = false; } public void CancelAttack() { if (!isAttacking) return; if (attackRoutine != null) { StopCoroutine(attackRoutine); attackRoutine = null; } isAttacking = false; canMove = true; SetTrails(false); // reset attack triggers animator.ResetTrigger("Haymaker"); animator.ResetTrigger("LeftKick"); animator.ResetTrigger("LowKick"); animator.ResetTrigger("ElbowSmash"); animator.ResetTrigger("SpinningBackFist"); animator.ResetTrigger("BicycleKick"); // NO animator.SetTrigger("Hit") here } public void PlayWhoosh() { AudioManager.Instance.PlaySFX("PunchWhoosh"); } bool IsTargetInRange() { if (target == null) return false; float dist = Vector3.Distance(transform.position, target.position); return dist <= attackRange; } void SetAttackDistance(float distance) { if (target == null) return; // direction from enemy player Vector3 dir = (transform.position - target.position).normalized; dir.y = 0; // place player at fixed distance Vector3 newPos = target.position + dir * distance; transform.position = newPos; } public void StartDeposit(float depositTime) { if (isDepositing) return; StartDepositEffect(); depositRoutine = StartCoroutine(DepositRoutine(depositTime)); } IEnumerator DepositRoutine(float depositTime) { isDepositing = true; float timer = depositTime; while (timer > 0) { UI_Manager.Instance?.UpdateDepositTimer(timer); timer -= Time.deltaTime; yield return null; } UI_Manager.Instance?.HideDepositTimer(); CashManager cash = GetComponent(); if (cash != null) { int depositedAmount = cash.DepositAllCash(); TeamMember teamMember = GetComponent(); DepositStationManager.Instance.AddCash( depositedAmount, teamMember.CurrentTeam ); } StopDepositEffect(); canMove = true; isDepositing = false; } public void CancelDeposit() { if (!isDepositing) return; if (depositRoutine != null) { StopCoroutine(depositRoutine); depositRoutine = null; } UI_Manager.Instance?.HideDepositTimer(); StopDepositEffect(); isDepositing = false; } void FaceTarget() { if (target == null) return; Vector3 dir = target.position - transform.position; dir.y = 0; if (dir.sqrMagnitude > 0.01f) { transform.rotation = Quaternion.LookRotation(dir); } } private void FindClosestEnemy() { TeamMember myTeam = GetComponent(); float closestDistance = Mathf.Infinity; Transform closestEnemy = null; TeamMember[] allCharacters = FindObjectsOfType(); foreach (TeamMember character in allCharacters) { if (character == myTeam) continue; if (character.CurrentTeam == myTeam.CurrentTeam) continue; float distance = Vector3.Distance(transform.position, character.transform.position); if (distance < closestDistance) { closestDistance = distance; closestEnemy = character.transform; } } target = closestEnemy; } public void PlayVaultOpen(System.Action onComplete) { StartCoroutine(VaultRoutine(onComplete)); } IEnumerator VaultRoutine(System.Action onComplete) { canMove = false; isOpeningVault = true; animator.SetTrigger("OpenVault"); float timer = 6f; while (timer > 0) { if (!isOpeningVault) { UI_Manager.Instance?.HideActionTimer(); canMove = true; yield break; } UI_Manager.Instance?.UpdateActionTimer( "Opening Vault", timer); timer -= Time.deltaTime; yield return null; } UI_Manager.Instance?.HideActionTimer(); canMove = true; isOpeningVault = false; onComplete?.Invoke(); } public void CancelVaultOpening() { if (!isOpeningVault) return; isOpeningVault = false; animator.ResetTrigger("OpenVault"); canMove = true; UI_Manager.Instance?.HideActionTimer(); } public void PlayPickupAnimation() { if (animator != null) { animator.SetTrigger("Pickup"); } } void SetTrails(bool state) { rightHandTrail.emitting = state; leftHandTrail.emitting = state; rightFootTrail.emitting = state; leftFootTrail.emitting = state; } public void StartDepositEffect() { if (depositAura != null) depositAura.Play(); } public void StopDepositEffect() { if (depositAura != null) depositAura.Stop(); } // Disable player movement (call at animation start) public void DisableMovement() { canMove = false; } // Enable player movement (call at animation end) public void EnableMovement() { canMove = true; } void HandleFootsteps(bool isMoving, bool isRunning) { if (!controller.isGrounded) { footstepTimer = 0f; return; } if (!isMoving) { footstepTimer = 0f; return; } float interval = isRunning ? runStepInterval : walkStepInterval; footstepTimer += Time.deltaTime; if (footstepTimer >= interval) { footstepTimer = 0f; AudioManager.Instance.PlayFootstep(isRunning); } } public void EnableRightHandPunchHitbox() => rightHandPunchHitbox.SetActive(true); public void DisableRightHandPunchHitbox() => rightHandPunchHitbox.SetActive(false); public void EnableLeftHandPunchHitbox() => leftHandPunchHitbox.SetActive(true); public void DisableLeftHandPunchHitbox() => leftHandPunchHitbox.SetActive(false); public void EnableLeftFootKickHitbox() => leftFootKickHitbox.SetActive(true); public void DisableLeftFootKickHitbox() => leftFootKickHitbox.SetActive(false); public void EnableRightFootKickHitbox() => rightFootKickHitbox.SetActive(true); public void DisableRightFootKickHitbox() => rightFootKickHitbox.SetActive(false); }