using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; using Cysharp.Threading.Tasks; using UnityEngine.Jobs; using UnityEngine.Pool; using UnityEngine.Profiling; 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)] private FrameUpdate frameUpdater; private readonly Collider[] colliders = new Collider[32]; private RaycastHit[] hits; private bool isExecuting; public override IEnumerable Get() { if (!_detectedDoubleBuffer.TryGetRelease(out var newRelease)) return _detectedBuffer; Profiler.BeginSample("Release Detected Buffer"); _detectedBuffer = newRelease; Profiler.EndSample(); return _detectedBuffer; } private readonly DoubleBuffer> _detectedDoubleBuffer=new(); private IEnumerable _detectedBuffer; public override UniTask Execute() { var length = Physics.OverlapSphereNonAlloc(Transform.position, radius, colliders, detectLayer); Profiler.BeginSample("Filter Detected Colliders"); var _newDetected = from x in colliders.Take(length) where IsValid(x) select x.transform; Profiler.EndSample(); _detectedDoubleBuffer.Release(_newDetected); return UniTask.CompletedTask; } public override bool IsValid(Collider _collider) { switch (_collider) { case var _ when ignoreColliders.Contains(_collider): return false; case var _ when fov > 0 && CheckFov(ref _collider) is false: case var _ when requireSight && CheckSight(ref _collider) is false: return false; default: return true; } } public override float GetDistance() => radius; private bool CheckFov(ref Collider _collider) { var _dir = _collider.transform.position - transform.position; if (_dir.sqrMagnitude <= 0) return false; var dir = Quaternion.LookRotation(_dir); return Vector3.Dot(transform.forward, _dir) > 0 && fov > Quaternion.Angle(transform.rotation, dir); } private bool CheckSight(ref Collider _collider) { if (!requireSight) return false; var transform1 = _collider.transform; var position = transform1.position; var location = new Location(Transform); var length = Physics.RaycastNonAlloc( location.position, position - location, hits, Vector3.Distance(location, position), blockLayer ); switch (length) { case 0: return true; case 1: if (hits[0].collider == _collider) { return true; } break; default: if (hits.Take(length).Any(x => ignoreColliders.Contains(x.collider) is false)) { return false; } break; } return true; } } }