using UnityEngine; using UnityEngine.AI; using System.Collections; using System.Collections.Generic; // ✅ 리스트 사용 필수 /// /// 돌진 공격 몬스터 /// public class ChargeMonster : MonsterClass { [Header("=== 돌진 공격 설정 ===")] [SerializeField] private float chargeSpeed = 15f; [SerializeField] private float chargeRange = 10f; [SerializeField] private float chargeDuration = 2f; [SerializeField] private float chargeDelay = 3f; [SerializeField] private float prepareTime = 0.5f; // 🎁 [추가] 드랍 아이템 리스트 [Header("=== 드랍 아이템 설정 ===")] [Tooltip("드랍 가능한 아이템 리스트 (랜덤 1개)")] [SerializeField] private List dropItemPrefabs; [Tooltip("아이템이 나올 확률 (0 ~ 100%)")] [Range(0, 100)][SerializeField] private float dropChance = 30f; private float lastChargeTime; private bool isCharging = false; private bool isPreparing = false; private Vector3 chargeDirection; [Header("공격 / 이동 애니메이션")] [SerializeField] private string chargeAnimation = "Monster_Charge"; [SerializeField] private string prepareAnimation = "Monster_ChargePrepare"; [SerializeField] private string Monster_Walk = "Monster_Walk"; [Header("AI 상세 설정")] [SerializeField] private float patrolRadius = 5f; [SerializeField] private float patrolInterval = 2f; private float nextPatrolTime; private bool isPlayerInZone; private Rigidbody _rigidbody; protected override void Awake() { base.Awake(); _rigidbody = GetComponent(); if (_rigidbody == null) _rigidbody = gameObject.AddComponent(); _rigidbody.isKinematic = true; } protected override void Init() { if (agent != null) agent.stoppingDistance = 1f; if (animator != null) animator.applyRootMotion = false; } protected override void ExecuteAILogic() { if (isHit || isCharging || isPreparing) return; float distance = Vector3.Distance(transform.position, playerTransform.position); if (isPlayerInZone || distance <= chargeRange * 1.5f) { HandleChargeCombat(distance); } else { Patrol(); } UpdateMovementAnimation(); } void HandleChargeCombat(float distance) { if (distance <= chargeRange && Time.time >= lastChargeTime + chargeDelay) { StartCoroutine(PrepareCharge()); } else if (!isCharging && !isPreparing) { if (agent.isOnNavMesh) { if (agent.isStopped) agent.isStopped = false; agent.SetDestination(playerTransform.position); } } } IEnumerator PrepareCharge() { isPreparing = true; if (agent.isOnNavMesh) { agent.isStopped = true; agent.ResetPath(); agent.velocity = Vector3.zero; } chargeDirection = (playerTransform.position - transform.position).normalized; chargeDirection.y = 0; if (chargeDirection != Vector3.zero) transform.rotation = Quaternion.LookRotation(chargeDirection); if (!string.IsNullOrEmpty(prepareAnimation)) animator.Play(prepareAnimation, 0, 0f); Debug.Log("[ChargeMonster] 돌진 준비..."); yield return new WaitForSeconds(prepareTime); StartCoroutine(Charge()); } IEnumerator Charge() { isPreparing = false; isCharging = true; lastChargeTime = Time.time; if (agent != null) agent.enabled = false; if (_rigidbody != null) _rigidbody.isKinematic = false; animator.Play(chargeAnimation, 0, 0f); Debug.Log("[ChargeMonster] 돌진 시작!"); float chargeStartTime = Time.time; while (Time.time < chargeStartTime + chargeDuration) { if (_rigidbody != null) _rigidbody.velocity = chargeDirection * chargeSpeed; else transform.position += chargeDirection * chargeSpeed * Time.deltaTime; yield return null; } if (_rigidbody != null) { _rigidbody.velocity = Vector3.zero; _rigidbody.isKinematic = true; } if (agent != null) { agent.enabled = true; agent.ResetPath(); agent.velocity = Vector3.zero; } isCharging = false; Debug.Log("[ChargeMonster] 돌진 종료, 쿨타임 시작"); } void UpdateMovementAnimation() { if (isCharging || isPreparing || isHit || isResting) return; if (agent.enabled && agent.velocity.magnitude > 0.1f) animator.Play(Monster_Walk); else animator.Play(Monster_Idle); } void Patrol() { if (Time.time < nextPatrolTime) return; Vector3 randomPoint = transform.position + new Vector3( Random.Range(-patrolRadius, patrolRadius), 0, Random.Range(-patrolRadius, patrolRadius) ); if (NavMesh.SamplePosition(randomPoint, out NavMeshHit hit, 3f, NavMesh.AllAreas)) if (agent.isOnNavMesh) agent.SetDestination(hit.position); nextPatrolTime = Time.time + patrolInterval; } private void OnCollisionEnter(Collision collision) { if (!isCharging) return; if (collision.gameObject.CompareTag("Player")) { if (collision.gameObject.TryGetComponent(out var playerHealth)) { if (!playerHealth.isInvincible) playerHealth.TakeDamage(attackDamage); } } } // ☠️ [추가] 죽을 때 아이템 드랍 protected override void OnDie() { if (_rigidbody != null) _rigidbody.velocity = Vector3.zero; if (dropItemPrefabs != null && dropItemPrefabs.Count > 0) { float randomValue = Random.Range(0f, 100f); if (randomValue <= dropChance) { int randomIndex = Random.Range(0, dropItemPrefabs.Count); if (dropItemPrefabs[randomIndex] != null) { Instantiate(dropItemPrefabs[randomIndex], transform.position + Vector3.up * 0.5f, Quaternion.identity); } } } } private void OnTriggerEnter(Collider other) { if (other.CompareTag("Player")) isPlayerInZone = true; } private void OnTriggerExit(Collider other) { if (other.CompareTag("Player")) isPlayerInZone = false; } }