BITFALL/Assets/BITKit/Unity/Scripts/Sensor/RangeSensor.cs

112 lines
3.9 KiB
C#
Raw Normal View History

2023-08-12 01:43:24 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Cysharp.Threading.Tasks;
using UnityEngine.Jobs;
using UnityEngine.Pool;
2023-11-15 23:54:54 +08:00
using UnityEngine.Profiling;
2023-08-12 01:43:24 +08:00
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;
2023-11-15 23:54:54 +08:00
public override IEnumerable<Transform> Get()
{
if (!_detectedDoubleBuffer.TryGetRelease(out var newRelease)) return _detectedBuffer;
Profiler.BeginSample("Release Detected Buffer");
_detectedBuffer = newRelease;
Profiler.EndSample();
return _detectedBuffer;
}
private readonly DoubleBuffer<IEnumerable<Transform>> _detectedDoubleBuffer=new();
private IEnumerable<Transform> _detectedBuffer;
2023-08-12 01:43:24 +08:00
private void Update()
{
2023-11-15 23:54:54 +08:00
if (autoUpdate && SensorGlobalSettings.Enabled)
2023-08-12 01:43:24 +08:00
{
Execute().Forget();
}
}
public override UniTask Execute()
{
if (frameUpdater.Allow is false) return UniTask.CompletedTask;
var location = new Location(transform);
var length = Physics.OverlapSphereNonAlloc(location, radius, colliders, detectLayer);
2023-11-15 23:54:54 +08:00
Profiler.BeginSample("Filter Detected Colliders");
var _newDetected = from x in colliders.Take(length) where IsValid(x) select x.transform;
Profiler.EndSample();
//detected = _newDetected.ToArray();
_detectedDoubleBuffer.Release(_newDetected);
2023-08-12 01:43:24 +08:00
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
);
2023-11-15 23:54:54 +08:00
switch (length)
2023-08-12 01:43:24 +08:00
{
2023-11-15 23:54:54 +08:00
case 0:
2023-08-12 01:43:24 +08:00
return true;
2023-11-15 23:54:54 +08:00
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;
2023-08-12 01:43:24 +08:00
}
2023-11-15 23:54:54 +08:00
return true;
2023-08-12 01:43:24 +08:00
}
}
}