using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를 using System.Collections.Generic; // 리스트를 사용할거에요 -> 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("애니메이션")] // 인스펙터 제목을 달거에요 -> 애니메이션을 [SerializeField] private string chargeAnim = "Monster_Charge"; // 변수를 선언할거에요 -> 돌진 애니를 [SerializeField] private string prepareAnim = "Monster_ChargePrepare"; // 변수를 선언할거에요 -> 준비 애니를 [SerializeField] private string walkAnim = "Monster_Walk"; // 변수를 선언할거에요 -> 걷기 애니를 private float lastChargeTime; // 변수를 선언할거에요 -> 마지막 돌진 시간을 private bool isCharging; // 변수를 선언할거에요 -> 돌진 중 여부를 private Rigidbody _rb; // 변수를 선언할거에요 -> 리지드바디를 protected override void Awake() // 함수를 실행할거에요 -> 초기화 Awake를 { base.Awake(); // 부모 함수를 실행할거에요 _rb = GetComponent(); // 가져올거에요 -> 리지드바디를 if (_rb == null) _rb = gameObject.AddComponent(); // 추가할거에요 -> 없으면 새로 _rb.isKinematic = true; // 끌거에요 -> 물리 연산을 } protected override void Init() { if (agent != null) agent.stoppingDistance = 1f; } // 초기화할거에요 -> 정지 거리를 protected override void ExecuteAILogic() // 함수를 실행할거에요 -> AI 로직을 { if (isHit || isCharging || isAttacking) return; // 중단할거에요 -> 행동 불가면 float dist = Vector3.Distance(transform.position, playerTransform.position); // 계산할거에요 -> 거리를 if (dist <= chargeRange && Time.time >= lastChargeTime + chargeDelay) StartCoroutine(ChargeRoutine()); // 실행할거에요 -> 돌진을 else ChasePlayer(); // 실행할거에요 -> 추격을 } private void ChasePlayer() // 함수를 선언할거에요 -> 추격 로직을 { if (agent.isOnNavMesh) { agent.isStopped = false; agent.SetDestination(playerTransform.position); } // 이동할거에요 -> 플레이어에게 animator.Play(walkAnim); // 재생할거에요 -> 걷기 애니를 } private IEnumerator ChargeRoutine() // 코루틴 함수를 정의할거에요 -> 돌진 과정을 { isAttacking = true; agent.isStopped = true; // 설정할거에요 -> 공격 상태와 정지를 animator.Play(prepareAnim); // 재생할거에요 -> 준비 애니를 Vector3 dir = (playerTransform.position - transform.position).normalized; dir.y = 0; // 계산할거에요 -> 방향을 transform.rotation = Quaternion.LookRotation(dir); // 회전할거에요 -> 방향대로 yield return new WaitForSeconds(prepareTime); // 기다릴거에요 -> 준비 시간만큼 isCharging = true; lastChargeTime = Time.time; // 설정할거에요 -> 돌진 상태와 시간을 agent.enabled = false; _rb.isKinematic = false; // 전환할거에요 -> 물리 이동으로 animator.Play(chargeAnim); // 재생할거에요 -> 돌진 애니를 float elapsed = 0f; // 초기화할거에요 -> 경과 시간을 while (elapsed < chargeDuration) // 반복할거에요 -> 지속 시간 동안 { _rb.velocity = transform.forward * chargeSpeed; // 적용할거에요 -> 속도를 elapsed += Time.deltaTime; // 더할거에요 -> 시간을 yield return null; // 대기할거에요 -> 다음 프레임까지 } _rb.velocity = Vector3.zero; _rb.isKinematic = true; agent.enabled = true; // 복구할거에요 -> 상태를 isCharging = false; OnAttackEnd(); // 종료할거에요 -> 돌진과 공격을 } private void OnCollisionEnter(Collision col) // 함수를 실행할거에요 -> 충돌 시 { if (isCharging && col.gameObject.CompareTag("Player")) // 조건이 맞으면 실행할거에요 -> 돌진 중 플레이어 충돌이면 { var t = col.gameObject.GetComponent(); // 가져올거에요 -> 인터페이스를 if (t != null) t.TakeDamage(attackDamage); // 입힐거에요 -> 데미지를 } } }