iFactory.Cutting.Unity/Assets/BITKit/Unity/Scripts/Sensor/RangeSensor.cs

134 lines
4.9 KiB
C#
Raw Normal View History

2024-01-23 02:56:26 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Cysharp.Threading.Tasks;
2024-04-22 03:48:37 +08:00
using Unity.Mathematics;
2024-01-23 02:56:26 +08:00
using UnityEngine.Jobs;
using UnityEngine.Pool;
using UnityEngine.Profiling;
2024-04-16 04:15:06 +08:00
using Physics=UnityEngine.Physics;
2024-01-23 02:56:26 +08:00
namespace BITKit.Sensors
{
public class RangeSensor : Sensor
{
2024-04-22 03:48:37 +08:00
[Header(Constant.Header.Settings)]
[SerializeField] private float radius;
[SerializeField] private float detectedHeightWeight=0.5f;
[Header(Constant.Header.Optional)]
[SerializeField] private Optional<int> fov;
[SerializeField] private Optional<LayerMask> requireSight;
[SerializeField] private Optional<float> perceptionRadius;
2024-04-16 04:15:06 +08:00
2024-04-22 03:48:37 +08:00
public float DetectedHeightWeight
{
get=>detectedHeightWeight;
set=>detectedHeightWeight=value;
}
2024-01-23 02:56:26 +08:00
private readonly Collider[] colliders = new Collider[32];
2024-04-22 03:48:37 +08:00
private readonly RaycastHit[] hits = new RaycastHit[32];
private float _delta;
2024-01-23 02:56:26 +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;
}
2024-04-16 04:15:06 +08:00
private readonly DoubleBuffer<IEnumerable<Transform>> _detectedDoubleBuffer = new();
private IEnumerable<Transform> _detectedBuffer=Array.Empty<Transform>();
public override UniTask Execute(float delta)
2024-01-23 02:56:26 +08:00
{
2024-04-22 03:48:37 +08:00
_delta = delta;
2024-01-23 02:56:26 +08:00
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)
{
2024-04-22 03:48:37 +08:00
case var _ when Ignores.Contains(_collider.GetInstanceID()):
2024-01-23 02:56:26 +08:00
case var _ when ignoreColliders.Contains(_collider):
return false;
2024-04-22 03:48:37 +08:00
}
if (perceptionRadius.Allow)
{
var distance = Vector3.Distance(Transform.position, _collider.bounds.center);
if(distance<=perceptionRadius.Value) return !requireSight.Allow || CheckSight(ref _collider);
}
switch (_collider)
{
case var _ when fov.Allow && CheckFov(ref _collider) is false:
case var _ when requireSight.Allow && CheckSight(ref _collider) is false:
2024-01-23 02:56:26 +08:00
return false;
default:
return true;
}
}
public override float GetDistance() => radius;
2024-04-16 04:15:06 +08:00
2024-01-23 02:56:26 +08:00
private bool CheckFov(ref Collider _collider)
{
2024-04-16 04:15:06 +08:00
var _dir = _collider.bounds.center - 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);
2024-01-23 02:56:26 +08:00
}
2024-04-16 04:15:06 +08:00
2024-01-23 02:56:26 +08:00
private bool CheckSight(ref Collider _collider)
{
2024-04-22 03:48:37 +08:00
var bounds = _collider.bounds;
var position = bounds.center;
position.y += bounds.size.y * detectedHeightWeight /2;
var selfPosition = Transform.position;
2024-01-23 02:56:26 +08:00
var length = Physics.RaycastNonAlloc(
2024-04-22 03:48:37 +08:00
selfPosition,
position - selfPosition,
2024-01-23 02:56:26 +08:00
hits,
2024-04-22 03:48:37 +08:00
Vector3.Distance(selfPosition, position),
requireSight.Value
2024-01-23 02:56:26 +08:00
);
switch (length)
{
case 0:
2024-04-22 03:48:37 +08:00
Debug.DrawLine(selfPosition, position, Color.green,_delta);
2024-01-23 02:56:26 +08:00
return true;
case 1:
2024-04-16 04:15:06 +08:00
return hits[0].collider == _collider;
default:
var collider1 = _collider;
if (hits.Take(length).Any(Predicate))
2024-01-23 02:56:26 +08:00
{
2024-04-16 04:15:06 +08:00
return false;
2024-01-23 02:56:26 +08:00
}
break;
2024-04-16 04:15:06 +08:00
bool Predicate(RaycastHit x)
2024-01-23 02:56:26 +08:00
{
2024-04-16 04:15:06 +08:00
var result = ignoreColliders.Contains(x.collider) is false && x.collider != collider1;
if (result)
{
2024-04-22 03:48:37 +08:00
Debug.DrawLine(selfPosition, x.point, Color.yellow,_delta);
Debug.DrawLine(selfPosition, position, Color.red,_delta);
2024-04-16 04:15:06 +08:00
}
return result;
2024-01-23 02:56:26 +08:00
}
}
2024-04-16 04:15:06 +08:00
2024-01-23 02:56:26 +08:00
return true;
}
}
}