1
This commit is contained in:
@@ -5,7 +5,6 @@ using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
using System.Linq;
|
||||
using UnityEditor.Search;
|
||||
|
||||
namespace BITKit.Sensors
|
||||
{
|
||||
@@ -13,37 +12,83 @@ namespace BITKit.Sensors
|
||||
{
|
||||
float GetVolume();
|
||||
}
|
||||
public class AudioSensor : MonoBehaviour,ISensor
|
||||
|
||||
public class AudioSensor : MonoBehaviour, ISensor
|
||||
{
|
||||
[Header(Constant.Header.Settings)]
|
||||
[SerializeField] private bool autoUpdate;
|
||||
[SerializeField]private float radius;
|
||||
|
||||
[Header(Constant.Header.Settings)] [SerializeField]
|
||||
private bool autoUpdate;
|
||||
|
||||
[SerializeField] private float radius;
|
||||
private readonly CacheList<Transform> cache = new();
|
||||
private readonly CacheList<AudioSensorService.AudioSensorData> data = new();
|
||||
public AudioSensorService.AudioSensorData[] Noises => data.ValueArray;
|
||||
private readonly HashSet<int> _addedSet = new();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Id = GetInstanceID();
|
||||
SensorQueue.Register(Id,this);
|
||||
SensorQueue.Register(Id, this);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SensorQueue.UnRegister(Id);
|
||||
}
|
||||
public UniTask Execute(float delta)
|
||||
|
||||
public async UniTask Execute(float delta)
|
||||
{
|
||||
var position = transform.position;
|
||||
cache.Clear();
|
||||
foreach (var x in AudioSensorService.QuadtreeRoot.Find(new Bounds(position, Vector3.one * radius)))
|
||||
|
||||
AudioSensorService.LockHash.Add(Id);
|
||||
|
||||
try
|
||||
{
|
||||
var distance = Vector3.Distance(position, x.Position);
|
||||
if(distance>radius) continue;
|
||||
cache.Add(x.Transform);
|
||||
var position = transform.position;
|
||||
cache.Clear();
|
||||
data.Clear();
|
||||
_addedSet.Clear();
|
||||
await UniTask.SwitchToTaskPool();
|
||||
|
||||
AudioSensorService.AudioSensorData[] value;
|
||||
|
||||
value = AudioSensorService.QuadtreeRoot.Find(new Bounds(position, Vector3.one * radius)).ToArray();
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
var x = value[index];
|
||||
var distance = Vector3.Distance(position, x.Position);
|
||||
if (distance > radius) continue;
|
||||
if (Ignores.Contains(x.Id)) continue;
|
||||
_addedSet.Add(index);
|
||||
// if (x.Transform)
|
||||
// cache.Add(x.Transform);
|
||||
// data.Add(x);
|
||||
}
|
||||
|
||||
await UniTask.SwitchToMainThread();
|
||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
||||
foreach (var x in _addedSet)
|
||||
{
|
||||
if (value[x].Transform)
|
||||
cache.Add(value[x].Transform);
|
||||
data.Add(value[x]);
|
||||
}
|
||||
|
||||
}
|
||||
return UniTask.CompletedTask;
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
|
||||
AudioSensorService.LockHash.Remove(Id);
|
||||
//return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public HashSet<int> Ignores { get; } = new();
|
||||
public int Id { get; set; }
|
||||
public IEnumerable<Transform> Get() => cache.ValueArray;
|
||||
public bool IsValid(Collider _collider) => false;
|
||||
public float GetDistance() => radius;
|
||||
public bool AutoUpdate=>autoUpdate;
|
||||
public bool AutoUpdate => autoUpdate;
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using kcp2k;
|
||||
@@ -10,8 +11,10 @@ using UnityEngine.Pool;
|
||||
|
||||
namespace BITKit.Sensors
|
||||
{
|
||||
public struct ClassicNoise{}
|
||||
public class AudioSensorService : MonoBehaviour
|
||||
{
|
||||
public static readonly HashSet<int> LockHash = new();
|
||||
public class AudioSensorData:IItem<AudioSensorData,Node<AudioSensorData>>
|
||||
{
|
||||
public int Id;
|
||||
@@ -20,6 +23,8 @@ namespace BITKit.Sensors
|
||||
public Transform Transform;
|
||||
public Bounds Bounds;
|
||||
public ITag Tag;
|
||||
public object NoiseType;
|
||||
public float ExpirationTime;
|
||||
public Bounds GetBounds() => Bounds;
|
||||
public Node<AudioSensorData> ParentNode { get; set; }
|
||||
public void QuadTree_Root_Initialized(IQuadtreeRoot<AudioSensorData, Node<AudioSensorData>> root){}
|
||||
@@ -27,40 +32,72 @@ namespace BITKit.Sensors
|
||||
internal static readonly QuadtreeRoot<AudioSensorData, Node<AudioSensorData>> QuadtreeRoot =
|
||||
new(default, Vector3.one * 2048);
|
||||
|
||||
private static Pool<AudioSensorData> pool = new(()=>new(), x=>{}, 1000);
|
||||
private static readonly Pool<AudioSensorData> pool = new(()=>new AudioSensorData(), x=>{}, 1000);
|
||||
private static readonly ConcurrentQueue<AudioSensorData> registerQueue = new();
|
||||
private static int count;
|
||||
public static async void MakeNoise(Vector3 position,Transform transform)
|
||||
private static readonly Queue<int> freeIds = new();
|
||||
private static readonly ConcurrentDictionary<int, AudioSensorData> dictionary = new();
|
||||
|
||||
public static void MakeNoise(Vector3 position, Transform transform, float radius = 1,
|
||||
object noiseType = null)
|
||||
{
|
||||
var data = pool.Take();
|
||||
data.Id = count++;
|
||||
data.Position = position;
|
||||
data.Transform = transform;
|
||||
data.Bounds = new Bounds(position, Vector3.one *1);
|
||||
data.Tag = transform.GetComponent<ITag>();
|
||||
QuadtreeRoot.Insert(data);
|
||||
await UniTask.Delay(3000);
|
||||
if (disposed) return;
|
||||
QuadtreeRoot.Remove(data);
|
||||
pool.Return(data);
|
||||
data.Bounds = new Bounds(position, Vector3.one * 1);
|
||||
if (transform)
|
||||
data.Tag = transform.GetComponent<ITag>();
|
||||
data.Radius = radius;
|
||||
data.ExpirationTime = Time.time + 0.5f;
|
||||
|
||||
registerQueue.Enqueue(data);
|
||||
}
|
||||
private static bool disposed;
|
||||
[SerializeReference, SubclassSelector] private ITicker ticker;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
disposed = false;
|
||||
ticker.Add(OnTick);
|
||||
ticker.Add(OnTick);
|
||||
destroyCancellationToken.Register(Dispose);
|
||||
pool.Clear();
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
registerQueue.Clear();
|
||||
ticker.Remove(OnTick);
|
||||
disposed = true;
|
||||
QuadtreeRoot.Clear();
|
||||
}
|
||||
|
||||
private void OnTick(float obj)
|
||||
{
|
||||
if (LockHash.Count > 0) return;
|
||||
|
||||
|
||||
while (registerQueue.TryDequeue(out var data))
|
||||
{
|
||||
|
||||
if (data.ExpirationTime < Time.time)
|
||||
{
|
||||
pool.Return(data);
|
||||
continue;
|
||||
}
|
||||
|
||||
QuadtreeRoot.Insert(data);
|
||||
dictionary.TryAdd(data.Id, data);
|
||||
}
|
||||
var currentTime = Time.time;
|
||||
foreach (var (id, data) in dictionary)
|
||||
{
|
||||
if (data.ExpirationTime > currentTime) continue;
|
||||
freeIds.Enqueue(id);
|
||||
QuadtreeRoot.Remove(data);
|
||||
pool.Return(data);
|
||||
}
|
||||
while (freeIds.TryDequeue(out var id))
|
||||
{
|
||||
dictionary.TryRemove(id, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -47,6 +47,7 @@ namespace BITKit.Sensors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
UniTask Execute(float delta);
|
||||
HashSet<int> Ignores{ get; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -74,6 +75,7 @@ namespace BITKit.Sensors
|
||||
{
|
||||
return _sensorImplementation.Execute(delta);
|
||||
}
|
||||
public HashSet<int> Ignores => _sensorImplementation.Ignores;
|
||||
}
|
||||
[System.Serializable]
|
||||
public class SensorMonoProxy:ISensor
|
||||
@@ -101,6 +103,7 @@ namespace BITKit.Sensors
|
||||
{
|
||||
return _sensorImplementation.Execute(delta);
|
||||
}
|
||||
public HashSet<int> Ignores => _sensorImplementation.Ignores;
|
||||
}
|
||||
public abstract class Sensor : MonoBehaviour, ISensor
|
||||
{
|
||||
@@ -109,13 +112,11 @@ namespace BITKit.Sensors
|
||||
public bool autoUpdate;
|
||||
[Header(Constant.Header.Gameobjects)]
|
||||
public Collider[] ignoreColliders;
|
||||
[Header(Constant.Header.InternalVariables)]
|
||||
[SerializeField,ReadOnly]
|
||||
public Transform[] detected = Array.Empty<Transform>();
|
||||
public abstract IEnumerable<Transform> Get();
|
||||
public abstract bool IsValid(Collider _collider);
|
||||
public abstract float GetDistance();
|
||||
public virtual UniTask Execute(float delta)=>UniTask.CompletedTask;
|
||||
public HashSet<int> Ignores { get; } = new();
|
||||
public int Id { get; private set; }
|
||||
bool ISensor.AutoUpdate => autoUpdate;
|
||||
|
||||
|
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Jobs;
|
||||
using UnityEngine.Pool;
|
||||
using UnityEngine.Profiling;
|
||||
@@ -13,19 +14,23 @@ 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.Debug)] [Header(Constant.Header.InternalVariables)]
|
||||
private FrameUpdate frameUpdater;
|
||||
[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;
|
||||
|
||||
public float DetectedHeightWeight
|
||||
{
|
||||
get=>detectedHeightWeight;
|
||||
set=>detectedHeightWeight=value;
|
||||
}
|
||||
private readonly Collider[] colliders = new Collider[32];
|
||||
private RaycastHit[] hits = new RaycastHit[32];
|
||||
private readonly HashSet<int> tempHashSet = new();
|
||||
|
||||
private readonly RaycastHit[] hits = new RaycastHit[32];
|
||||
private float _delta;
|
||||
|
||||
public override IEnumerable<Transform> Get()
|
||||
{
|
||||
if (!_detectedDoubleBuffer.TryGetRelease(out var newRelease)) return _detectedBuffer;
|
||||
@@ -40,7 +45,7 @@ namespace BITKit.Sensors
|
||||
|
||||
public override UniTask Execute(float delta)
|
||||
{
|
||||
tempHashSet.Clear();
|
||||
_delta = delta;
|
||||
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;
|
||||
@@ -53,10 +58,21 @@ namespace BITKit.Sensors
|
||||
{
|
||||
switch (_collider)
|
||||
{
|
||||
case var _ when Ignores.Contains(_collider.GetInstanceID()):
|
||||
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:
|
||||
}
|
||||
|
||||
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:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
@@ -75,23 +91,21 @@ namespace BITKit.Sensors
|
||||
|
||||
private bool CheckSight(ref Collider _collider)
|
||||
{
|
||||
if (!requireSight) return false;
|
||||
var position = _collider.bounds.center;
|
||||
//是检测bounds的顶部
|
||||
position.y += _collider.bounds.extents.y;
|
||||
var location = new Location(Transform);
|
||||
var bounds = _collider.bounds;
|
||||
var position = bounds.center;
|
||||
position.y += bounds.size.y * detectedHeightWeight /2;
|
||||
var selfPosition = Transform.position;
|
||||
var length = Physics.RaycastNonAlloc(
|
||||
location.position,
|
||||
position - location,
|
||||
selfPosition,
|
||||
position - selfPosition,
|
||||
hits,
|
||||
Vector3.Distance(location, position),
|
||||
blockLayer
|
||||
Vector3.Distance(selfPosition, position),
|
||||
requireSight.Value
|
||||
);
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 0:
|
||||
Debug.DrawLine(location, position, Color.green, 1);
|
||||
Debug.DrawLine(selfPosition, position, Color.green,_delta);
|
||||
return true;
|
||||
case 1:
|
||||
return hits[0].collider == _collider;
|
||||
@@ -107,7 +121,8 @@ namespace BITKit.Sensors
|
||||
var result = ignoreColliders.Contains(x.collider) is false && x.collider != collider1;
|
||||
if (result)
|
||||
{
|
||||
Debug.DrawLine(location, x.point, Color.red, 1);
|
||||
Debug.DrawLine(selfPosition, x.point, Color.yellow,_delta);
|
||||
Debug.DrawLine(selfPosition, position, Color.red,_delta);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -2,7 +2,9 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
namespace BITKit.Sensors
|
||||
{
|
||||
@@ -11,8 +13,11 @@ namespace BITKit.Sensors
|
||||
[Header(Constant.Header.Settings)]
|
||||
[SerializeField] private float radius = 0.16f;
|
||||
public float distance;
|
||||
public override IEnumerable<Transform> Get() => detected;
|
||||
public override IEnumerable<Transform> Get() => detected.ValueArray;
|
||||
private readonly RaycastHit[] raycasts = new RaycastHit[16];
|
||||
private readonly Queue<(Vector3,Vector3)> _drawGizmosQueue = new();
|
||||
private readonly CacheList<Transform> detected = new();
|
||||
|
||||
public override UniTask Execute(float delta)
|
||||
{
|
||||
var _transform = transform;
|
||||
@@ -28,25 +33,43 @@ namespace BITKit.Sensors
|
||||
}
|
||||
else
|
||||
{
|
||||
var ray = new Ray(_transform.position,_transform.forward);
|
||||
var ray = new Ray(_transform.position, _transform.forward);
|
||||
size = Physics.RaycastNonAlloc(ray, raycasts, distance, detectLayer);
|
||||
}
|
||||
|
||||
detected = raycasts
|
||||
.Take(size)
|
||||
.Select(x => x.collider)
|
||||
.Where(IsValid)
|
||||
.Select(x=>x.transform)
|
||||
.ToArray();
|
||||
//var reportBuilder = new StringBuilder();
|
||||
|
||||
detected.Clear();
|
||||
foreach (var hit in raycasts
|
||||
.Take(size)
|
||||
.Where(IsValid)
|
||||
.OrderBy(ByDistance))
|
||||
{
|
||||
detected.Add(hit.transform);
|
||||
}
|
||||
|
||||
//Debug.Log(reportBuilder);
|
||||
return UniTask.CompletedTask;
|
||||
|
||||
float ByDistance(RaycastHit arg)
|
||||
{
|
||||
var x = Vector3.Distance(arg.point, position);
|
||||
//_drawGizmosQueue.Enqueue(new(arg.collider.bounds.center, arg.point));
|
||||
//reportBuilder.AppendLine($"Name:{arg.collider.name},Distance:{x}");
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid(RaycastHit hit) => IsValid(hit.collider);
|
||||
public override bool IsValid(Collider _collider) => ignoreColliders.Contains(_collider) is false;
|
||||
public override float GetDistance() => distance;
|
||||
private void Update()
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (autoUpdate)
|
||||
while (_drawGizmosQueue.TryDequeue(out var p))
|
||||
{
|
||||
Execute(Time.deltaTime).Forget();
|
||||
var (closePoint, point) = p;
|
||||
Gizmos.DrawWireCube(point,Vector3.one*0.01f);
|
||||
Gizmos.DrawLine(closePoint,point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,22 +10,20 @@ namespace BITKit.Sensors
|
||||
{
|
||||
public class SensorQueue : MonoBehaviour
|
||||
{
|
||||
internal static readonly Dictionary<int,ISensor> Sensors=new();
|
||||
internal static readonly ConcurrentDictionary<int,ISensor> Sensors=new();
|
||||
internal static readonly ConcurrentDictionary<int, float> LastDetectedTime = new();
|
||||
private static bool IsDirty;
|
||||
|
||||
[SerializeField,ReadOnly] private int _position;
|
||||
|
||||
private static int[] _keys;
|
||||
|
||||
public static void Register(int id,ISensor sensor)
|
||||
{
|
||||
Sensors.Add(id,sensor);
|
||||
Sensors.TryAdd(id,sensor);
|
||||
MarkDirty();
|
||||
}
|
||||
public static void UnRegister(int id)
|
||||
{
|
||||
Sensors.Remove(id);
|
||||
Sensors.TryRemove(id);
|
||||
MarkDirty();
|
||||
}
|
||||
public static void MarkDirty()
|
||||
@@ -33,7 +31,6 @@ namespace BITKit.Sensors
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
[SerializeField] private MonoBehaviour[] sensors;
|
||||
[SerializeReference,SubclassSelector] private ITicker ticker;
|
||||
|
||||
private bool _isBusy;
|
||||
@@ -51,44 +48,46 @@ namespace BITKit.Sensors
|
||||
{
|
||||
if (_isBusy) return;
|
||||
if (SensorGlobalSettings.Enabled is false) return;
|
||||
|
||||
_isBusy = true;
|
||||
if(IsDirty)
|
||||
try
|
||||
{
|
||||
_position = 0;
|
||||
_keys = Sensors.Where(IsEnabled).Select(x=>x.Key).ToArray();
|
||||
IsDirty = false;
|
||||
sensors = Sensors.Values.Where(IsEnabled).OfType<MonoBehaviour>().ToArray();
|
||||
}
|
||||
|
||||
if (Sensors.Count is 0)
|
||||
{
|
||||
_isBusy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var current = Sensors.ElementAt(_position++).Value;
|
||||
var currentUpdateTime = LastDetectedTime.GetOrAdd(current.Id,Time.time);
|
||||
await current.Execute(Time.time-currentUpdateTime);
|
||||
float UpdateValueFactory(int key, float old) => Time.time;
|
||||
LastDetectedTime.AddOrUpdate(current.Id,Time.time,UpdateValueFactory);
|
||||
|
||||
if (destroyCancellationToken.IsCancellationRequested) {
|
||||
_isBusy = false;
|
||||
return;
|
||||
}
|
||||
_isBusy = true;
|
||||
if(IsDirty)
|
||||
{
|
||||
_position = 0;
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
|
||||
_position %= Sensors.Count;
|
||||
if (Sensors.Count is 0)
|
||||
{
|
||||
_isBusy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var current = Sensors.ElementAt(_position++).Value;
|
||||
|
||||
if (current.AutoUpdate)
|
||||
{
|
||||
|
||||
var currentUpdateTime = LastDetectedTime.GetOrAdd(current.Id,Time.time);
|
||||
await current.Execute(Time.time-currentUpdateTime);
|
||||
LastDetectedTime.AddOrUpdate(current.Id,Time.time,UpdateValueFactory);
|
||||
|
||||
if (destroyCancellationToken.IsCancellationRequested) {
|
||||
_isBusy = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_position %= Sensors.Count;
|
||||
float UpdateValueFactory(int key, float old) => Time.time;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
_isBusy = false;
|
||||
}
|
||||
private bool IsEnabled(ISensor sensor)
|
||||
{
|
||||
return sensor.AutoUpdate;
|
||||
}
|
||||
private bool IsEnabled(KeyValuePair<int,ISensor> pair)
|
||||
{
|
||||
return pair.Value.AutoUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -30,6 +30,7 @@ namespace BITKit.Sensors
|
||||
[SerializeField] private AudioSensor audioSensor;
|
||||
public int Id { get; set; }
|
||||
private readonly CacheList<Transform> _detected=new();
|
||||
public HashSet<int> Ignores { get; } = new();
|
||||
private void OnEnable()
|
||||
{
|
||||
Id = GetInstanceID();
|
||||
|
@@ -28,6 +28,7 @@ namespace BITKit.Sensors
|
||||
[Header(Constant.Header.InternalVariables)]
|
||||
// ReSharper disable once FieldCanBeMadeReadOnly.Local
|
||||
private List<Collider> detected = new();
|
||||
public HashSet<int> Ignores { get; } = new();
|
||||
|
||||
private readonly Queue<Collider> triggerEnterQueue = new();
|
||||
private readonly Queue<Collider> triggerExitQueue = new();
|
||||
@@ -171,7 +172,7 @@ namespace BITKit.Sensors
|
||||
if (!agent || detectedContainer is null) return;
|
||||
if (BITAppForUnity.IsPlaying is false) return;
|
||||
detectedContainer.Clear();
|
||||
foreach (var x in agent.detected)
|
||||
foreach (var x in agent.Get())
|
||||
{
|
||||
ObjectField objectField = new()
|
||||
{
|
||||
|
Reference in New Issue
Block a user