Files
DeviantMobile-Rohan/Assets/New Lowpoly Models/Scripts/Player/PlayerControllerNewRohan.cs
2026-07-21 08:58:18 +05:30

592 lines
14 KiB
C#

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<CharacterController>();
animator = GetComponent<Animator>();
stamina = GetComponent<Stamina>();
//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<Vector2>();
}
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<CashManager>();
if (cash != null)
{
int depositedAmount = cash.DepositAllCash();
TeamMember teamMember = GetComponent<TeamMember>();
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<TeamMember>();
float closestDistance = Mathf.Infinity;
Transform closestEnemy = null;
TeamMember[] allCharacters = FindObjectsOfType<TeamMember>();
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);
}