Update:EnemyAI, KamikazeAI
This commit is contained in:
@@ -1,16 +1,47 @@
|
|||||||
|
using Invector;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class AutoDestroy : MonoBehaviour
|
public class AutoDestroy : MonoBehaviour
|
||||||
{
|
{
|
||||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
public int damageAmount = 30;
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
Destroy(gameObject,2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update is called once per frame
|
// Update is called once per frame
|
||||||
void Update()
|
private void OnTriggerEnter(Collider other)
|
||||||
|
{
|
||||||
|
// Debug: Log tên và tag của bất cứ thứ gì đạn chạm vào
|
||||||
|
Debug.Log(
|
||||||
|
$"Laser collided with: {other.name} | Tag: {other.tag} | Layer: {LayerMask.LayerToName(other.gameObject.layer)}");
|
||||||
|
|
||||||
|
// Kiểm tra nếu trúng Player
|
||||||
|
if (other.CompareTag("Player") || other.GetComponentInParent<vIHealthController>() != null)
|
||||||
|
{
|
||||||
|
var healthController = other.GetComponentInParent<vIHealthController>();
|
||||||
|
|
||||||
|
if (healthController != null)
|
||||||
|
{
|
||||||
|
Debug.Log(
|
||||||
|
$"<color=red>HIT PLAYER!</color> Found health controller on {healthController.gameObject.name}. Applying {damageAmount} damage.");
|
||||||
|
var damage = new vDamage(damageAmount);
|
||||||
|
damage.sender = transform;
|
||||||
|
damage.hitPosition = transform.position;
|
||||||
|
healthController.TakeDamage(damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Luôn phá hủy đạn khi trúng Player
|
||||||
|
Impact();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Impact()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Phá hủy đạn ngay lập tức
|
||||||
|
Destroy(gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using Random = UnityEngine.Random;
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class DialogueResult { public string text; public float speedMod; public float suspicionMod; }
|
public class DialogueResult { public string text; public float speedMod; public float suspicionMod; }
|
||||||
|
|
||||||
// Quy trình ưu tiên: Né đòn --> Bắn hạ (Artifact) --> Đuổi theo (Vector) --> Điều tra --> Nói chuyện --> Đi tuần
|
// Quy trình ưu tiên: Né đòn --> Bắn hạ (Artifact / Sound Aggro) --> Đuổi theo (Vector) --> Điều tra --> Nói chuyện --> Đi tuần
|
||||||
[RequireComponent(typeof(NavMeshAgent))]
|
[RequireComponent(typeof(NavMeshAgent))]
|
||||||
[RequireComponent(typeof(Rigidbody))]
|
[RequireComponent(typeof(Rigidbody))]
|
||||||
public class EnemyAI : MonoBehaviour
|
public class EnemyAI : MonoBehaviour
|
||||||
@@ -26,20 +26,18 @@ public class EnemyAI : MonoBehaviour
|
|||||||
public float rotateSpeed = 10f;
|
public float rotateSpeed = 10f;
|
||||||
|
|
||||||
[Header("Patrol Settings")]
|
[Header("Patrol Settings")]
|
||||||
|
|
||||||
public float patrolWaitTime = 2f;
|
public float patrolWaitTime = 2f;
|
||||||
private float currentWaitTime = 0f;
|
private float currentWaitTime = 0f;
|
||||||
public float patrolSpeed = 2.5f;
|
public float patrolSpeed = 2.5f;
|
||||||
|
public float patrolRadius = 12f;
|
||||||
public float patrolRadius = 12f; // Bán kính của khu vực tuần tra ngẫu nhiên
|
|
||||||
|
|
||||||
|
|
||||||
private Vector3 startPosition;
|
private Vector3 startPosition;
|
||||||
|
|
||||||
[Header("Combat State")]
|
[Header("Combat State")]
|
||||||
public bool playerHasArtifact;
|
public bool playerHasArtifact;
|
||||||
|
public bool isAggroedBySound; // <-- MỚI: Trạng thái bị đánh động bởi âm thanh
|
||||||
public GameObject laserPrefab;
|
public GameObject laserPrefab;
|
||||||
public Transform firePoint;
|
public Transform firePoint;
|
||||||
public float minShootDelay = 1.5f; // Delay giữa các LOẠT BẮN
|
public float minShootDelay = 1.5f;
|
||||||
public float maxShootDelay = 3.5f;
|
public float maxShootDelay = 3.5f;
|
||||||
private float nextShootTime;
|
private float nextShootTime;
|
||||||
|
|
||||||
@@ -59,11 +57,9 @@ public class EnemyAI : MonoBehaviour
|
|||||||
public float approachWeight = 0.35f;
|
public float approachWeight = 0.35f;
|
||||||
public float minCombatDistance = 5.0f;
|
public float minCombatDistance = 5.0f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private float nextStrafeChangeTime;
|
private float nextStrafeChangeTime;
|
||||||
private int strafeDirectionSign = 1; // -1: Trái, 1: Phải, 0: Đứng im bắn
|
private int strafeDirectionSign = 1;
|
||||||
private bool isShootingBurst = false; // Khóa chống trùng lặp loạt bắn
|
private bool isShootingBurst = false;
|
||||||
|
|
||||||
[Header("Conversation Settings")]
|
[Header("Conversation Settings")]
|
||||||
public string npcName = "Guard";
|
public string npcName = "Guard";
|
||||||
@@ -71,7 +67,7 @@ public class EnemyAI : MonoBehaviour
|
|||||||
public float talkRange = 12f;
|
public float talkRange = 12f;
|
||||||
public float talkCooldown = 60f;
|
public float talkCooldown = 60f;
|
||||||
private float lastTalkTime;
|
private float lastTalkTime;
|
||||||
public bool isTalking; // Public để debug
|
public bool isTalking;
|
||||||
private EnemyAI talkingPartner;
|
private EnemyAI talkingPartner;
|
||||||
private Hallucinate.UI.ChatBubble chatBubble;
|
private Hallucinate.UI.ChatBubble chatBubble;
|
||||||
|
|
||||||
@@ -92,6 +88,7 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
rb.isKinematic = true;
|
rb.isKinematic = true;
|
||||||
rb.freezeRotation = true;
|
rb.freezeRotation = true;
|
||||||
|
startPosition = transform.position;
|
||||||
|
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
@@ -105,7 +102,10 @@ public class EnemyAI : MonoBehaviour
|
|||||||
void InitTree()
|
void InitTree()
|
||||||
{
|
{
|
||||||
var dodgeSequence = new Sequence(new List<Node> { new TaskNode(CheckDodgeConditions), new TaskNode(ActionDodge) });
|
var dodgeSequence = new Sequence(new List<Node> { new TaskNode(CheckDodgeConditions), new TaskNode(ActionDodge) });
|
||||||
var laserSequence = new Sequence(new List<Node> { new TaskNode(CheckHasArtifact), new TaskNode(ActionFocusAndShoot) });
|
|
||||||
|
// Đổi hàm CheckHasArtifact thành CheckCombatConditions để dùng chung cho cả âm thanh
|
||||||
|
var laserSequence = new Sequence(new List<Node> { new TaskNode(CheckCombatConditions), new TaskNode(ActionFocusAndShoot) });
|
||||||
|
|
||||||
var chaseSequence = new Sequence(new List<Node> { new TaskNode(CheckCanSeePlayer), new TaskNode(ActionChasePlayer) });
|
var chaseSequence = new Sequence(new List<Node> { new TaskNode(CheckCanSeePlayer), new TaskNode(ActionChasePlayer) });
|
||||||
var investigateSequence = new Sequence(new List<Node> { new TaskNode(CheckHasInvestigateTarget), new TaskNode(ActionInvestigate) });
|
var investigateSequence = new Sequence(new List<Node> { new TaskNode(CheckHasInvestigateTarget), new TaskNode(ActionInvestigate) });
|
||||||
var talkSequence = new Sequence(new List<Node> { new TaskNode(CheckCanTalkToNPC), new TaskNode(ActionTalk) });
|
var talkSequence = new Sequence(new List<Node> { new TaskNode(CheckCanTalkToNPC), new TaskNode(ActionTalk) });
|
||||||
@@ -128,9 +128,14 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
if (!agent.isOnNavMesh) return;
|
if (!agent.isOnNavMesh) return;
|
||||||
|
|
||||||
// Decay suspicion
|
|
||||||
suspicionLevel = Mathf.Max(0, suspicionLevel - Time.deltaTime * 0.5f);
|
suspicionLevel = Mathf.Max(0, suspicionLevel - Time.deltaTime * 0.5f);
|
||||||
|
|
||||||
|
// Bình tĩnh lại và tắt chế độ bắn dồn dập khi mức độ nghi ngờ về 0
|
||||||
|
if (suspicionLevel <= 0f)
|
||||||
|
{
|
||||||
|
isAggroedBySound = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isTalking && !isDodging && agent.isStopped)
|
if (!isTalking && !isDodging && agent.isStopped)
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
|
|
||||||
@@ -141,7 +146,7 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
private NodeState CheckDodgeConditions()
|
private NodeState CheckDodgeConditions()
|
||||||
{
|
{
|
||||||
if (playerHasArtifact) return NodeState.Failure; // Có cổ vật -> Không Dash né nữa
|
if (playerHasArtifact || isAggroedBySound) return NodeState.Failure;
|
||||||
|
|
||||||
if (isDodging) return NodeState.Success;
|
if (isDodging) return NodeState.Success;
|
||||||
if (fov != null && fov.canSeePlayer && Mouse.current.leftButton.isPressed)
|
if (fov != null && fov.canSeePlayer && Mouse.current.leftButton.isPressed)
|
||||||
@@ -149,10 +154,12 @@ public class EnemyAI : MonoBehaviour
|
|||||||
return NodeState.Failure;
|
return NodeState.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeState CheckHasArtifact()
|
// Node này thay thế cho CheckHasArtifact cũ
|
||||||
|
private NodeState CheckCombatConditions()
|
||||||
{
|
{
|
||||||
if (playerHasArtifact) StopConversation();
|
bool shouldCombat = playerHasArtifact || isAggroedBySound;
|
||||||
return playerHasArtifact ? NodeState.Success : NodeState.Failure;
|
if (shouldCombat) StopConversation();
|
||||||
|
return shouldCombat ? NodeState.Success : NodeState.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeState CheckCanSeePlayer()
|
private NodeState CheckCanSeePlayer()
|
||||||
@@ -176,7 +183,7 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
private NodeState CheckCanTalkToNPC()
|
private NodeState CheckCanTalkToNPC()
|
||||||
{
|
{
|
||||||
if (playerHasArtifact || (fov != null && fov.canSeePlayer)) return NodeState.Failure;
|
if (playerHasArtifact || isAggroedBySound || (fov != null && fov.canSeePlayer)) return NodeState.Failure;
|
||||||
if (Time.time < lastTalkTime + talkCooldown) return NodeState.Failure;
|
if (Time.time < lastTalkTime + talkCooldown) return NodeState.Failure;
|
||||||
if (isTalking) return NodeState.Success;
|
if (isTalking) return NodeState.Success;
|
||||||
|
|
||||||
@@ -216,6 +223,13 @@ public class EnemyAI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
suspicionLevel += volume * 15f;
|
suspicionLevel += volume * 15f;
|
||||||
if (fov != null) fov.lastKnownPlayerPosition = location;
|
if (fov != null) fov.lastKnownPlayerPosition = location;
|
||||||
|
|
||||||
|
// CẬP NHẬT: Nếu AI nghe thấy tiếng động làm mức nghi ngờ vượt mốc điều tra, chuyển sang trạng thái chiến đấu (bắn bồi)
|
||||||
|
if (suspicionLevel >= investigationThreshold)
|
||||||
|
{
|
||||||
|
isAggroedBySound = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (suspicionLevel >= alertNeighborsThreshold) AlertNeighbors();
|
if (suspicionLevel >= alertNeighborsThreshold) AlertNeighbors();
|
||||||
StopConversation();
|
StopConversation();
|
||||||
Debug.Log($"<color=orange>[AI {npcName}]</color> Heard noise! Suspicion: {suspicionLevel}");
|
Debug.Log($"<color=orange>[AI {npcName}]</color> Heard noise! Suspicion: {suspicionLevel}");
|
||||||
@@ -279,31 +293,25 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
private NodeState ActionPatrol()
|
private NodeState ActionPatrol()
|
||||||
{
|
{
|
||||||
Debug.Log("Wandering randomly...");
|
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
agent.speed = patrolSpeed;
|
agent.speed = patrolSpeed;
|
||||||
|
|
||||||
// Kiểm tra xem NPC đã đi đến điểm ngẫu nhiên hiện tại chưa
|
|
||||||
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
|
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
|
||||||
{
|
{
|
||||||
currentWaitTime += Time.deltaTime;
|
currentWaitTime += Time.deltaTime;
|
||||||
|
|
||||||
// Đứng đợi hết thời gian quy định rồi mới tìm đường mới
|
|
||||||
if (currentWaitTime >= patrolWaitTime)
|
if (currentWaitTime >= patrolWaitTime)
|
||||||
{
|
{
|
||||||
// 1. Lấy một điểm ngẫu nhiên trong không gian hình cầu dựa trên bán kính
|
|
||||||
Vector3 randomDirection = Random.insideUnitSphere * patrolRadius;
|
Vector3 randomDirection = Random.insideUnitSphere * patrolRadius;
|
||||||
randomDirection += startPosition; // Cộng với tâm ban đầu để giới hạn khu vực
|
randomDirection += startPosition;
|
||||||
|
|
||||||
NavMeshHit hit;
|
NavMeshHit hit;
|
||||||
// 2. Ép tọa độ ngẫu nhiên đó phải nằm TRÊN bề mặt xanh của NavMesh (tránh kẹt tường)
|
|
||||||
// Số 1 ở cuối là Area Mask (thường là Walkable)
|
|
||||||
if (NavMesh.SamplePosition(randomDirection, out hit, patrolRadius, 1))
|
if (NavMesh.SamplePosition(randomDirection, out hit, patrolRadius, 1))
|
||||||
{
|
{
|
||||||
agent.SetDestination(hit.position);
|
agent.SetDestination(hit.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWaitTime = 0f; // Reset thời gian chờ
|
currentWaitTime = 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,13 +347,30 @@ public class EnemyAI : MonoBehaviour
|
|||||||
|
|
||||||
private NodeState ActionFocusAndShoot()
|
private NodeState ActionFocusAndShoot()
|
||||||
{
|
{
|
||||||
if (player == null) return NodeState.Failure;
|
if (player == null) return NodeState.Failure;
|
||||||
|
|
||||||
if (agent.hasPath) agent.ResetPath();
|
if (agent.hasPath) agent.ResetPath();
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
|
|
||||||
// 1. XOAY THÂN THEO TRỤC NGANG HƯỚNG VỀ PLAYER
|
// CẢI TIẾN: Xác định mục tiêu linh hoạt để tránh Wallhack.
|
||||||
Vector3 bodyDir = player.position - transform.position;
|
Vector3 targetPos = player.position; // Mặc định khóa chặt người chơi
|
||||||
|
|
||||||
|
// Nếu không cầm Artifact và cũng chưa bị nhìn thấy, AI chỉ nhắm vào MỐC ÂM THANH
|
||||||
|
if (!playerHasArtifact && fov != null && !fov.canSeePlayer && fov.lastKnownPlayerPosition != Vector3.zero)
|
||||||
|
{
|
||||||
|
targetPos = fov.lastKnownPlayerPosition;
|
||||||
|
|
||||||
|
// Nếu AI tiến hành áp sát và xả đạn vào nơi phát ra tiếng mà không thấy ai, ngưng bắn
|
||||||
|
if (Vector3.Distance(transform.position, targetPos) < 2f)
|
||||||
|
{
|
||||||
|
isAggroedBySound = false;
|
||||||
|
suspicionLevel *= 0.5f;
|
||||||
|
return NodeState.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. XOAY THÂN THEO TRỤC NGANG HƯỚNG VỀ MỤC TIÊU (Người chơi hoặc Tiếng động)
|
||||||
|
Vector3 bodyDir = targetPos - transform.position;
|
||||||
bodyDir.y = 0f;
|
bodyDir.y = 0f;
|
||||||
Vector3 bodyDirNormal = bodyDir.normalized;
|
Vector3 bodyDirNormal = bodyDir.normalized;
|
||||||
if (bodyDir != Vector3.zero)
|
if (bodyDir != Vector3.zero)
|
||||||
@@ -365,32 +390,28 @@ public class EnemyAI : MonoBehaviour
|
|||||||
// 3. TÍNH TOÁN TRỘN VECTOR: CHỈ TIẾN LÊN KHI ĐANG ĐI NGANG TRÁI/PHẢI
|
// 3. TÍNH TOÁN TRỘN VECTOR: CHỈ TIẾN LÊN KHI ĐANG ĐI NGANG TRÁI/PHẢI
|
||||||
Vector3 finalMovementVector = Vector3.zero;
|
Vector3 finalMovementVector = Vector3.zero;
|
||||||
|
|
||||||
// Kiểm tra xem AI có đang di chuyển ngang không (strafeDirectionSign khác 0)
|
|
||||||
if (strafeDirectionSign != 0 && bodyDir != Vector3.zero)
|
if (strafeDirectionSign != 0 && bodyDir != Vector3.zero)
|
||||||
{
|
{
|
||||||
// Vector đi ngang trái/phải
|
|
||||||
finalMovementVector = new Vector3(-bodyDirNormal.z, 0, bodyDirNormal.x) * strafeDirectionSign;
|
finalMovementVector = new Vector3(-bodyDirNormal.z, 0, bodyDirNormal.x) * strafeDirectionSign;
|
||||||
|
|
||||||
// Tiến tới tịnh tiến dần dần nếu chưa đạt khoảng cách tối thiểu
|
float currentDistance = Vector3.Distance(transform.position, targetPos);
|
||||||
float currentDistance = Vector3.Distance(transform.position, player.position);
|
|
||||||
if (currentDistance > minCombatDistance)
|
if (currentDistance > minCombatDistance)
|
||||||
{
|
{
|
||||||
finalMovementVector += bodyDirNormal * approachWeight;
|
finalMovementVector += bodyDirNormal * approachWeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Áp dụng di chuyển thực tế bằng Agent.Move
|
|
||||||
if (finalMovementVector != Vector3.zero)
|
if (finalMovementVector != Vector3.zero)
|
||||||
{
|
{
|
||||||
finalMovementVector.Normalize(); // Chuẩn hóa vector
|
finalMovementVector.Normalize();
|
||||||
agent.speed = moveSpeed * 0.75f;
|
agent.speed = moveSpeed * 0.75f;
|
||||||
agent.Move(finalMovementVector * agent.speed * Time.deltaTime);
|
agent.Move(finalMovementVector * agent.speed * Time.deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. XOAY HỌNG SÚNG TRỤC DỌC NHẮM VÀO NGƯỜI PLAYER
|
// 4. XOAY HỌNG SÚNG TRỤC DỌC NHẮM VÀO MỤC TIÊU
|
||||||
if (firePoint != null)
|
if (firePoint != null)
|
||||||
{
|
{
|
||||||
Vector3 targetCenter = player.position + Vector3.up * 1f;
|
Vector3 targetCenter = targetPos + Vector3.up * 1f;
|
||||||
Vector3 aimDir = targetCenter - firePoint.position;
|
Vector3 aimDir = targetCenter - firePoint.position;
|
||||||
if (aimDir != Vector3.zero)
|
if (aimDir != Vector3.zero)
|
||||||
{
|
{
|
||||||
@@ -409,7 +430,6 @@ public class EnemyAI : MonoBehaviour
|
|||||||
return NodeState.Running;
|
return NodeState.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coroutine xử lý bắn loạt đạn kết hợp RANDOM ĐỘ LỆCH (Spread)
|
|
||||||
private IEnumerator ShootBurstRoutine(int bulletCount)
|
private IEnumerator ShootBurstRoutine(int bulletCount)
|
||||||
{
|
{
|
||||||
isShootingBurst = true;
|
isShootingBurst = true;
|
||||||
@@ -418,19 +438,15 @@ public class EnemyAI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (laserPrefab == null || firePoint == null) break;
|
if (laserPrefab == null || firePoint == null) break;
|
||||||
|
|
||||||
// Tính toán độ lệch ngẫu nhiên (Xoay quanh trục X và Y của họng súng để tạo độ "lệch tâm thông minh")
|
|
||||||
float randomX = Random.Range(-maxSpreadAngle, maxSpreadAngle);
|
float randomX = Random.Range(-maxSpreadAngle, maxSpreadAngle);
|
||||||
float randomY = Random.Range(-maxSpreadAngle, maxSpreadAngle);
|
float randomY = Random.Range(-maxSpreadAngle, maxSpreadAngle);
|
||||||
Quaternion spreadRotation = Quaternion.Euler(randomX, randomY, 0f);
|
Quaternion spreadRotation = Quaternion.Euler(randomX, randomY, 0f);
|
||||||
|
|
||||||
// Nhân góc xoay gốc của họng súng với góc lệch ngẫu nhiên
|
|
||||||
Quaternion finalBulletRotation = firePoint.rotation * spreadRotation;
|
Quaternion finalBulletRotation = firePoint.rotation * spreadRotation;
|
||||||
|
|
||||||
// Sinh đạn
|
|
||||||
Instantiate(laserPrefab, firePoint.position, finalBulletRotation);
|
Instantiate(laserPrefab, firePoint.position, finalBulletRotation);
|
||||||
Debug.Log($"<color=cyan>[AI Burst]</color> Viên thứ {i + 1}/{bulletCount} | Độ lệch X:{randomX:F1}, Y:{randomY:F1}");
|
Debug.Log($"<color=cyan>[AI Burst]</color> Viên thứ {i + 1}/{bulletCount} | Độ lệch X:{randomX:F1}, Y:{randomY:F1}");
|
||||||
|
|
||||||
// Nếu còn đạn trong loạt, đợi một khoảng ngắn (burstInterval) rồi mới bắn tiếp viên sau
|
|
||||||
if (i < bulletCount - 1)
|
if (i < bulletCount - 1)
|
||||||
{
|
{
|
||||||
yield return new WaitForSeconds(burstInterval);
|
yield return new WaitForSeconds(burstInterval);
|
||||||
@@ -440,7 +456,7 @@ public class EnemyAI : MonoBehaviour
|
|||||||
isShootingBurst = false;
|
isShootingBurst = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShootLaser() { } // Hàm cũ không dùng nữa, đã có Burst lo
|
private void ShootLaser() { }
|
||||||
|
|
||||||
private NodeState ActionDodge()
|
private NodeState ActionDodge()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,13 @@ public class LaserProjectile : MonoBehaviour
|
|||||||
Impact();
|
Impact();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// KIỂM TRA LAYER "GROUND"
|
||||||
|
if (other.gameObject.layer == LayerMask.NameToLayer("Ground"))
|
||||||
|
{
|
||||||
|
Debug.Log("<color=yellow>Laser hit GROUND layer.</color>");
|
||||||
|
Impact();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Phá hủy đạn nếu trúng tường, sàn nhà (mọi thứ không phải trigger khác)
|
// Phá hủy đạn nếu trúng tường, sàn nhà (mọi thứ không phải trigger khác)
|
||||||
if (!other.isTrigger)
|
if (!other.isTrigger)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user