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
[Header("Nuclear Diagnostic (Siêu chẩn đoán)")]
public string forcePlayState = ""; // Gõ tên State vào đây để ép nó chạy (vd: Idle)
public bool showLayerWeights = false;
protected virtual void Start()
{
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ó!");
return;
}
// Chạy chẩn đoán hạt nhân
StartCoroutine(NuclearDiagnosticRoutine());
InitializeParameters();
}
private IEnumerator NuclearDiagnosticRoutine()
{
while (true)
{
yield return new WaitForSeconds(1f);
if (animator == null) yield break;
// 1. Kiểm tra Enabled
if (!animator.enabled)
Debug.LogError($"[NUCLEAR ALERT] Component Animator đang bị TẮT (enabled = false)!");
// 2. Kiểm tra Rig Type
if (animator.isHuman)
Debug.Log($"[Rig Info] Rig là Humanoid. Hãy chắc chắn các Animation cũng là Humanoid.");
else
Debug.LogWarning($"[Rig Info] Rig là Generic/Legacy. Nếu bạn dùng Animation Humanoid nó sẽ không chạy.");
// 3. Kiểm tra Layer Weight
if (showLayerWeights)
{
for (int i = 0; i < animator.layerCount; i++)
{
Debug.Log($"Layer {i} ({animator.GetLayerName(i)}): Weight = {animator.GetLayerWeight(i)}");
}
}
// 4. Ép chạy State nếu có yêu cầu
if (!string.IsNullOrEmpty(forcePlayState))
{
Debug.Log($"[Nuclear Force] ÉP CHẠY STATE: {forcePlayState}");
animator.Play(forcePlayState);
forcePlayState = ""; // Reset sau khi chạy
}
// 5. Kiểm tra vị trí xương (Nếu T-pose thì thường xương không đổi vị trí)
Vector3 handPos = animator.GetBoneTransform(HumanBodyBones.RightHand) ? animator.GetBoneTransform(HumanBodyBones.RightHand).position : Vector3.zero;
yield return new WaitForSeconds(0.1f);
if (handPos != Vector3.zero && Vector3.Distance(handPos, animator.GetBoneTransform(HumanBodyBones.RightHand).position) < 0.001f && animator.speed > 0)
{
// Nếu xương không nhúc nhích dù tốc độ > 0
Debug.LogWarning($"[NUCLEAR ALERT] CẢNH BÁO: Xương nhân vật không nhúc nhích! Có thể do Rig lỗi hoặc bị script khác khóa xương.");
}
if (!useSimulation) yield break;
}
}
protected virtual void InitializeParameters()
{
if (animator == null) return;
// Khởi tạo và kiểm tra từng tham số quan trọng
isDead = ValidateAndInit("isDead");
isGrounded = ValidateAndInit("IsGrounded");
isCrouching = ValidateAndInit("IsCrouching");
isStrafing = ValidateAndInit("IsStrafing");
isSliding = ValidateAndInit("IsSliding");
isSprinting = ValidateAndInit("IsSprinting");
isAiming = ValidateAndInit("IsAiming");
canAim = ValidateAndInit("CanAim");
flipAnimation = ValidateAndInit("FlipAnimation");
flipEquip = ValidateAndInit("FlipEquip");
groundDistance = ValidateAndInit("GroundDistance");
groundAngle = ValidateAndInit("GroundAngle");
verticalVelocity = ValidateAndInit("VerticalVelocity");
moveSet_ID = ValidateAndInit("MoveSet_ID");
upperBody_ID = ValidateAndInit("UpperBody_ID");
idleRandom = ValidateAndInit("IdleRandom");
idleRandomTrigger = ValidateAndInit("IdleRandomTrigger");
randomAttack = ValidateAndInit("RandomAttack");
weakAttack = ValidateAndInit("WeakAttack");
strongAttack = ValidateAndInit("StrongAttack");
isBlocking = ValidateAndInit("IsBlocking");
attackID = ValidateAndInit("AttackID");
defenseID = ValidateAndInit("DefenseID");
recoilID = ValidateAndInit("RecoilID");
reactionID = ValidateAndInit("ReactionID");
triggerRecoil = ValidateAndInit("TriggerRecoil");
triggerReaction = ValidateAndInit("TriggerReaction");
hitDirection = ValidateAndInit("HitDirection");
resetState = ValidateAndInit("ResetState");
reload = ValidateAndInit("Reload");
cancelReload = ValidateAndInit("CancelReload");
reloadID = ValidateAndInit("ReloadID");
shoot = ValidateAndInit("Shoot");
shot_ID = ValidateAndInit("Shot_ID");
powerCharger = ValidateAndInit("PowerCharger");
}
private vAnimatorParameter ValidateAndInit(string paramName)
{
vAnimatorParameter p = new vAnimatorParameter(animator, paramName);
if (!p.isValid && debugMode)
{
// Chỉ cảnh báo những biến cốt lõi nếu thiếu
if (paramName == "VerticalVelocity" || paramName == "IsGrounded" || paramName == "IsAiming")
Debug.LogWarning($"[AnimatorAI] Cảnh báo: Controller thiếu biến quan trọng: {paramName}");
}
return p;
}
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
}