1
This commit is contained in:
@@ -18,7 +18,7 @@ namespace BITKit.Sensors
|
||||
IAudioObject currentAudioObject;
|
||||
Collider currentCollider;
|
||||
Collider[] colliders = new Collider[32];
|
||||
public override IEnumerable<Transform> Get() => detecteds;
|
||||
public override IEnumerable<Transform> Get() => detected;
|
||||
public override UniTask Execute()
|
||||
{
|
||||
var cacheList = ListPool<Transform>.Get();
|
||||
@@ -30,15 +30,15 @@ namespace BITKit.Sensors
|
||||
cacheList.Add(currentCollider.transform);
|
||||
}
|
||||
}
|
||||
detecteds = cacheList.ToArray();
|
||||
detected = cacheList.ToArray();
|
||||
ListPool<Transform>.Release(cacheList);
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
public override bool IsValid(Collider collider)
|
||||
public override bool IsValid(Collider _collider)
|
||||
{
|
||||
if (ignoreColliders.Contains(collider) is false)
|
||||
if (Vector3.Distance(transform.position, collider.transform.position) <= radius)
|
||||
if (collider.TryGetComponent<IAudioObject>(out currentAudioObject))
|
||||
if (ignoreColliders.Contains(_collider) is false)
|
||||
if (Vector3.Distance(transform.position, _collider.transform.position) <= radius)
|
||||
if (_collider.TryGetComponent<IAudioObject>(out currentAudioObject))
|
||||
{
|
||||
return currentAudioObject.GetVolume() >= 1;
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -6,12 +7,35 @@ using BITKit;
|
||||
using Cysharp.Threading.Tasks;
|
||||
namespace BITKit.Sensors
|
||||
{
|
||||
/// <summary>
|
||||
/// 传感器的接口定义
|
||||
/// </summary>
|
||||
public interface ISensor
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否监测到任何目标
|
||||
/// </summary>
|
||||
bool Any=>Get().Any();
|
||||
/// <summary>
|
||||
/// 获取检测到的目标
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Transform> Get();
|
||||
bool IsValid(Collider collider);
|
||||
/// <summary>
|
||||
/// 目标是否有效
|
||||
/// </summary>
|
||||
/// <param name="_collider">目标的碰撞体</param>
|
||||
/// <returns></returns>
|
||||
bool IsValid(Collider _collider);
|
||||
/// <summary>
|
||||
/// 获取传感器的范围
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
float GetDistance();
|
||||
/// <summary>
|
||||
/// 传感器执行检测
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
UniTask Execute();
|
||||
}
|
||||
[System.Serializable]
|
||||
@@ -24,9 +48,9 @@ namespace BITKit.Sensors
|
||||
return _sensorImplementation.Get();
|
||||
}
|
||||
|
||||
public bool IsValid(Collider collider)
|
||||
public bool IsValid(Collider _collider)
|
||||
{
|
||||
return _sensorImplementation.IsValid(collider);
|
||||
return _sensorImplementation.IsValid(_collider);
|
||||
}
|
||||
|
||||
public float GetDistance()
|
||||
@@ -43,15 +67,14 @@ namespace BITKit.Sensors
|
||||
{
|
||||
[Header(Constant.Header.Settings)]
|
||||
public LayerMask detectLayer;
|
||||
public bool autoUpdate;
|
||||
[Header(Constant.Header.Gameobjects)]
|
||||
public Collider[] ignoreColliders;
|
||||
[Header(Constant.Header.Components)]
|
||||
public Sensor[] subSensors;
|
||||
[Header(Constant.Header.InternalVariables)]
|
||||
[System.NonSerialized]
|
||||
public Transform[] detecteds = new Transform[0];
|
||||
[NonSerialized]
|
||||
public Transform[] detected = Array.Empty<Transform>();
|
||||
public abstract IEnumerable<Transform> Get();
|
||||
public abstract bool IsValid(Collider collider);
|
||||
public abstract bool IsValid(Collider _collider);
|
||||
public abstract UniTask Execute();
|
||||
public abstract float GetDistance();
|
||||
}
|
||||
|
@@ -5,7 +5,8 @@
|
||||
"GUID:a209c53514018594f9f482516f2a6781",
|
||||
"GUID:508392158bd966c4d9c21e19661a441d",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4"
|
||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
||||
"GUID:be17a8778dbfe454890ed8279279e153"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
@@ -14,19 +14,14 @@ namespace BITKit.Sensors
|
||||
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<Transform> Get() => detecteds;
|
||||
private FrameUpdate frameUpdater;
|
||||
private readonly Collider[] colliders = new Collider[32];
|
||||
private RaycastHit[] hits;
|
||||
public override IEnumerable<Transform> Get() => detected;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
@@ -37,100 +32,64 @@ namespace BITKit.Sensors
|
||||
}
|
||||
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<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);
|
||||
}
|
||||
if (frameUpdater.Allow is false) return UniTask.CompletedTask;
|
||||
var location = new Location(transform);
|
||||
var length = Physics.OverlapSphereNonAlloc(location, radius, colliders, detectLayer);
|
||||
var list = new List<Transform>();
|
||||
list.AddRange(from x in colliders.Take(length) where IsValid(x) select x.transform);
|
||||
detected = list.ToArray();
|
||||
list.Clear();
|
||||
// detected = colliders
|
||||
// .Take(length)
|
||||
// .Select(x => x.transform)
|
||||
// .ToArray();
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
public override bool IsValid(Collider collider)
|
||||
|
||||
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
|
||||
)
|
||||
switch (_collider)
|
||||
{
|
||||
return false;
|
||||
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
|
||||
);
|
||||
if (length > 0)
|
||||
{
|
||||
if (hits[0].collider == _collider)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
namespace BITKit.Sensors
|
||||
@@ -8,22 +10,29 @@ namespace BITKit.Sensors
|
||||
{
|
||||
[Header(Constant.Header.Settings)]
|
||||
public float distance;
|
||||
public override IEnumerable<Transform> Get() => detecteds;
|
||||
public override IEnumerable<Transform> Get() => detected;
|
||||
private readonly RaycastHit[] raycasts = new RaycastHit[16];
|
||||
public override UniTask Execute()
|
||||
{
|
||||
if (Physics.Raycast(transform.position, transform.forward, out var rayhit, distance, detectLayer))
|
||||
{
|
||||
detecteds = new Transform[]{
|
||||
rayhit.transform
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
detecteds = new Transform[0];
|
||||
}
|
||||
var _transform = transform;
|
||||
var ray = new Ray(_transform.position,_transform.forward);
|
||||
var size = Physics.RaycastNonAlloc(ray, raycasts, distance, detectLayer);
|
||||
detected = raycasts
|
||||
.Take(size)
|
||||
.Select(x => x.collider)
|
||||
.Where(IsValid)
|
||||
.Select(x=>x.transform)
|
||||
.ToArray();
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
public override bool IsValid(Collider collider) => true;
|
||||
public override bool IsValid(Collider _collider) => ignoreColliders.Contains(_collider) is false;
|
||||
public override float GetDistance() => distance;
|
||||
private void Update()
|
||||
{
|
||||
if (autoUpdate)
|
||||
{
|
||||
Execute().Forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
Packages/Runtime~/Unity/Common/Scripts/Sensor/Smart.meta
Normal file
8
Packages/Runtime~/Unity/Common/Scripts/Sensor/Smart.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b4a8919533349e4e9bb0cd30005668c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace BITKit.Sensors
|
||||
{
|
||||
/// <summary>
|
||||
/// 智能目标传感器,根据条件,智能选择目标
|
||||
/// </summary>
|
||||
public class SmartTargetSensor :MonoBehaviour,ISensor,IAction
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动更新
|
||||
/// </summary>
|
||||
[Header(Constant.Header.Settings)]
|
||||
[SerializeField] private bool autoUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// 目标有效性验证
|
||||
/// </summary>
|
||||
[Header(Constant.Header.Providers)]
|
||||
[SerializeField,SerializeReference,SubclassSelector] private IValidityProvider validityProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 主传感器
|
||||
/// </summary>
|
||||
[Header(nameof(Sensor))]
|
||||
[SerializeField,SerializeReference,SubclassSelector] private ISensor sensor;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Header(Constant.Header.Debug)]
|
||||
[SerializeField] private Transform sensorTransform;
|
||||
#endif
|
||||
|
||||
public IEnumerable<Transform> Get() =>CurrentTarget is not null ? new[] { CurrentTarget }:Enumerable.Empty<Transform>();
|
||||
public bool IsValid(Collider _collider) =>validityProvider?.IsValid(_collider) ?? true;
|
||||
public float GetDistance() => sensor.GetDistance();
|
||||
public Transform CurrentTarget { get; private set; }
|
||||
private readonly List<Transform> detected = new();
|
||||
|
||||
public async UniTask Execute()
|
||||
{
|
||||
await sensor.Execute();
|
||||
var _detected = sensor.Get().ToList();
|
||||
if (_detected.Contains(CurrentTarget))
|
||||
{
|
||||
if (detected.Count is 1 && detected[0] == CurrentTarget)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
detected.Clear();
|
||||
detected.Add(CurrentTarget);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
CurrentTarget = _detected
|
||||
.Where(_transform => IsValid(_transform.GetComponent<Collider>()))
|
||||
.OrderBy(_transform => Vector3.Distance(transform.position, _transform.position))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if(autoUpdate)Execute().Forget();
|
||||
}
|
||||
|
||||
void IAction.Execute()
|
||||
{
|
||||
Execute().Forget();
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (CurrentTarget is null) return;
|
||||
Gizmos.DrawLine(sensorTransform.position,CurrentTarget.position);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(SmartTargetSensor))]
|
||||
public class SmartTargetSensorInspector:BITInspector<SmartTargetSensor>
|
||||
{
|
||||
private ObjectField _objectField;
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
FillDefaultInspector();
|
||||
|
||||
CreateSubTitle("Editor Debug Field");
|
||||
|
||||
_objectField = root.Create<ObjectField>();
|
||||
|
||||
_objectField.objectType = typeof(Transform);
|
||||
|
||||
_objectField.SetEnabled(false);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if (_objectField is not null)
|
||||
{
|
||||
_objectField.value = agent.CurrentTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33d6f52a9de8ea149ab70ac4e67a0c36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -6,7 +6,6 @@ using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UIElements;
|
||||
#if UNITY_EDITOR
|
||||
using System.CodeDom;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
#endif
|
||||
@@ -63,18 +62,24 @@ namespace BITKit.Sensors
|
||||
public bool IsValid(Collider _collider)
|
||||
{
|
||||
if(allowStatic is false && _collider.gameObject.isStatic) return false;
|
||||
if (ignores.Contains(_collider.gameObject)) return false;
|
||||
var attachedRigidbody = _collider.attachedRigidbody;
|
||||
var detectedObject = _collider switch
|
||||
{
|
||||
var x when attachedRigidbody is not null && useRigidbody => attachedRigidbody.gameObject,
|
||||
_ => _collider.gameObject,
|
||||
};
|
||||
if (ignores.Contains(detectedObject)) return false;
|
||||
return !detectedLayer.Allow || detectedLayer.Value.Includes(_collider.gameObject.layer);
|
||||
}
|
||||
|
||||
public float GetDistance()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public UniTask Execute()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
|
Reference in New Issue
Block a user