using System; 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; public bool autoUpdate; [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 Get() => detecteds; private void Update() { if (autoUpdate) { Execute().Forget(); } } public override UniTask Execute() { 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.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.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; } } #if UNITY_EDITOR #endif }