From a6110a814c166a56f68e626b3ad4935554501288 Mon Sep 17 00:00:00 2001 From: ngtuanz1 Date: Fri, 5 Jun 2026 16:26:04 +0700 Subject: [PATCH] ahahahahahah --- Assets/Prefabs/NPC/xNPC.prefab | 52 ++++-- Assets/Scripts/AI NPC/AnimatorAI.cs | 247 +++++++++++++++++++++++++++- 2 files changed, 282 insertions(+), 17 deletions(-) diff --git a/Assets/Prefabs/NPC/xNPC.prefab b/Assets/Prefabs/NPC/xNPC.prefab index bfd33362..247b00d8 100644 --- a/Assets/Prefabs/NPC/xNPC.prefab +++ b/Assets/Prefabs/NPC/xNPC.prefab @@ -453,6 +453,8 @@ GameObject: - component: {fileID: 5770331367975928816} - component: {fileID: 4112854993683970537} - component: {fileID: 3240800621832008763} + - component: {fileID: 8239948856752686218} + - component: {fileID: 3321677048699702084} m_Layer: 0 m_Name: xNPC m_TagString: Untagged @@ -491,23 +493,15 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::EnemyAI player: {fileID: 0} - viewAngle: 90 - viewRadius: 20 - targetLayerMask: - serializedVersion: 2 - m_Bits: 0 - obstacleLayerMask: - serializedVersion: 2 - m_Bits: 0 - patrolPoints: [] moveSpeed: 3 - chaseSpeed: 5 + rotateSpeed: 50 + patrolPoints: [] + patrolWaitTime: 2 playerHasArtifact: 0 laserPrefab: {fileID: 3965388737199864462, guid: fbec2b501d70daa4c9cb481ba53fc0b8, type: 3} firePoint: {fileID: 5863061020199015852} minShootDelay: 1 maxShootDelay: 3 - rotateSpeed: 50 dodgeForce: 8 dodgeDuration: 0.5 dodgeCooldown: 3 @@ -575,6 +569,42 @@ MonoBehaviour: textDisplay: {fileID: 4454520411962799200} canvasGroup: {fileID: 1620994605374968907} bubbleRect: {fileID: 6775114823217050358} +--- !u!114 &8239948856752686218 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7522161431095319480} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 210b37cfe4a84a34a91d0a9e58856a60, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FieldOfView + viewAngle: 90 + viewRadius: 20 + obstacleLayerMask: + serializedVersion: 2 + m_Bits: 128 + targetLayerMask: + serializedVersion: 2 + m_Bits: 256 + canSeePlayer: 0 + lastKnownPlayerPosition: {x: 0, y: 0, z: 0} +--- !u!114 &3321677048699702084 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7522161431095319480} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 35bba55c2a743d042ab1fff35e29db50, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::AnimatorAI + sprintThreshold: 0.8 + dampTime: 0.1 --- !u!1001 &7561534673732472622 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/AI NPC/AnimatorAI.cs b/Assets/Scripts/AI NPC/AnimatorAI.cs index 7d96529a..695cfb0c 100644 --- a/Assets/Scripts/AI NPC/AnimatorAI.cs +++ b/Assets/Scripts/AI NPC/AnimatorAI.cs @@ -1,16 +1,251 @@ 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 { - // Start is called once before the first execution of Update after the MonoBehaviour is created - void Start() + 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(); } - // Update is called once per frame - void Update() + 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 }