update
This commit is contained in:
36
.idea/.idea.HALLUCINATE/.idea/workspace.xml
generated
36
.idea/.idea.HALLUCINATE/.idea/workspace.xml
generated
@@ -6,34 +6,8 @@
|
|||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
|
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/NPC/xNPC.prefab" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/NPC/xNPC.prefab" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Assets/Scripts/AI NPC/AnimatorAI.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/AI NPC/AnimatorAI.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/projectile/_LazerPrọectile.prefab" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/projectile/_LazerPrọectile.prefab" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Assets/Scripts/AI NPC/EnemyAI.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/AI NPC/EnemyAI.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scenes/Cho môn AI/Only AI.unity" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scenes/Cho môn AI/Only AI.unity" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scripts/AI NPC/LaserProjectile.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/AI NPC/LaserProjectile.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Player/CharacterController/vThirdPersonController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Player/CharacterController/vThirdPersonController.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UIElements.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UIElements.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/Unity.Multiplayer.PlayMode.Editor.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/Unity.Multiplayer.PlayMode.Editor.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/Unity.Profiling.Editor.UI.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/Unity.Profiling.Editor.UI.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/Unity.Profiling.Editor.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/Unity.Profiling.Editor.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/Unity.UI.Builder.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/Unity.UI.Builder.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/Unity.UIToolkit.Editor.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/Unity.UIToolkit.Editor.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Accessibility.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Accessibility.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Audio.UIElements.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Audio.UIElements.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Inspector.GraphicsSettingsInspectors.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Inspector.GraphicsSettingsInspectors.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Inspector.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Inspector.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Overlays.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Overlays.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Rendering.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Rendering.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Search.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Search.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.ShaderGraph.Drawing.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.ShaderGraph.Drawing.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.ShortcutManagement.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.ShortcutManagement.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Toolbars.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.Toolbars.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.U2D.Sprites.SpriteEditorTool.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.U2D.Sprites.SpriteEditorTool.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.ProjectSettings.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.ProjectSettings.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEditor.UIElements.xsd" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/UIElementsSchema/UnityEngine.UIElements.xsd" beforeDir="false" afterPath="$PROJECT_DIR$/UIElementsSchema/UnityEngine.UIElements.xsd" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -98,7 +72,7 @@
|
|||||||
}</component>
|
}</component>
|
||||||
<component name="RunManager" selected="Attach to Unity Editor.Attach to Unity Editor">
|
<component name="RunManager" selected="Attach to Unity Editor.Attach to Unity Editor">
|
||||||
<configuration name="Standalone Player" type="RunUnityExe" factoryName="Unity Executable">
|
<configuration name="Standalone Player" type="RunUnityExe" factoryName="Unity Executable">
|
||||||
<option name="EXE_PATH" value="$PROJECT_DIR$/Build\HALLUCINATE.exe" />
|
<option name="EXE_PATH" value="$PROJECT_DIR$/../Build test\HALLUCINATE.exe" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="" />
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="D:\BAI MUTIPLAY" />
|
<option name="WORKING_DIRECTORY" value="D:\BAI MUTIPLAY" />
|
||||||
<option name="PASS_PARENT_ENVS" value="1" />
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
@@ -127,7 +101,7 @@
|
|||||||
<option name="MIXED_MODE_DEBUG" value="0" />
|
<option name="MIXED_MODE_DEBUG" value="0" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="Attach to Unity Editor" type="UNITY_DEBUG_RUN_CONFIGURATION" factoryName="Unity Debug" show_console_on_std_err="false" show_console_on_std_out="false" port="50000" address="localhost" useMixedMode="false">
|
<configuration name="Attach to Unity Editor" type="UNITY_DEBUG_RUN_CONFIGURATION" factoryName="Unity Debug" show_console_on_std_err="false" show_console_on_std_out="false" port="50000" address="localhost">
|
||||||
<option name="allowRunningInParallel" value="false" />
|
<option name="allowRunningInParallel" value="false" />
|
||||||
<option name="listenPortForConnections" value="false" />
|
<option name="listenPortForConnections" value="false" />
|
||||||
<option name="pid" />
|
<option name="pid" />
|
||||||
@@ -138,6 +112,7 @@
|
|||||||
<option name="selectedOptions">
|
<option name="selectedOptions">
|
||||||
<list />
|
<list />
|
||||||
</option>
|
</option>
|
||||||
|
<option name="useMixedMode" value="false" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="Attach to" type="UnityDevicePlayer" factoryName="UnityAttachToDevicePlayer">
|
<configuration name="Attach to" type="UnityDevicePlayer" factoryName="UnityAttachToDevicePlayer">
|
||||||
@@ -204,6 +179,7 @@
|
|||||||
<workItem from="1780409218377" duration="9852000" />
|
<workItem from="1780409218377" duration="9852000" />
|
||||||
<workItem from="1780494322686" duration="643000" />
|
<workItem from="1780494322686" duration="643000" />
|
||||||
<workItem from="1780633654231" duration="23904000" />
|
<workItem from="1780633654231" duration="23904000" />
|
||||||
|
<workItem from="1780674685197" duration="1960000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -1,307 +1,199 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.AI;
|
using UnityEngine.AI;
|
||||||
using Invector;
|
using Invector;
|
||||||
|
using Invector.vEventSystems;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AnimatorAI: Đồng bộ hóa trạng thái của EnemyAI với Animator.
|
/// AnimatorAI: Advanced Invector-style Animator synchronization for EnemyAI.
|
||||||
/// Tích hợp Simulation Mode để giả lập animation khi chưa có logic di chuyển hoàn chỉnh.
|
/// Resolves T-pose by ensuring all core Invector parameters are correctly synced.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AnimatorAI : MonoBehaviour
|
public class AnimatorAI : MonoBehaviour, vIAnimatorStateInfoController
|
||||||
{
|
{
|
||||||
protected Animator animator;
|
protected Animator animator;
|
||||||
protected EnemyAI enemyAI;
|
protected EnemyAI enemyAI;
|
||||||
protected NavMeshAgent agent;
|
protected NavMeshAgent agent;
|
||||||
protected Rigidbody rb;
|
protected Rigidbody rb;
|
||||||
|
protected vHealthController healthController;
|
||||||
[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")]
|
[Header("Movement Settings")]
|
||||||
public float sprintThreshold = 0.8f;
|
public float sprintThreshold = 0.8f;
|
||||||
public float dampTime = 0.1f;
|
public float dampTime = 0.1f;
|
||||||
|
public float groundDistanceValue = 0.05f;
|
||||||
|
|
||||||
|
public vAnimatorStateInfos animatorStateInfos { get; protected set; }
|
||||||
|
|
||||||
#region Animator Parameters (Invector Style)
|
#region Animator Parameters (Invector Style)
|
||||||
protected vAnimatorParameter isDead;
|
protected vAnimatorParameter isDead;
|
||||||
protected vAnimatorParameter isGrounded;
|
protected vAnimatorParameter isGrounded;
|
||||||
protected vAnimatorParameter isCrouching;
|
|
||||||
protected vAnimatorParameter isStrafing;
|
protected vAnimatorParameter isStrafing;
|
||||||
protected vAnimatorParameter isSliding;
|
|
||||||
protected vAnimatorParameter isSprinting;
|
protected vAnimatorParameter isSprinting;
|
||||||
protected vAnimatorParameter isAiming;
|
protected vAnimatorParameter isAiming;
|
||||||
protected vAnimatorParameter canAim;
|
|
||||||
protected vAnimatorParameter flipAnimation;
|
|
||||||
protected vAnimatorParameter flipEquip;
|
|
||||||
protected vAnimatorParameter groundDistance;
|
|
||||||
protected vAnimatorParameter groundAngle;
|
|
||||||
protected vAnimatorParameter verticalVelocity;
|
protected vAnimatorParameter verticalVelocity;
|
||||||
|
protected vAnimatorParameter horizontalVelocity;
|
||||||
|
protected vAnimatorParameter groundDistance;
|
||||||
protected vAnimatorParameter moveSet_ID;
|
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 attackID;
|
||||||
protected vAnimatorParameter defenseID;
|
|
||||||
protected vAnimatorParameter recoilID;
|
|
||||||
protected vAnimatorParameter reactionID;
|
|
||||||
protected vAnimatorParameter triggerRecoil;
|
|
||||||
protected vAnimatorParameter triggerReaction;
|
|
||||||
protected vAnimatorParameter hitDirection;
|
protected vAnimatorParameter hitDirection;
|
||||||
|
protected vAnimatorParameter reactionID;
|
||||||
|
protected vAnimatorParameter triggerReaction;
|
||||||
protected vAnimatorParameter resetState;
|
protected vAnimatorParameter resetState;
|
||||||
protected vAnimatorParameter reload;
|
|
||||||
protected vAnimatorParameter cancelReload;
|
|
||||||
protected vAnimatorParameter reloadID;
|
|
||||||
protected vAnimatorParameter shoot;
|
|
||||||
protected vAnimatorParameter shot_ID;
|
|
||||||
protected vAnimatorParameter powerCharger;
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
[Header("Nuclear Diagnostic (Siêu chẩn đoán)")]
|
protected Vector3 lastPosition;
|
||||||
public string forcePlayState = ""; // Gõ tên State vào đây để ép nó chạy (vd: Idle)
|
protected float currentV;
|
||||||
public bool showLayerWeights = false;
|
protected float currentH;
|
||||||
|
|
||||||
protected virtual void Start()
|
protected virtual void Awake()
|
||||||
{
|
{
|
||||||
animator = GetComponentInChildren<Animator>();
|
animator = GetComponentInChildren<Animator>();
|
||||||
enemyAI = GetComponent<EnemyAI>();
|
enemyAI = GetComponent<EnemyAI>();
|
||||||
agent = GetComponent<NavMeshAgent>();
|
agent = GetComponent<NavMeshAgent>();
|
||||||
rb = GetComponent<Rigidbody>();
|
rb = GetComponent<Rigidbody>();
|
||||||
|
healthController = GetComponent<vHealthController>();
|
||||||
|
|
||||||
if (animator == null)
|
if (animator)
|
||||||
{
|
{
|
||||||
Debug.LogError($"<color=red>[AnimatorAI]</color> KHÔNG tìm thấy Animator trên {gameObject.name} hoặc các con của nó!");
|
animatorStateInfos = new vAnimatorStateInfos(animator);
|
||||||
return;
|
InitializeParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chạy chẩn đoán hạt nhân
|
lastPosition = transform.position;
|
||||||
StartCoroutine(NuclearDiagnosticRoutine());
|
|
||||||
|
|
||||||
InitializeParameters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator NuclearDiagnosticRoutine()
|
protected virtual void OnEnable()
|
||||||
{
|
{
|
||||||
while (true)
|
this.Register();
|
||||||
{
|
if (healthController) healthController.onReceiveDamage.AddListener(OnReceiveDamage);
|
||||||
yield return new WaitForSeconds(1f);
|
}
|
||||||
|
|
||||||
if (animator == null) yield break;
|
protected virtual void OnDisable()
|
||||||
|
{
|
||||||
// 1. Kiểm tra Enabled
|
this.UnRegister();
|
||||||
if (!animator.enabled)
|
if (healthController) healthController.onReceiveDamage.RemoveListener(OnReceiveDamage);
|
||||||
Debug.LogError($"<color=red>[NUCLEAR ALERT]</color> Component Animator đang bị TẮT (enabled = false)!");
|
|
||||||
|
|
||||||
// 2. Kiểm tra Rig Type
|
|
||||||
if (animator.isHuman)
|
|
||||||
Debug.Log($"<color=white>[Rig Info]</color> Rig là Humanoid. Hãy chắc chắn các Animation cũng là Humanoid.");
|
|
||||||
else
|
|
||||||
Debug.LogWarning($"<color=yellow>[Rig Info]</color> 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($"<color=magenta>[Nuclear Force]</color> É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($"<color=red>[NUCLEAR ALERT]</color> 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()
|
protected virtual void InitializeParameters()
|
||||||
{
|
{
|
||||||
if (animator == null) return;
|
isDead = new vAnimatorParameter(animator, "isDead");
|
||||||
|
isGrounded = new vAnimatorParameter(animator, "IsGrounded");
|
||||||
// Khởi tạo và kiểm tra từng tham số quan trọng
|
isStrafing = new vAnimatorParameter(animator, "IsStrafing");
|
||||||
isDead = ValidateAndInit("isDead");
|
isSprinting = new vAnimatorParameter(animator, "IsSprinting");
|
||||||
isGrounded = ValidateAndInit("IsGrounded");
|
isAiming = new vAnimatorParameter(animator, "IsAiming");
|
||||||
isCrouching = ValidateAndInit("IsCrouching");
|
verticalVelocity = new vAnimatorParameter(animator, "VerticalVelocity");
|
||||||
isStrafing = ValidateAndInit("IsStrafing");
|
horizontalVelocity = new vAnimatorParameter(animator, "HorizontalVelocity");
|
||||||
isSliding = ValidateAndInit("IsSliding");
|
groundDistance = new vAnimatorParameter(animator, "GroundDistance");
|
||||||
isSprinting = ValidateAndInit("IsSprinting");
|
moveSet_ID = new vAnimatorParameter(animator, "MoveSet_ID");
|
||||||
isAiming = ValidateAndInit("IsAiming");
|
attackID = new vAnimatorParameter(animator, "AttackID");
|
||||||
canAim = ValidateAndInit("CanAim");
|
hitDirection = new vAnimatorParameter(animator, "HitDirection");
|
||||||
flipAnimation = ValidateAndInit("FlipAnimation");
|
reactionID = new vAnimatorParameter(animator, "ReactionID");
|
||||||
flipEquip = ValidateAndInit("FlipEquip");
|
triggerReaction = new vAnimatorParameter(animator, "TriggerReaction");
|
||||||
groundDistance = ValidateAndInit("GroundDistance");
|
resetState = new vAnimatorParameter(animator, "ResetState");
|
||||||
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($"<color=yellow>[AnimatorAI]</color> Cảnh báo: Controller thiếu biến quan trọng: <b>{paramName}</b>");
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Update()
|
protected virtual void Update()
|
||||||
{
|
{
|
||||||
if (animator == null) return;
|
if (animator == null || enemyAI == null || agent == null) return;
|
||||||
|
|
||||||
if (useSimulation)
|
UpdateMovementParameters();
|
||||||
{
|
UpdateCombatParameters();
|
||||||
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()
|
protected virtual void UpdateMovementParameters()
|
||||||
{
|
{
|
||||||
|
// 1. Grounded & GroundDistance (Critical for T-pose prevention)
|
||||||
bool grounded = agent.isOnNavMesh || agent.enabled;
|
bool grounded = agent.isOnNavMesh || agent.enabled;
|
||||||
SetBool(isGrounded, grounded, "IsGrounded");
|
SetBool(isGrounded, grounded);
|
||||||
|
SetFloat(groundDistance, grounded ? 0f : groundDistanceValue);
|
||||||
|
|
||||||
float speed = agent.velocity.magnitude / enemyAI.moveSpeed;
|
// 2. Responsive Velocity Calculation
|
||||||
SetFloat(verticalVelocity, speed, "VerticalVelocity");
|
// Use a mix of agent velocity and position delta for better responsiveness
|
||||||
|
Vector3 worldVelocity = (transform.position - lastPosition) / Time.deltaTime;
|
||||||
|
lastPosition = transform.position;
|
||||||
|
|
||||||
bool sprinting = agent.velocity.magnitude > (enemyAI.moveSpeed * sprintThreshold);
|
if (worldVelocity.magnitude < 0.01f) worldVelocity = Vector3.zero;
|
||||||
SetBool(isSprinting, sprinting, "IsSprinting");
|
|
||||||
|
|
||||||
bool isDodging = !agent.enabled && !rb.isKinematic;
|
Vector3 localVelocity = transform.InverseTransformDirection(worldVelocity);
|
||||||
SetBool(flipAnimation, isDodging, "FlipAnimation (Dodge)");
|
|
||||||
|
float targetV = localVelocity.z / enemyAI.moveSpeed;
|
||||||
|
float targetH = localVelocity.x / enemyAI.moveSpeed;
|
||||||
|
|
||||||
|
// Smooth velocity values
|
||||||
|
currentV = Mathf.Lerp(currentV, targetV, 10f * Time.deltaTime);
|
||||||
|
currentH = Mathf.Lerp(currentH, targetH, 10f * Time.deltaTime);
|
||||||
|
|
||||||
|
SetFloat(verticalVelocity, currentV);
|
||||||
|
SetFloat(horizontalVelocity, currentH);
|
||||||
|
|
||||||
|
// 3. Sprinting
|
||||||
|
bool sprinting = worldVelocity.magnitude > (enemyAI.moveSpeed * sprintThreshold);
|
||||||
|
SetBool(isSprinting, sprinting);
|
||||||
|
|
||||||
|
// 4. Strafing
|
||||||
|
SetBool(isStrafing, enemyAI.playerHasArtifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateCombatParameters()
|
protected virtual void UpdateCombatParameters()
|
||||||
{
|
{
|
||||||
bool aiming = enemyAI.playerHasArtifact && agent.isStopped;
|
SetBool(isAiming, enemyAI.playerHasArtifact);
|
||||||
SetBool(isAiming, aiming, "IsAiming");
|
SetInt(moveSet_ID, enemyAI.playerHasArtifact ? 1 : 0);
|
||||||
|
|
||||||
int moveID = enemyAI.playerHasArtifact ? 1 : 0;
|
// Shooting burst
|
||||||
SetInt(moveSet_ID, moveID, "MoveSet_ID");
|
if (enemyAI.IsShootingBurst)
|
||||||
|
SetInt(attackID, 1);
|
||||||
|
else
|
||||||
|
SetInt(attackID, 0);
|
||||||
|
|
||||||
SetBool(canAim, enemyAI.playerHasArtifact, "CanAim");
|
// Dodge logic
|
||||||
}
|
if (enemyAI.IsDodging)
|
||||||
|
|
||||||
#region Optimized Setters with Debug
|
|
||||||
|
|
||||||
protected void SetBool(vAnimatorParameter param, bool value, string name)
|
|
||||||
{
|
|
||||||
if (param.isValid)
|
|
||||||
{
|
{
|
||||||
bool current = animator.GetBool(param);
|
// In Invector, dodges are often handled via triggers or specific IDs
|
||||||
if (current != value)
|
SetAnimatorTrigger(triggerReaction);
|
||||||
{
|
|
||||||
animator.SetBool(param, value);
|
|
||||||
if (debugMode) Debug.Log($"<color=cyan>[AnimDebug]</color> {gameObject.name}: <b>{name}</b> -> {value}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Death state
|
||||||
|
if (healthController) SetBool(isDead, healthController.isDead);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetFloat(vAnimatorParameter param, float value, string name)
|
protected virtual void OnReceiveDamage(vDamage damage)
|
||||||
|
{
|
||||||
|
if (animator == null || !animator.enabled) return;
|
||||||
|
|
||||||
|
// Sync damage parameters for hit reactions
|
||||||
|
if (hitDirection.isValid && damage.sender)
|
||||||
|
{
|
||||||
|
float angle = transform.HitAngle(damage.sender.position);
|
||||||
|
animator.SetInteger(hitDirection, (int)angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reactionID.isValid) animator.SetInteger(reactionID, damage.reaction_id);
|
||||||
|
|
||||||
|
SetAnimatorTrigger(triggerReaction);
|
||||||
|
SetAnimatorTrigger(resetState);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Helpers
|
||||||
|
protected void SetBool(vAnimatorParameter param, bool value)
|
||||||
|
{
|
||||||
|
if (param.isValid && animator.GetBool(param) != value)
|
||||||
|
animator.SetBool(param, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetFloat(vAnimatorParameter param, float value)
|
||||||
{
|
{
|
||||||
if (param.isValid)
|
if (param.isValid)
|
||||||
{
|
|
||||||
animator.SetFloat(param, value, dampTime, Time.deltaTime);
|
animator.SetFloat(param, value, dampTime, Time.deltaTime);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetInt(vAnimatorParameter param, int value, string name)
|
protected void SetInt(vAnimatorParameter param, int value)
|
||||||
{
|
{
|
||||||
if (param.isValid)
|
if (param.isValid && animator.GetInteger(param) != value)
|
||||||
{
|
animator.SetInteger(param, value);
|
||||||
int current = animator.GetInteger(param);
|
|
||||||
if (current != value)
|
|
||||||
{
|
|
||||||
animator.SetInteger(param, value);
|
|
||||||
if (debugMode) Debug.Log($"<color=orange>[AnimDebug]</color> {gameObject.name}: <b>{name}</b> -> {value}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
public void SetAnimatorTrigger(vAnimatorParameter trigger)
|
||||||
|
|
||||||
#region Helper Methods (Triggers)
|
|
||||||
|
|
||||||
public virtual void SetAnimatorTrigger(vAnimatorParameter trigger, string name = "Trigger")
|
|
||||||
{
|
{
|
||||||
if (trigger.isValid)
|
if (trigger.isValid) StartCoroutine(SetTriggerRoutine(trigger));
|
||||||
{
|
|
||||||
if (debugMode) Debug.Log($"<color=yellow>[AnimDebug]</color> {gameObject.name}: Kích hoạt <b>{name}</b>");
|
|
||||||
StartCoroutine(SetTriggerRoutine(trigger));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator SetTriggerRoutine(int targetHash)
|
private IEnumerator SetTriggerRoutine(int targetHash)
|
||||||
@@ -310,6 +202,5 @@ public class AnimatorAI : MonoBehaviour
|
|||||||
yield return new WaitForSeconds(0.1f);
|
yield return new WaitForSeconds(0.1f);
|
||||||
animator.ResetTrigger(targetHash);
|
animator.ResetTrigger(targetHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ public class EnemyAI : MonoBehaviour
|
|||||||
private int strafeDirectionSign = 1; // -1: Trái, 1: Phải, 0: Đứng im bắn
|
private int strafeDirectionSign = 1; // -1: Trái, 1: Phải, 0: Đứng im bắn
|
||||||
private bool isShootingBurst = false; // Khóa chống trùng lặp loạt bắn
|
private bool isShootingBurst = false; // Khóa chống trùng lặp loạt bắn
|
||||||
|
|
||||||
|
public bool IsDodging => isDodging;
|
||||||
|
public bool IsShootingBurst => isShootingBurst;
|
||||||
|
|
||||||
[Header("Conversation Settings")]
|
[Header("Conversation Settings")]
|
||||||
public string npcName = "Guard";
|
public string npcName = "Guard";
|
||||||
[TextArea] public string persona = "You are a bored security guard. You love coffee and hate night shifts.";
|
[TextArea] public string persona = "You are a bored security guard. You love coffee and hate night shifts.";
|
||||||
|
|||||||
Reference in New Issue
Block a user