OldBlueWater/BlueWater/Assets/02.Scripts/Ai/FieldOfView.cs

158 lines
4.7 KiB
C#
Raw Normal View History

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);
}
2023-08-08 07:53:35 +00:00
#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<IAiStat>();
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<IAiStat>();
if (iAiStat.GetCurrentHp() <= 0) continue;
nearestDistance = distance;
nearestTargetTransform = colliderWithinRange[i].transform;
}
if (nearestTargetTransform)
{
targetCollider = nearestTargetTransform.GetComponent<Collider>();
iAiStat = nearestTargetTransform.GetComponent<IAiStat>();
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
}
}