using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 using System.Collections.Generic; // 리스트를 사용할거에요 -> 제네릭을 public class MeleeMonster : MonsterClass // 클래스를 선언할거에요 -> 근접 몬스터를 { [Header("=== 공격 설정 ===")] // 인스펙터 제목을 달거에요 -> 공격 설정을 [SerializeField] private float attackRange = 2f; // 변수를 선언할거에요 -> 사거리를 [SerializeField] private float attackDelay = 1.5f; // 변수를 선언할거에요 -> 딜레이를 [Header("=== 드랍 ===")] // 인스펙터 제목을 달거에요 -> 드랍 설정을 [SerializeField] private List dropItemPrefabs; // 변수를 선언할거에요 -> 아이템 목록을 [Range(0, 100)][SerializeField] private float dropChance = 30f; // 변수를 선언할거에요 -> 확률을 [Header("애니메이션")] // 인스펙터 제목을 달거에요 -> 애니메이션을 [SerializeField] private string[] attackAnimations = { "Monster_Attack_1" }; // 변수를 선언할거에요 -> 공격 애니들을 [SerializeField] private string Monster_Walk = "Monster_Walk"; // 변수를 선언할거에요 -> 걷기 애니를 private float lastAttackTime; // 변수를 선언할거에요 -> 마지막 공격 시간을 private int attackIndex; // 변수를 선언할거에요 -> 공격 인덱스를 protected override void Init() // 함수를 실행할거에요 -> 초기화를 { if (agent != null) agent.stoppingDistance = attackRange - 0.4f; // 설정할거에요 -> 정지 거리를 if (animator != null) animator.applyRootMotion = false; // 끌거에요 -> 루트 모션을 } protected override void OnResetStats() => myWeapon?.SetDamage(attackDamage); // 함수를 실행할거에요 -> 무기 데미지 설정을 protected override void ExecuteAILogic() // 함수를 실행할거에요 -> AI 로직을 { if (isHit || isAttacking || isResting) return; // 중단할거에요 -> 행동 불가면 float dist = Vector3.Distance(transform.position, playerTransform.position); // 계산할거에요 -> 거리를 if (dist <= attackRange) TryAttack(); // 분기할거에요 -> 가까우면 공격을 else MoveToPlayer(); // 분기할거에요 -> 멀면 이동을 } private void MoveToPlayer() // 함수를 선언할거에요 -> 이동 로직을 { if (agent.isOnNavMesh) { agent.isStopped = false; agent.SetDestination(playerTransform.position); } // 이동할거에요 -> 플레이어에게 if (agent.velocity.magnitude > 0.1f) animator.Play(Monster_Walk); // 재생할거에요 -> 걷기 애니를 else animator.Play(Monster_Idle); // 재생할거에요 -> 대기 애니를 } private void TryAttack() // 함수를 선언할거에요 -> 공격 시도를 { if (Time.time < lastAttackTime + attackDelay) return; // 중단할거에요 -> 쿨타임이면 lastAttackTime = Time.time; // 갱신할거에요 -> 공격 시간을 isAttacking = true; // 설정할거에요 -> 공격 중으로 if (agent.isOnNavMesh) { agent.isStopped = true; agent.velocity = Vector3.zero; } // 멈출거에요 -> 이동을 string animName = attackAnimations[attackIndex]; // 가져올거에요 -> 애니 이름을 attackIndex = (attackIndex + 1) % attackAnimations.Length; // 갱신할거에요 -> 인덱스를 animator.Play(animName, 0, 0f); // 재생할거에요 -> 공격 애니를 } protected override void OnDie() // 함수를 실행할거에요 -> 사망 시 { base.OnDie(); // 실행할거에요 -> 부모 사망 로직을 if (dropItemPrefabs != null && dropItemPrefabs.Count > 0) // 조건이 맞으면 실행할거에요 -> 아이템이 있으면 { if (Random.Range(0f, 100f) <= dropChance) // 조건이 맞으면 실행할거에요 -> 확률 당첨되면 { int idx = Random.Range(0, dropItemPrefabs.Count); // 뽑을거에요 -> 랜덤 인덱스를 if (dropItemPrefabs[idx] != null) Instantiate(dropItemPrefabs[idx], transform.position + Vector3.up * 0.5f, Quaternion.identity); // 생성할거에요 -> 아이템을 } } } }