123 lines
4.1 KiB
C#
123 lines
4.1 KiB
C#
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using System.Linq;
|
||
|
using Cysharp.Threading.Tasks;
|
||
|
using UnityEngine.Jobs;
|
||
|
using UnityEngine.Pool;
|
||
|
namespace BITKit.Sensors
|
||
|
{
|
||
|
public class RangeSensor : Sensor
|
||
|
{
|
||
|
[Header(Constant.Header.Settings)]
|
||
|
public float radius;
|
||
|
public int fov;
|
||
|
public bool requireSight;
|
||
|
[Header(Constant.Header.Settings)]
|
||
|
public LayerMask blockLayer;
|
||
|
[Header(Constant.Header.InternalVariables)]
|
||
|
FrameUpdate frameUpdater;
|
||
|
Collider[] colliders = new Collider[32];
|
||
|
RaycastHit[] hits;
|
||
|
Collider currentCollider;
|
||
|
Location location;
|
||
|
int length;
|
||
|
Vector3 dir;
|
||
|
float maxDistance;
|
||
|
public override IEnumerable<Transform> Get() => detecteds;
|
||
|
public override UniTask Excute()
|
||
|
{
|
||
|
if (frameUpdater)
|
||
|
{
|
||
|
if (maxDistance is 0)
|
||
|
{
|
||
|
maxDistance = Mathf.Max(subSensors.Select(x => x.GetDistance()).Append(radius).ToArray());
|
||
|
}
|
||
|
location.position = transform.position;
|
||
|
location.rotation = transform.rotation;
|
||
|
var list = ListPool<Transform>.Get();
|
||
|
for (int i = 0; i < Physics.OverlapSphereNonAlloc(location, maxDistance, colliders, detectLayer); i++)
|
||
|
{
|
||
|
currentCollider = colliders[i];
|
||
|
if (IsValid(currentCollider))
|
||
|
list.Add(currentCollider.transform);
|
||
|
else
|
||
|
{
|
||
|
foreach (var sensor in subSensors)
|
||
|
{
|
||
|
if (sensor.IsValid(currentCollider))
|
||
|
{
|
||
|
list.Add(currentCollider.transform);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
detecteds = list.ToArray();
|
||
|
list.Clear();
|
||
|
ListPool<Transform>.Release(list);
|
||
|
}
|
||
|
return UniTask.CompletedTask;
|
||
|
}
|
||
|
public override bool IsValid(Collider collider)
|
||
|
{
|
||
|
if (ignoreColliders.Contains(collider)
|
||
|
|| CheckFov(ref collider) is false
|
||
|
|| CheckSight(ref collider) is false
|
||
|
|| CheckDistance(ref collider) is false
|
||
|
)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else return true;
|
||
|
}
|
||
|
public override float GetDistance() => radius;
|
||
|
bool CheckFov(ref Collider collider)
|
||
|
{
|
||
|
if (fov is not 0)
|
||
|
{
|
||
|
var _dir = collider.transform.position - transform.position;
|
||
|
if (_dir.sqrMagnitude > 0)
|
||
|
{
|
||
|
var dir = Quaternion.LookRotation(_dir);
|
||
|
if (Vector3.Dot(transform.forward, _dir) > 0 && fov > Quaternion.Angle(transform.rotation, dir))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else return false;
|
||
|
}
|
||
|
else return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
bool CheckSight(ref Collider collider)
|
||
|
{
|
||
|
if (requireSight)
|
||
|
{
|
||
|
length = Physics.RaycastNonAlloc(
|
||
|
location.position,
|
||
|
collider.transform.position - location,
|
||
|
hits,
|
||
|
Vector3.Distance(location, collider.transform.position),
|
||
|
blockLayer
|
||
|
);
|
||
|
if (length > 0)
|
||
|
{
|
||
|
if (hits[0].collider == collider)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
else return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
bool CheckDistance(ref Collider collider)
|
||
|
{
|
||
|
return Vector3.Distance(collider.transform.position, transform.position) <= radius;
|
||
|
}
|
||
|
}
|
||
|
}
|