using Unity.Netcode; using UnityEngine; namespace Northbound { /// /// 자동으로 적을 탐지하고 공격하는 시스템 /// public class AutoTargetSystem : NetworkBehaviour { [Header("Targeting")] [Tooltip("적을 감지하는 범위")] public float detectionRange = 15f; [Tooltip("공격 가능한 범위")] public float attackRange = 10f; [Tooltip("공격 간격 (초)")] public float attackInterval = 1f; [Tooltip("탐지할 레이어")] public LayerMask targetLayer = ~0; [Header("Combat")] [Tooltip("공격 데미지")] public int attackDamage = 10; [Header("Debug")] [Tooltip("디버그 정보 표시")] public bool showDebugInfo = true; private ITeamMember _teamMember; private float _lastAttackTime; private void Awake() { _teamMember = GetComponent(); if (_teamMember == null) { Debug.LogError($"[AutoTargetSystem] {gameObject.name}에 ITeamMember 컴포넌트가 없습니다!"); } } private void Update() { if (!IsServer) return; if (_teamMember == null) return; if (Time.time - _lastAttackTime >= attackInterval) { FindAndAttackEnemy(); } } private void FindAndAttackEnemy() { // 범위 내 모든 콜라이더 탐지 Collider[] colliders = Physics.OverlapSphere(transform.position, detectionRange, targetLayer); if (showDebugInfo && colliders.Length > 0) { Debug.Log($"[AutoTarget] {gameObject.name}이(가) {colliders.Length}개의 오브젝트를 감지했습니다."); } GameObject closestEnemy = null; float closestDistance = float.MaxValue; foreach (Collider col in colliders) { // 자기 자신 제외 if (col.transform.root == transform.root) continue; // 팀 확인 ITeamMember targetTeam = col.GetComponent(); if (targetTeam == null) { // 부모나 자식에서 찾기 targetTeam = col.GetComponentInParent(); if (targetTeam == null) { targetTeam = col.GetComponentInChildren(); } } if (targetTeam == null) { if (showDebugInfo) { Debug.Log($"[AutoTarget] {col.gameObject.name}에 ITeamMember가 없습니다."); } continue; } // 적대 관계 확인 bool canAttack = TeamManager.CanAttack(_teamMember, targetTeam); if (showDebugInfo) { Debug.Log($"[AutoTarget] {gameObject.name} ({TeamManager.GetTeamName(_teamMember.GetTeam())}) → {col.gameObject.name} ({TeamManager.GetTeamName(targetTeam.GetTeam())}): 공격가능={canAttack}"); } if (!canAttack) continue; // 가장 가까운 적 찾기 float distance = Vector3.Distance(transform.position, col.transform.position); if (distance < closestDistance && distance <= attackRange) { closestDistance = distance; closestEnemy = col.gameObject; } } // 공격 if (closestEnemy != null) { IDamageable damageable = closestEnemy.GetComponent(); if (damageable == null) { damageable = closestEnemy.GetComponentInParent(); if (damageable == null) { damageable = closestEnemy.GetComponentInChildren(); } } if (damageable != null) { damageable.TakeDamage(attackDamage, NetworkObjectId); _lastAttackTime = Time.time; var targetTeam = closestEnemy.GetComponent() ?? closestEnemy.GetComponentInParent() ?? closestEnemy.GetComponentInChildren(); Debug.Log($"[AutoTarget] {gameObject.name} ({TeamManager.GetTeamName(_teamMember.GetTeam())})이(가) {closestEnemy.name} ({TeamManager.GetTeamName(targetTeam?.GetTeam() ?? TeamType.Neutral)})을(를) 공격! (거리: {closestDistance:F2}m, 데미지: {attackDamage})"); } else { Debug.LogWarning($"[AutoTarget] {closestEnemy.name}에 IDamageable이 없습니다."); } } else if (showDebugInfo && colliders.Length > 0) { Debug.Log($"[AutoTarget] {gameObject.name}이(가) 공격 가능한 적을 찾지 못했습니다."); } } private void OnDrawGizmos() { // 탐지 범위 (노란색) Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, detectionRange); // 공격 범위 (빨간색) Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); } private void OnDrawGizmosSelected() { OnDrawGizmos(); #if UNITY_EDITOR if (_teamMember != null && Application.isPlaying) { UnityEditor.Handles.Label(transform.position + Vector3.up * 3f, $"Auto Target\nTeam: {TeamManager.GetTeamName(_teamMember.GetTeam())}\nDetection: {detectionRange}m\nAttack: {attackRange}m"); } #endif } } }