using System; using UnityEngine; // ReSharper disable once CheckNamespace namespace BlueWaterProject { [Serializable] public class TargetInfo { public Transform transform; public Collider collider; public IAiStat iAiStat; public TargetInfo() { transform = null; collider = null; iAiStat = null; } public TargetInfo(Transform transform, Collider collider, IAiStat iAiStat) { this.transform = transform; this.collider = collider; this.iAiStat = iAiStat; } public void SetTargetInfo(Transform targetTransform, Collider collider, IAiStat targetIAiStat) { transform = targetTransform; this.collider = collider; iAiStat = targetIAiStat; } public void DefaultSetting() { transform = null; collider = null; iAiStat = null; } } public class FieldOfView : MonoBehaviour { #region Property and variable [Header("타겟 및 시야 설정")] [SerializeField] private bool drawGizmo = true; [SerializeField] private LayerMask targetLayer; [Tooltip("시야 각도\n상대를 감지하는 0~360도 사이의 시야각")] [Range(0f, 360f)] [SerializeField] private float viewAngle = 360f; [Tooltip("시야 길이\n상대를 감지하는 최대 길이, 부채꼴 혹은 원의 반지름 길이")] [Range(0f, 50f)] [SerializeField] private float viewRadius; [Header("시야 내 타겟 정보")] [SerializeField] private Collider[] colliderWithinRange = new Collider[TARGET_MAX_SIZE]; [SerializeField] private TargetInfo targetInfo = new(); private Collider targetCollider; private IAiStat iAiStat; private const int TARGET_MAX_SIZE = 20; #endregion #region Unity built-in Function #if UNITY_EDITOR public void OnDrawGizmosSelected() { if (!drawGizmo) return; var myPos = transform.position; Gizmos.color = Color.green; Gizmos.DrawWireSphere(myPos, viewRadius); if (targetInfo.transform == null) return; Debug.DrawLine(myPos, targetInfo.transform.position, Color.red); } #endif private void LateUpdate() { Array.Clear(colliderWithinRange, 0, TARGET_MAX_SIZE); var myPos = transform.position; var maxColliderCount = Physics.OverlapSphereNonAlloc(myPos, viewRadius, colliderWithinRange, targetLayer, QueryTriggerInteraction.Collide); if (maxColliderCount <= 0) { targetInfo.DefaultSetting(); return; } iAiStat = colliderWithinRange[0].GetComponent(); float nearestDistance; Transform nearestTargetTransform; if (iAiStat.GetCurrentHp() <= 0) { nearestDistance = float.PositiveInfinity; nearestTargetTransform = null; } else { nearestDistance = Vector3.Distance(colliderWithinRange[0].transform.position, myPos); nearestTargetTransform = colliderWithinRange[0].transform; } for (var i = 1; i < maxColliderCount; i++) { var distance = Vector3.Distance(colliderWithinRange[i].transform.position, myPos); if (nearestDistance < distance) continue; iAiStat = colliderWithinRange[i].GetComponent(); if (iAiStat.GetCurrentHp() <= 0) continue; nearestDistance = distance; nearestTargetTransform = colliderWithinRange[i].transform; } if (nearestTargetTransform) { targetCollider = nearestTargetTransform.GetComponent(); iAiStat = nearestTargetTransform.GetComponent(); targetInfo.SetTargetInfo(nearestTargetTransform, targetCollider, iAiStat); var targetPos = targetInfo.transform.position; targetPos.y = transform.position.y; transform.LookAt(targetPos); } else { targetInfo.DefaultSetting(); } } #endregion #region Custom Function public int GetTargetLayer() => targetLayer; public TargetInfo GetTargetInfo() => targetInfo; #endregion } }