using UnityEngine; using UnityEngine.AI; using Invector; using System.Collections; /// /// AnimatorAI: Đồng bộ hóa trạng thái của EnemyAI với Animator. /// Tích hợp Simulation Mode để giả lập animation khi chưa có logic di chuyển hoàn chỉnh. /// public class AnimatorAI : MonoBehaviour { protected Animator animator; protected EnemyAI enemyAI; protected NavMeshAgent agent; protected Rigidbody rb; [Header("Debug Settings")] public bool debugMode = true; public Color debugColor = Color.cyan; [Header("Simulation Mode (Giả lập)")] public bool useSimulation = false; // Tích chọn để dùng thông số giả lập bên dưới public bool autoCycleSpeed = false; // Tự động chạy/đi bộ/đứng im theo vòng lặp [Range(0, 1)] public float simVerticalVelocity = 0f; public bool simIsSprinting = false; public bool simIsAiming = false; public int simMoveSetID = 0; [Header("Movement Settings")] public float sprintThreshold = 0.8f; public float dampTime = 0.1f; #region Animator Parameters (Invector Style) protected vAnimatorParameter isDead; protected vAnimatorParameter isGrounded; protected vAnimatorParameter isCrouching; protected vAnimatorParameter isStrafing; protected vAnimatorParameter isSliding; protected vAnimatorParameter isSprinting; protected vAnimatorParameter isAiming; protected vAnimatorParameter canAim; protected vAnimatorParameter flipAnimation; protected vAnimatorParameter flipEquip; protected vAnimatorParameter groundDistance; protected vAnimatorParameter groundAngle; protected vAnimatorParameter verticalVelocity; protected vAnimatorParameter moveSet_ID; protected vAnimatorParameter upperBody_ID; protected vAnimatorParameter idleRandom; protected vAnimatorParameter idleRandomTrigger; protected vAnimatorParameter randomAttack; protected vAnimatorParameter weakAttack; protected vAnimatorParameter strongAttack; protected vAnimatorParameter isBlocking; protected vAnimatorParameter attackID; protected vAnimatorParameter defenseID; protected vAnimatorParameter recoilID; protected vAnimatorParameter reactionID; protected vAnimatorParameter triggerRecoil; protected vAnimatorParameter triggerReaction; protected vAnimatorParameter hitDirection; protected vAnimatorParameter resetState; protected vAnimatorParameter reload; protected vAnimatorParameter cancelReload; protected vAnimatorParameter reloadID; protected vAnimatorParameter shoot; protected vAnimatorParameter shot_ID; protected vAnimatorParameter powerCharger; #endregion protected virtual void Start() { // Sử dụng GetComponentInChildren để tìm Animator ở các đối tượng con (khung Mesh) animator = GetComponentInChildren(); enemyAI = GetComponent(); agent = GetComponent(); rb = GetComponent(); if (animator == null) { Debug.LogError($"[AnimatorAI] KHÔNG tìm thấy Animator trên {gameObject.name} hoặc các con của nó!"); } else if (debugMode) { Debug.Log($"[AnimatorAI] Đã tìm thấy Animator trên đối tượng: {animator.gameObject.name}"); } InitializeParameters(); } protected virtual void InitializeParameters() { if (animator == null) return; isDead = new vAnimatorParameter(animator, "isDead"); isGrounded = new vAnimatorParameter(animator, "IsGrounded"); isCrouching = new vAnimatorParameter(animator, "IsCrouching"); isStrafing = new vAnimatorParameter(animator, "IsStrafing"); isSliding = new vAnimatorParameter(animator, "IsSliding"); isSprinting = new vAnimatorParameter(animator, "IsSprinting"); isAiming = new vAnimatorParameter(animator, "IsAiming"); canAim = new vAnimatorParameter(animator, "CanAim"); flipAnimation = new vAnimatorParameter(animator, "FlipAnimation"); flipEquip = new vAnimatorParameter(animator, "FlipEquip"); groundDistance = new vAnimatorParameter(animator, "GroundDistance"); groundAngle = new vAnimatorParameter(animator, "GroundAngle"); verticalVelocity = new vAnimatorParameter(animator, "VerticalVelocity"); moveSet_ID = new vAnimatorParameter(animator, "MoveSet_ID"); upperBody_ID = new vAnimatorParameter(animator, "UpperBody_ID"); idleRandom = new vAnimatorParameter(animator, "IdleRandom"); idleRandomTrigger = new vAnimatorParameter(animator, "IdleRandomTrigger"); randomAttack = new vAnimatorParameter(animator, "RandomAttack"); weakAttack = new vAnimatorParameter(animator, "WeakAttack"); strongAttack = new vAnimatorParameter(animator, "StrongAttack"); isBlocking = new vAnimatorParameter(animator, "IsBlocking"); attackID = new vAnimatorParameter(animator, "AttackID"); defenseID = new vAnimatorParameter(animator, "DefenseID"); recoilID = new vAnimatorParameter(animator, "RecoilID"); reactionID = new vAnimatorParameter(animator, "ReactionID"); triggerRecoil = new vAnimatorParameter(animator, "TriggerRecoil"); triggerReaction = new vAnimatorParameter(animator, "TriggerReaction"); hitDirection = new vAnimatorParameter(animator, "HitDirection"); resetState = new vAnimatorParameter(animator, "ResetState"); reload = new vAnimatorParameter(animator, "Reload"); cancelReload = new vAnimatorParameter(animator, "CancelReload"); reloadID = new vAnimatorParameter(animator, "ReloadID"); shoot = new vAnimatorParameter(animator, "Shoot"); shot_ID = new vAnimatorParameter(animator, "Shot_ID"); powerCharger = new vAnimatorParameter(animator, "PowerCharger"); } protected virtual void Update() { if (animator == null) return; if (useSimulation) { RunSimulation(); } else { if (enemyAI == null || agent == null) return; UpdateMovementParameters(); UpdateCombatParameters(); } } protected virtual void RunSimulation() { // 1. Giả lập tốc độ di chuyển if (autoCycleSpeed) { // Tạo vòng lặp tốc độ từ 0 đến 1 dùng hàm Sin simVerticalVelocity = Mathf.Abs(Mathf.Sin(Time.time * 0.5f)); simIsSprinting = simVerticalVelocity > sprintThreshold; } SetFloat(verticalVelocity, simVerticalVelocity, "SIM: VerticalVelocity"); SetBool(isSprinting, simIsSprinting, "SIM: IsSprinting"); SetBool(isGrounded, true, "SIM: IsGrounded"); // Luôn giả lập trên mặt đất // 2. Giả lập chiến đấu SetBool(isAiming, simIsAiming, "SIM: IsAiming"); SetInt(moveSet_ID, simMoveSetID, "SIM: MoveSet_ID"); SetBool(canAim, simIsAiming, "SIM: CanAim"); } protected virtual void UpdateMovementParameters() { bool grounded = agent.isOnNavMesh || agent.enabled; SetBool(isGrounded, grounded, "IsGrounded"); float speed = agent.velocity.magnitude / enemyAI.moveSpeed; SetFloat(verticalVelocity, speed, "VerticalVelocity"); bool sprinting = agent.velocity.magnitude > (enemyAI.moveSpeed * sprintThreshold); SetBool(isSprinting, sprinting, "IsSprinting"); bool isDodging = !agent.enabled && !rb.isKinematic; SetBool(flipAnimation, isDodging, "FlipAnimation (Dodge)"); } protected virtual void UpdateCombatParameters() { bool aiming = enemyAI.playerHasArtifact && agent.isStopped; SetBool(isAiming, aiming, "IsAiming"); int moveID = enemyAI.playerHasArtifact ? 1 : 0; SetInt(moveSet_ID, moveID, "MoveSet_ID"); SetBool(canAim, enemyAI.playerHasArtifact, "CanAim"); } #region Optimized Setters with Debug protected void SetBool(vAnimatorParameter param, bool value, string name) { if (param.isValid) { bool current = animator.GetBool(param); if (current != value) { animator.SetBool(param, value); if (debugMode) Debug.Log($"[AnimDebug] {gameObject.name}: {name} -> {value}"); } } } protected void SetFloat(vAnimatorParameter param, float value, string name) { if (param.isValid) { animator.SetFloat(param, value, dampTime, Time.deltaTime); } } protected void SetInt(vAnimatorParameter param, int value, string name) { if (param.isValid) { int current = animator.GetInteger(param); if (current != value) { animator.SetInteger(param, value); if (debugMode) Debug.Log($"[AnimDebug] {gameObject.name}: {name} -> {value}"); } } } #endregion #region Helper Methods (Triggers) public virtual void SetAnimatorTrigger(vAnimatorParameter trigger, string name = "Trigger") { if (trigger.isValid) { if (debugMode) Debug.Log($"[AnimDebug] {gameObject.name}: Kích hoạt {name}"); StartCoroutine(SetTriggerRoutine(trigger)); } } private IEnumerator SetTriggerRoutine(int targetHash) { animator.SetTrigger(targetHash); yield return new WaitForSeconds(0.1f); animator.ResetTrigger(targetHash); } #endregion }