Compare commits

...

1 Commits
1.8 ... main

Author SHA1 Message Date
CortexCore c1f51826b3 1 2024-04-22 03:48:37 +08:00
35 changed files with 556 additions and 270 deletions

View File

@ -3,12 +3,15 @@
namespace BITKit namespace BITKit
{ {
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method)]
public class BITCommandAttribute : Attribute { } public class BITCommandAttribute : Attribute
{
}
/// <summary> /// <summary>
/// 自动注入依赖 /// 自动注入依赖
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Field)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class InjectAttribute : System.Attribute public class InjectAttribute : Attribute
{ {
public static void Clear(object obj) public static void Clear(object obj)
{ {

View File

@ -125,6 +125,29 @@ namespace BITKit
/// <param name="obj"></param> /// <param name="obj"></param>
public static void Inject(object obj) public static void Inject(object obj)
{ {
foreach (var propertyInfo in obj.GetType().GetProperties(ReflectionHelper.Flags))
{
try
{
if (propertyInfo.GetCustomAttribute<ObsoleteAttribute>() is null &&
propertyInfo.GetCustomAttribute<InjectAttribute>() is not null)
{
lock (dictionary)
{
if(dictionary!.TryGetValue(propertyInfo.PropertyType,out var value))
{
BIT4Log.Log<DI>($"已为{obj.GetType().Name}.{propertyInfo.Name}注入{value.GetType().Name}");
propertyInfo.SetValue(obj,value);
}
}
}
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
foreach (var field in obj.GetType().GetFields(ReflectionHelper.Flags)) foreach (var field in obj.GetType().GetFields(ReflectionHelper.Flags))
{ {
try try

View File

@ -15,7 +15,7 @@ namespace BITKit.Entities
/// 等待初始化完成,通常用于其他系统需要等待实体初始化完成 /// 等待初始化完成,通常用于其他系统需要等待实体初始化完成
/// </summary> /// </summary>
void WaitForInitializationComplete(); void WaitForInitializationComplete();
ulong Id { get; } int Id { get; }
CancellationToken CancellationToken { get; } CancellationToken CancellationToken { get; }
bool TryGetComponent<T>(out T component); bool TryGetComponent<T>(out T component);
IEntityComponent[] Components { get; } IEntityComponent[] Components { get; }
@ -81,18 +81,18 @@ namespace BITKit.Entities
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <returns></returns> /// <returns></returns>
IEntity Get(ulong id); IEntity Get(int id);
/// <summary> /// <summary>
/// 尝试通过Id获取Entity /// 尝试通过Id获取Entity
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="entity"></param> /// <param name="entity"></param>
/// <returns></returns> /// <returns></returns>
bool TryGetEntity(ulong id, out IEntity entity); bool TryGetEntity(int id, out IEntity entity);
/// <summary> /// <summary>
/// 通过Id获取或添加Entity /// 通过Id获取或添加Entity
/// </summary> /// </summary>
IEntity GetOrAdd(ulong id,Func<ulong,IEntity> factory); IEntity GetOrAdd(int id,Func<int,IEntity> factory);
/// <summary> /// <summary>
/// 查询Entity,例如 /// 查询Entity,例如

View File

@ -220,7 +220,6 @@ namespace BITKit.Mod
private static Thread _Thread; private static Thread _Thread;
private static bool _IsRunning; private static bool _IsRunning;
private static bool _IsLocked; private static bool _IsLocked;
private static AppDomain _ModDomain;
public static void Initialize() public static void Initialize()
{ {
@ -241,8 +240,6 @@ namespace BITKit.Mod
try try
{ {
_ModDomain = AppDomain.CreateDomain("ModDomain");
var modPath = Path.Combine(Environment.CurrentDirectory, "Mods\\"); var modPath = Path.Combine(Environment.CurrentDirectory, "Mods\\");
PathHelper.EnsureDirectoryCreated(modPath); PathHelper.EnsureDirectoryCreated(modPath);
var directoryInfo = new DirectoryInfo(modPath); var directoryInfo = new DirectoryInfo(modPath);
@ -383,7 +380,6 @@ namespace BITKit.Mod
_UnRegisterQueue.Clear(); _UnRegisterQueue.Clear();
Mods = Array.Empty<IMod>(); Mods = Array.Empty<IMod>();
_InstalledMods.Clear(); _InstalledMods.Clear();
AppDomain.Unload(_ModDomain);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -41,6 +41,15 @@
"interactions": "Press,Tap", "interactions": "Press,Tap",
"initialStateCheck": false "initialStateCheck": false
}, },
{
"name": "Crawl",
"type": "Button",
"id": "350ae177-bf96-40b1-aff0-e10865947df9",
"expectedControlType": "Button",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{ {
"name": "HoldCrouch", "name": "HoldCrouch",
"type": "Button", "type": "Button",
@ -570,6 +579,17 @@
"action": "Inspect", "action": "Inspect",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
},
{
"name": "",
"id": "a533436d-c3bf-4cb3-93b2-1ca02791e6d1",
"path": "<Keyboard>/leftCtrl",
"interactions": "Press,Hold",
"processors": "",
"groups": "",
"action": "Crawl",
"isComposite": false,
"isPartOfComposite": false
} }
] ]
}, },

View File

@ -6,10 +6,10 @@ namespace BITKit
public class AnimatorHelper : MonoBehaviour public class AnimatorHelper : MonoBehaviour
{ {
[SerializeField] private Transform root; [SerializeField] private Transform root;
[SerializeField] private bool allowAnimatorMove;
private void OnAnimatorMove() private void OnAnimatorMove()
{ {
if (root) if (root && allowAnimatorMove)
root.SendMessageUpwards(nameof(OnAnimatorMove),SendMessageOptions.DontRequireReceiver); root.SendMessageUpwards(nameof(OnAnimatorMove),SendMessageOptions.DontRequireReceiver);
} }
private void AIAnimationEvent(string actionName) private void AIAnimationEvent(string actionName)

View File

@ -62,6 +62,7 @@ namespace BITKit.Entities
/// </summary> /// </summary>
public interface IEntityMovement:IStateMachine<IEntityMovementState> public interface IEntityMovement:IStateMachine<IEntityMovementState>
{ {
Vector3 Size => Vector3.one;
float ReferenceSpeed => 2.5f; float ReferenceSpeed => 2.5f;
Vector3 Position { get; set; } Vector3 Position { get; set; }
Quaternion Rotation { get; set; } Quaternion Rotation { get; set; }
@ -138,5 +139,6 @@ namespace BITKit.Entities
void BeforeUpdateMovement(float deltaTime); void BeforeUpdateMovement(float deltaTime);
void AfterUpdateMovement(float deltaTime); void AfterUpdateMovement(float deltaTime);
void ExecuteCommand<T>(T command); void ExecuteCommand<T>(T command);
void DrawGizmos();
} }
} }

View File

@ -81,8 +81,8 @@ namespace BITKit.Entities
{ {
public override DamageMessage ReadBinary(BinaryReader reader) public override DamageMessage ReadBinary(BinaryReader reader)
{ {
UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var initiator); UnityEntitiesService.TryGetEntity(reader.ReadInt32(),out var initiator);
UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var target); UnityEntitiesService.TryGetEntity(reader.ReadInt32(),out var target);
return new DamageMessage() return new DamageMessage()
{ {
Initiator = initiator as Entity, Initiator = initiator as Entity,

View File

@ -3,7 +3,9 @@ using System.Collections.Generic;
using BITFALL.Rig; using BITFALL.Rig;
using BITKit.Entities; using BITKit.Entities;
using Cysharp.Threading.Tasks.Triggers; using Cysharp.Threading.Tasks.Triggers;
#if UNITY_EDITOR
using UnityEditor; using UnityEditor;
#endif
using UnityEngine; using UnityEngine;
namespace BITKit namespace BITKit
@ -14,6 +16,7 @@ namespace BITKit
[SerializeField] private EntityHitbox[] hitboxes; [SerializeField] private EntityHitbox[] hitboxes;
[SerializeReference,SubclassSelector] private IReference[] tagReferences; [SerializeReference,SubclassSelector] private IReference[] tagReferences;
#if UNITY_EDITOR
[BIT] [BIT]
private void Build() private void Build()
{ {
@ -73,5 +76,6 @@ namespace BITKit
} }
EditorUtility.SetDirty(this); EditorUtility.SetDirty(this);
} }
#endif
} }
} }

View File

@ -20,7 +20,7 @@ namespace BITKit.Entities
private readonly GenericEvent genericEvent = new(); private readonly GenericEvent genericEvent = new();
public ulong Id { get; set; } public int Id { get; set; }
public CancellationToken CancellationToken { get; private set; } public CancellationToken CancellationToken { get; private set; }
public IEntityBehavior[] Behaviors { get;private set; } public IEntityBehavior[] Behaviors { get;private set; }
public IEntityComponent[] Components => Behaviors.Cast<IEntityComponent>().ToArray(); public IEntityComponent[] Components => Behaviors.Cast<IEntityComponent>().ToArray();
@ -33,9 +33,43 @@ namespace BITKit.Entities
IServiceProvider Entities.IEntity.ServiceProvider=> throw new InvalidOperationException("Unity Entity can't register component"); IServiceProvider Entities.IEntity.ServiceProvider=> throw new InvalidOperationException("Unity Entity can't register component");
public void Inject(object obj) public void Inject(object obj)
{ {
foreach (var propertyInfo in obj
.GetType()
.GetProperties(ReflectionHelper.Flags)
.Where(x=>x.GetCustomAttribute<InjectAttribute>(true) is not null))
{
var type = propertyInfo.PropertyType;
var attribute = propertyInfo.GetCustomAttribute<InjectAttribute>();
var currentValue = propertyInfo.GetValue(obj);
try
{
switch (currentValue)
{
case null:
break;
case IEntityComponent entityComponent:
if(entityComponent.Entity.Id == Id)
continue;
break;
case MonoBehaviour { destroyCancellationToken: { IsCancellationRequested: false } }:
continue;
case not null:
continue;
}
}
catch (MissingReferenceException){}
if(genericEvent.TryGetObjectDirect(type.FullName,out var value))
{
propertyInfo.SetValue(obj,value,null);
}
else if(attribute?.CanBeNull is false)
{
BIT4Log.Warning<Entity>($"{name}未找到{obj.GetType().Name}需要的{type.FullName}");
}
}
foreach (var fieldInfo in obj foreach (var fieldInfo in obj
.GetType() .GetType()
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .GetFields(ReflectionHelper.Flags)
.Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>(true) is not null)) .Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>(true) is not null))
{ {
var type = fieldInfo.FieldType; var type = fieldInfo.FieldType;
@ -97,7 +131,7 @@ namespace BITKit.Entities
private void Awake() private void Awake()
{ {
if (Id.IsDefault()) if (Id.IsDefault())
Id = (ulong)Guid.NewGuid().GetHashCode(); Id = GetInstanceID();
CancellationToken = gameObject.GetCancellationTokenOnDestroy(); CancellationToken = gameObject.GetCancellationTokenOnDestroy();
Set(CancellationToken); Set(CancellationToken);
} }

View File

@ -48,6 +48,13 @@ namespace BITKit.Entities
stateMachine.Initialize(); stateMachine.Initialize();
} }
} }
public override void OnDestroyComponent()
{
base.OnDestroyComponent();
CurrentState?.OnStateExit(CurrentState,null);
}
void IStateMachine<T>.Initialize() void IStateMachine<T>.Initialize()
{ {
stateMachine.Initialize(); stateMachine.Initialize();

View File

@ -38,10 +38,10 @@ public class UnityEntitiesServiceSingleton:IEntitiesService
public CancellationToken CancellationToken => UnityEntitiesService.CancellationToken; public CancellationToken CancellationToken => UnityEntitiesService.CancellationToken;
public IEntity Get(ulong id) => UnityEntitiesService.Get(id); public IEntity Get(int id) => UnityEntitiesService.Get(id);
public bool TryGetEntity(ulong id, out IEntity entity) => UnityEntitiesService.TryGetEntity(id, out entity); public bool TryGetEntity(int id, out IEntity entity) => UnityEntitiesService.TryGetEntity(id, out entity);
public IEntity GetOrAdd(ulong id, Func<ulong, IEntity> factory)=>UnityEntitiesService.GetOrAdd(id,factory); public IEntity GetOrAdd(int id, Func<int, IEntity> factory)=>UnityEntitiesService.GetOrAdd(id,factory);
public IEntity[] Query<T>() public IEntity[] Query<T>()
@ -85,7 +85,7 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
return false; return false;
} }
public static CancellationToken CancellationToken; public static CancellationToken CancellationToken;
private static readonly ConcurrentDictionary<ulong,IEntity> Dictionary=new(); private static readonly ConcurrentDictionary<int,IEntity> Dictionary=new();
private static readonly Queue<IEntity> RegisterQueue = new(); private static readonly Queue<IEntity> RegisterQueue = new();
private static readonly Queue<IEntity> UnRegisterQueue = new(); private static readonly Queue<IEntity> UnRegisterQueue = new();
private void Awake() private void Awake()
@ -126,18 +126,18 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
} }
CancellationToken IEntitiesService.CancellationToken => CancellationToken; CancellationToken IEntitiesService.CancellationToken => CancellationToken;
public static IEntity Get(ulong id)=>Dictionary[id]; public static IEntity Get(int id)=>Dictionary[id];
IEntity IEntitiesService.Get(ulong id)=>Get(id); IEntity IEntitiesService.Get(int id)=>Get(id);
public static bool TryGetEntity(ulong id, out IEntity entity) public static bool TryGetEntity(int id, out IEntity entity)
{ {
return Dictionary.TryGetValue(id, out entity); return Dictionary.TryGetValue(id, out entity);
} }
bool IEntitiesService.TryGetEntity(ulong id, out IEntity entity)=>TryGetEntity(id,out entity); bool IEntitiesService.TryGetEntity(int id, out IEntity entity)=>TryGetEntity(id,out entity);
public static IEntity GetOrAdd(ulong id, Func<ulong, IEntity> factory) public static IEntity GetOrAdd(int id, Func<int, IEntity> factory)
{ {
return Dictionary.GetOrAdd(id, factory); return Dictionary.GetOrAdd(id, factory);
} }
IEntity IEntitiesService.GetOrAdd(ulong id, Func<ulong, IEntity> factory)=>GetOrAdd(id,factory); IEntity IEntitiesService.GetOrAdd(int id, Func<int, IEntity> factory)=>GetOrAdd(id,factory);
IEntity[] IEntitiesService.Query<T>()=>Query<T>(); IEntity[] IEntitiesService.Query<T>()=>Query<T>();
public static IEntity[] Query<T>() public static IEntity[] Query<T>()

View File

@ -7,14 +7,14 @@ namespace BITKit.Entities
{ {
public interface IdComponent public interface IdComponent
{ {
ulong Id { get; } int Id { get; }
string Name { get; } string Name { get; }
} }
public class UnityIdComponent : EntityBehavior,IdComponent public class UnityIdComponent : EntityBehavior,IdComponent
{ {
[SerializeField] private ulong id; [SerializeField] private int id;
[SerializeField] private string unityName; [SerializeField] private string unityName;
public ulong Id => id; public int Id => id;
public string Name => unityName; public string Name => unityName;
public override void Initialize(IEntity _entity) public override void Initialize(IEntity _entity)
{ {

View File

@ -19,7 +19,7 @@ namespace BITKit.Entities
public struct EntitiesNetSyncBatchCommand public struct EntitiesNetSyncBatchCommand
{ {
public int Length; public int Length;
public ulong[] Ids; public int[] Ids;
public ulong[] AddressablePaths; public ulong[] AddressablePaths;
public EntitiesNetSyncCommand[] Commands; public EntitiesNetSyncCommand[] Commands;
} }
@ -81,7 +81,7 @@ namespace BITKit.Entities
{ {
using var ms = new MemoryStream(obj.Data); using var ms = new MemoryStream(obj.Data);
using var reader = new BinaryReader(ms); using var reader = new BinaryReader(ms);
var id = reader.ReadUInt64(); var id = reader.ReadInt32();
var path = reader.ReadUInt64(); var path = reader.ReadUInt64();
entitiesService.GetOrAdd(id, x => AddEntity(id, path)).TryGetComponent<IEntityBinaryHeader>(out var header); entitiesService.GetOrAdd(id, x => AddEntity(id, path)).TryGetComponent<IEntityBinaryHeader>(out var header);
header.Deserialize(reader); header.Deserialize(reader);
@ -100,7 +100,7 @@ namespace BITKit.Entities
header.Deserialize(reader); header.Deserialize(reader);
} }
} }
private static IEntity AddEntity(ulong id,ulong addressableId) private static IEntity AddEntity(int id,ulong addressableId)
{ {
var entity = AddressableHelper.Get<GameObject>(addressableId); var entity = AddressableHelper.Get<GameObject>(addressableId);
var instance = Instantiate(entity).GetComponent<Entity>(); var instance = Instantiate(entity).GetComponent<Entity>();
@ -146,7 +146,7 @@ namespace BITKit.Entities
var batchCommand = new EntitiesNetSyncBatchCommand() var batchCommand = new EntitiesNetSyncBatchCommand()
{ {
Length = headers.Length, Length = headers.Length,
Ids = new ulong[headers.Length], Ids = new int[headers.Length],
AddressablePaths = new ulong[headers.Length], AddressablePaths = new ulong[headers.Length],
Commands = new EntitiesNetSyncCommand[headers.Length] Commands = new EntitiesNetSyncCommand[headers.Length]
}; };

View File

@ -15,8 +15,8 @@ namespace BITKit.Entities.Player
[SerializeField] private MonoStateMachine<T> stateMachine; [SerializeField] private MonoStateMachine<T> stateMachine;
public override void OnAwake() public override void OnAwake()
{ {
stateMachine?.Initialize();
base.OnAwake(); base.OnAwake();
stateMachine?.Initialize();
} }
public bool Enabled public bool Enabled

View File

@ -3,57 +3,121 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
namespace BITKit namespace BITKit
{ {
public interface IClosePoint public interface IClosePoint
{ {
Vector3 CurrentPoint { get; }
Collider Collider { get; } Collider Collider { get; }
bool TryGetClosePoint(out Vector3 vector3); bool TryGetClosePoint(out Vector3 vector3);
} }
[System.Serializable] [Serializable]
public class GetClosePointFromCollider : IClosePoint public class GetClosePointFromCollider : IClosePoint
{ {
public Transform root; [SerializeField] private string name;
public LayerMask layerMask; [SerializeField] private Transform transform;
public float distance; [SerializeField] private Vector3 offset = Vector3.one;
[SerializeField] private LayerMask layerMask;
[SerializeField] private float distance;
[SerializeField] private float minHeight=0.32f;
[SerializeField] private float maxHeight = 1f;
public Vector3 CurrentPoint { get; set; }
public Collider Collider { get; set; } public Collider Collider { get; set; }
private Collider[] _colliders=new Collider[8];
private Collider[] _mainCollider=new Collider[8];
public bool TryGetClosePoint(out Vector3 vector3) public bool TryGetClosePoint(out Vector3 vector3)
{ {
vector3 = default; vector3 = default;
if (UnityEngine.Physics.Raycast(root.position, root.forward, out var raycastHit, distance, layerMask)) StringBuilder reportBuilder = new();
reportBuilder.AppendLine($"检测任务:{name}");
var position = transform.position + transform.rotation * offset;
var detectedLength = Physics.OverlapSphereNonAlloc(position, distance, _mainCollider, layerMask);
reportBuilder.AppendLine($"检测到了{detectedLength}个碰撞体");
for (var i = 0; i <detectedLength ; i++)
{ {
var collider = raycastHit.collider; reportBuilder.AppendLine($"----------------------------检测到了碰撞体{_mainCollider[i].name}");
if (collider.isTrigger) return false; var collider = _mainCollider[i];
if (collider.isTrigger)
{
reportBuilder?.AppendLine("碰撞体是触发器");
continue;
}
switch (collider) switch (collider)
{ {
case MeshCollider meshCollider: case MeshCollider meshCollider:
if (meshCollider.convex is false) if (meshCollider.convex is false)
return false; {
reportBuilder?.AppendLine("MeshCollider未勾选Convex");
continue;
}
break; break;
} }
vector3 = collider.ClosestPoint(root.position + Vector3.up); var bounds = collider.bounds;
var top = collider.bounds.center + collider.bounds.extents; vector3 = collider.ClosestPoint(transform.position + Vector3.up*64);
var top = bounds.center.y + bounds.extents.y;
if (Mathf.Abs(vector3.y - top.y) > 0.16f) return false; Debug.DrawLine(transform.position,transform.position + Vector3.up * top,Color.blue,8f);
if (transform.position.y + minHeight > top)
if (UnityEngine.Physics.Linecast(root.position, vector3, out var raycastHit2, layerMask))
{ {
if(raycastHit2.collider != collider) reportBuilder?.AppendLine("高度不足");
return false; continue;
}
var nextPos = position;
nextPos.y = collider.bounds.center.y;
if (collider.Raycast(new Ray(nextPos, transform.forward), out _, distance) is false)
{
reportBuilder?.AppendLine("未检测到前方");
continue;
}
var height = Mathf.Abs(top - transform.position.y);
if (height > maxHeight)
{
reportBuilder?.AppendLine($"高度差距过大:{height}");
continue;
}
if (Physics.Linecast(transform.position, vector3, out var raycastHit2, layerMask))
{
if (raycastHit2.collider != collider)
{
reportBuilder?.AppendLine($"检测到了其他碰撞体:{raycastHit2.transform.name}");
continue;
}
}; };
foreach(var hit in UnityEngine.Physics.OverlapSphere(vector3, 0.1f, layerMask))
var length = Physics.OverlapSphereNonAlloc(vector3, 0.01f, _colliders, layerMask);
switch (length)
{ {
if(hit!= collider) case 1:
return false; if (_colliders[0] != collider)
{
reportBuilder.AppendLine($"检测到了其他碰撞体{_colliders[0].name}");
continue;
}
break;
case > 1:
reportBuilder.AppendLine("检测到了更多碰撞体");
for (var ii = 0; ii < length; ii++)
{
//Debug.DrawLine(vector3, _colliders[ii].ClosestPoint(vector3), Color.red, 8);
reportBuilder.AppendLine($"\t{_colliders[ii].name}");
}
continue;
} }
Collider = collider; Collider = collider;
vector3.y = top;
CurrentPoint = vector3;
reportBuilder.AppendLine("<color=green>成功</color>");
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
return true; return true;
//return vector3.y >= collider.bounds.center.y + collider.bounds.extents.y;
//return true;
} }
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
return false; return false;
} }
} }
@ -74,6 +138,7 @@ namespace BITKit
public Vector3 StartPosition; public Vector3 StartPosition;
public Vector3 EndPosition; public Vector3 EndPosition;
public Vector3 CurrentPoint { get; set; }
public Collider Collider { get; set; } public Collider Collider { get; set; }
private Rigidbody rigidbody; private Rigidbody rigidbody;
@ -92,7 +157,8 @@ namespace BITKit
if (rigidbody.velocity.GetLength() < 0.1f) return false; if (rigidbody.velocity.GetLength() < 0.1f) return false;
} }
var reportBuilder = new System.Text.StringBuilder(); //var reportBuilder = new System.Text.StringBuilder();
StringBuilder reportBuilder=null;
var forward = root.forward; var forward = root.forward;
var sourceStartPosition = groundReference.position; var sourceStartPosition = groundReference.position;
@ -101,7 +167,7 @@ namespace BITKit
var collider = UnityEngine.Physics.OverlapSphere(startPosition, radius, layerMask); var collider = UnityEngine.Physics.OverlapSphere(startPosition, radius, layerMask);
reportBuilder.AppendLine($"检测到了{collider.Length}个碰撞体"); reportBuilder?.AppendLine($"检测到了{collider.Length}个碰撞体");
foreach (var hit in collider) foreach (var hit in collider)
{ {
@ -112,12 +178,12 @@ namespace BITKit
continue; continue;
} }
reportBuilder.AppendLine(); reportBuilder?.AppendLine();
reportBuilder.AppendLine($">{hit.name}"); reportBuilder?.AppendLine($">{hit.name}");
if(top.y>groundReference.transform.position.y+maxHeight) if(top.y>groundReference.transform.position.y+maxHeight)
{ {
reportBuilder.AppendLine("高度超出可翻越高度"); reportBuilder?.AppendLine("高度超出可翻越高度");
continue; continue;
} }
@ -128,9 +194,9 @@ namespace BITKit
if (hit.Raycast(ray, out var colliderHit, 8) is false) if (hit.Raycast(ray, out var colliderHit, 8) is false)
{ {
reportBuilder.AppendLine("未检测到背面,算法错误"); reportBuilder?.AppendLine("未检测到背面,算法错误");
Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8); //Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8);
continue; continue;
} }
@ -151,15 +217,15 @@ namespace BITKit
} }
catch (OperationCanceledException e) catch (OperationCanceledException e)
{ {
reportBuilder.AppendLine(e.Message); reportBuilder?.AppendLine(e.Message);
continue; continue;
} }
if(UnityEngine.Physics.Raycast(EndPosition,Vector3.down,out _,1.6f,layerMask) is false) if(UnityEngine.Physics.Raycast(EndPosition,Vector3.down,out _,1.6f,layerMask) is false)
{ {
Debug.DrawRay(EndPosition, Vector3.down*1.6f, Color.red, 8); //Debug.DrawRay(EndPosition, Vector3.down*1.6f, Color.red, 8);
reportBuilder.AppendLine("未检测到地面,跳过"); reportBuilder?.AppendLine("未检测到地面,跳过");
continue; continue;
//Debug.DrawRay(EndPosition, Vector3.down, Color.red, 8); //Debug.DrawRay(EndPosition, Vector3.down, Color.red, 8);
} }
@ -174,7 +240,7 @@ namespace BITKit
end2.y -= 0.1f; end2.y -= 0.1f;
if(UnityEngine.Physics.Linecast(start2,end2,out var downHit,layerMask)) if(UnityEngine.Physics.Linecast(start2,end2,out var downHit,layerMask))
{ {
reportBuilder.AppendLine($"检测到了障碍物{downHit.collider.name}"); reportBuilder?.AppendLine($"检测到了障碍物{downHit.collider.name}");
//BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString()); //BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
continue; continue;
@ -186,8 +252,8 @@ namespace BITKit
ray = new Ray(start, forward); ray = new Ray(start, forward);
if(hit.Raycast(ray,out colliderHit,8) is false) if(hit.Raycast(ray,out colliderHit,8) is false)
{ {
reportBuilder.AppendLine("未检测到正面,算法错误"); reportBuilder?.AppendLine("未检测到正面,算法错误");
Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8); //Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8);
continue; continue;
} }
@ -200,14 +266,26 @@ namespace BITKit
var lineDistance = Vector3.Distance(closeStart, closeEnd); var lineDistance = Vector3.Distance(closeStart, closeEnd);
if(lineDistance > maxVaultDistance) if(lineDistance > maxVaultDistance)
{ {
reportBuilder.AppendLine($"长度{lineDistance}超出可翻越距离{maxVaultDistance}"); reportBuilder?.AppendLine($"长度{lineDistance}超出可翻越距离{maxVaultDistance}");
Debug.DrawLine(closeStart,closeEnd, Color.yellow, 4); //Debug.DrawLine(closeStart,closeEnd, Color.yellow, 4);
//BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString()); //BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
continue; continue;
} }
if(Physics.Linecast(closeStart+Vector3.up*0.1f,closeEnd+Vector3.up*0.1f,out var _hit,layerMask))
{
//Debug.DrawLine(closeStart+Vector3.up*0.1f,_hit.point, Color.red, 4);
reportBuilder?.AppendLine("检测到了障碍物");
continue;
}
else
{
//Debug.DrawLine(closeStart+Vector3.up*0.1f,closeEnd+Vector3.up*0.1f, Color.green, 4);
}
vector3 = colliderHit.point; vector3 = colliderHit.point;
@ -215,14 +293,19 @@ namespace BITKit
vector3 += colliderHit.normal * 0.4f; vector3 += colliderHit.normal * 0.4f;
reportBuilder.AppendLine(); reportBuilder?.AppendLine();
if(reportBuilder is not null)
BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString()); BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
CurrentPoint = vector3;
Collider = hit;
return true; return true;
} }
reportBuilder.AppendLine($"failed"); reportBuilder?.AppendLine($"failed");
if(reportBuilder is not null)
BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString()); BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
vector3 = default; vector3 = default;

View File

@ -2,7 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
#if UNITY_EDITOR
using UnityEditor; using UnityEditor;
#endif
namespace Quadtree namespace Quadtree
{ {
@ -405,10 +407,12 @@ namespace Quadtree
public void DrawBounds(bool displayNumberOfItems = false) public void DrawBounds(bool displayNumberOfItems = false)
{ {
#if UNITY_EDITOR
if (displayNumberOfItems) if (displayNumberOfItems)
Handles.Label(Bounds.center, _items.Count.ToString()); Handles.Label(Bounds.center, _items.Count.ToString());
Gizmos.DrawWireCube(Bounds.center, Bounds.size); Gizmos.DrawWireCube(Bounds.center, Bounds.size);
#endif
foreach (var subNode in SubNodes) foreach (var subNode in SubNodes)
subNode.DrawBounds(displayNumberOfItems); subNode.DrawBounds(displayNumberOfItems);
} }

View File

@ -5,7 +5,6 @@ using Cysharp.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.Pool; using UnityEngine.Pool;
using System.Linq; using System.Linq;
using UnityEditor.Search;
namespace BITKit.Sensors namespace BITKit.Sensors
{ {
@ -19,6 +18,8 @@ namespace BITKit.Sensors
[SerializeField] private bool autoUpdate; [SerializeField] private bool autoUpdate;
[SerializeField]private float radius; [SerializeField]private float radius;
private readonly CacheList<Transform> cache = new(); private readonly CacheList<Transform> cache = new();
private readonly CacheList<AudioSensorService.AudioSensorData> data = new();
public AudioSensorService.AudioSensorData[] Noises => data.ValueArray;
private void OnEnable() private void OnEnable()
{ {
Id = GetInstanceID(); Id = GetInstanceID();
@ -32,14 +33,19 @@ namespace BITKit.Sensors
{ {
var position = transform.position; var position = transform.position;
cache.Clear(); cache.Clear();
data.Clear();
foreach (var x in AudioSensorService.QuadtreeRoot.Find(new Bounds(position, Vector3.one * radius))) foreach (var x in AudioSensorService.QuadtreeRoot.Find(new Bounds(position, Vector3.one * radius)))
{ {
var distance = Vector3.Distance(position, x.Position); var distance = Vector3.Distance(position, x.Position);
if(distance>radius) continue; if (distance > radius) continue;
cache.Add(x.Transform); if (x.Transform)
cache.Add(x.Transform);
data.Add(x);
} }
return UniTask.CompletedTask; return UniTask.CompletedTask;
} }
public HashSet<int> Ignores { get; } = new();
public int Id { get; set; } public int Id { get; set; }
public IEnumerable<Transform> Get() => cache.ValueArray; public IEnumerable<Transform> Get() => cache.ValueArray;
public bool IsValid(Collider _collider) => false; public bool IsValid(Collider _collider) => false;

View File

@ -10,6 +10,7 @@ using UnityEngine.Pool;
namespace BITKit.Sensors namespace BITKit.Sensors
{ {
public struct ClassicNoise{}
public class AudioSensorService : MonoBehaviour public class AudioSensorService : MonoBehaviour
{ {
public class AudioSensorData:IItem<AudioSensorData,Node<AudioSensorData>> public class AudioSensorData:IItem<AudioSensorData,Node<AudioSensorData>>
@ -20,6 +21,7 @@ namespace BITKit.Sensors
public Transform Transform; public Transform Transform;
public Bounds Bounds; public Bounds Bounds;
public ITag Tag; public ITag Tag;
public object NoiseType;
public Bounds GetBounds() => Bounds; public Bounds GetBounds() => Bounds;
public Node<AudioSensorData> ParentNode { get; set; } public Node<AudioSensorData> ParentNode { get; set; }
public void QuadTree_Root_Initialized(IQuadtreeRoot<AudioSensorData, Node<AudioSensorData>> root){} public void QuadTree_Root_Initialized(IQuadtreeRoot<AudioSensorData, Node<AudioSensorData>> root){}
@ -29,20 +31,25 @@ namespace BITKit.Sensors
private static Pool<AudioSensorData> pool = new(()=>new(), x=>{}, 1000); private static Pool<AudioSensorData> pool = new(()=>new(), x=>{}, 1000);
private static int count; private static int count;
public static async void MakeNoise(Vector3 position,Transform transform)
public static async void MakeNoise(Vector3 position, Transform transform, float radius = 1,
object noiseType = null)
{ {
var data = pool.Take(); var data = pool.Take();
data.Id = count++; data.Id = count++;
data.Position = position; data.Position = position;
data.Transform = transform; data.Transform = transform;
data.Bounds = new Bounds(position, Vector3.one *1); data.Bounds = new Bounds(position, Vector3.one * 1);
data.Tag = transform.GetComponent<ITag>(); if (transform)
data.Tag = transform.GetComponent<ITag>();
data.Radius = radius;
QuadtreeRoot.Insert(data); QuadtreeRoot.Insert(data);
await UniTask.Delay(3000); await UniTask.Delay(3000);
if (disposed) return; if (disposed) return;
QuadtreeRoot.Remove(data); QuadtreeRoot.Remove(data);
pool.Return(data); pool.Return(data);
} }
private static bool disposed; private static bool disposed;
[SerializeReference, SubclassSelector] private ITicker ticker; [SerializeReference, SubclassSelector] private ITicker ticker;
private void Start() private void Start()

View File

@ -47,6 +47,7 @@ namespace BITKit.Sensors
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
UniTask Execute(float delta); UniTask Execute(float delta);
HashSet<int> Ignores{ get; }
} }
[Serializable] [Serializable]
@ -74,6 +75,7 @@ namespace BITKit.Sensors
{ {
return _sensorImplementation.Execute(delta); return _sensorImplementation.Execute(delta);
} }
public HashSet<int> Ignores => _sensorImplementation.Ignores;
} }
[System.Serializable] [System.Serializable]
public class SensorMonoProxy:ISensor public class SensorMonoProxy:ISensor
@ -101,6 +103,7 @@ namespace BITKit.Sensors
{ {
return _sensorImplementation.Execute(delta); return _sensorImplementation.Execute(delta);
} }
public HashSet<int> Ignores => _sensorImplementation.Ignores;
} }
public abstract class Sensor : MonoBehaviour, ISensor public abstract class Sensor : MonoBehaviour, ISensor
{ {
@ -109,13 +112,11 @@ namespace BITKit.Sensors
public bool autoUpdate; public bool autoUpdate;
[Header(Constant.Header.Gameobjects)] [Header(Constant.Header.Gameobjects)]
public Collider[] ignoreColliders; public Collider[] ignoreColliders;
[Header(Constant.Header.InternalVariables)]
[SerializeField,ReadOnly]
public Transform[] detected = Array.Empty<Transform>();
public abstract IEnumerable<Transform> Get(); public abstract IEnumerable<Transform> Get();
public abstract bool IsValid(Collider _collider); public abstract bool IsValid(Collider _collider);
public abstract float GetDistance(); public abstract float GetDistance();
public virtual UniTask Execute(float delta)=>UniTask.CompletedTask; public virtual UniTask Execute(float delta)=>UniTask.CompletedTask;
public HashSet<int> Ignores { get; } = new();
public int Id { get; private set; } public int Id { get; private set; }
bool ISensor.AutoUpdate => autoUpdate; bool ISensor.AutoUpdate => autoUpdate;

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using System.Linq; using System.Linq;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine.Jobs; using UnityEngine.Jobs;
using UnityEngine.Pool; using UnityEngine.Pool;
using UnityEngine.Profiling; using UnityEngine.Profiling;
@ -13,19 +14,23 @@ namespace BITKit.Sensors
{ {
public class RangeSensor : Sensor public class RangeSensor : Sensor
{ {
[Header(Constant.Header.Settings)] public float radius; [Header(Constant.Header.Settings)]
public int fov; [SerializeField] private float radius;
public bool requireSight; [SerializeField] private float detectedHeightWeight=0.5f;
[Header(Constant.Header.Optional)]
[Header(Constant.Header.Settings)] public LayerMask blockLayer; [SerializeField] private Optional<int> fov;
[SerializeField] private Optional<LayerMask> requireSight;
[Header(Constant.Header.Debug)] [Header(Constant.Header.InternalVariables)] [SerializeField] private Optional<float> perceptionRadius;
private FrameUpdate frameUpdater;
public float DetectedHeightWeight
{
get=>detectedHeightWeight;
set=>detectedHeightWeight=value;
}
private readonly Collider[] colliders = new Collider[32]; private readonly Collider[] colliders = new Collider[32];
private RaycastHit[] hits = new RaycastHit[32]; private readonly RaycastHit[] hits = new RaycastHit[32];
private readonly HashSet<int> tempHashSet = new(); private float _delta;
public override IEnumerable<Transform> Get() public override IEnumerable<Transform> Get()
{ {
if (!_detectedDoubleBuffer.TryGetRelease(out var newRelease)) return _detectedBuffer; if (!_detectedDoubleBuffer.TryGetRelease(out var newRelease)) return _detectedBuffer;
@ -40,7 +45,7 @@ namespace BITKit.Sensors
public override UniTask Execute(float delta) public override UniTask Execute(float delta)
{ {
tempHashSet.Clear(); _delta = delta;
var length = Physics.OverlapSphereNonAlloc(Transform.position, radius, colliders, detectLayer); var length = Physics.OverlapSphereNonAlloc(Transform.position, radius, colliders, detectLayer);
Profiler.BeginSample("Filter Detected Colliders"); Profiler.BeginSample("Filter Detected Colliders");
var _newDetected = from x in colliders.Take(length) where IsValid(x) select x.transform; var _newDetected = from x in colliders.Take(length) where IsValid(x) select x.transform;
@ -53,10 +58,21 @@ namespace BITKit.Sensors
{ {
switch (_collider) switch (_collider)
{ {
case var _ when Ignores.Contains(_collider.GetInstanceID()):
case var _ when ignoreColliders.Contains(_collider): case var _ when ignoreColliders.Contains(_collider):
return false; 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; return false;
default: default:
return true; return true;
@ -75,23 +91,21 @@ namespace BITKit.Sensors
private bool CheckSight(ref Collider _collider) private bool CheckSight(ref Collider _collider)
{ {
if (!requireSight) return false; var bounds = _collider.bounds;
var position = _collider.bounds.center; var position = bounds.center;
//是检测bounds的顶部 position.y += bounds.size.y * detectedHeightWeight /2;
position.y += _collider.bounds.extents.y; var selfPosition = Transform.position;
var location = new Location(Transform);
var length = Physics.RaycastNonAlloc( var length = Physics.RaycastNonAlloc(
location.position, selfPosition,
position - location, position - selfPosition,
hits, hits,
Vector3.Distance(location, position), Vector3.Distance(selfPosition, position),
blockLayer requireSight.Value
); );
switch (length) switch (length)
{ {
case 0: case 0:
Debug.DrawLine(location, position, Color.green, 1); Debug.DrawLine(selfPosition, position, Color.green,_delta);
return true; return true;
case 1: case 1:
return hits[0].collider == _collider; return hits[0].collider == _collider;
@ -107,7 +121,8 @@ namespace BITKit.Sensors
var result = ignoreColliders.Contains(x.collider) is false && x.collider != collider1; var result = ignoreColliders.Contains(x.collider) is false && x.collider != collider1;
if (result) 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; return result;
} }

View File

@ -2,7 +2,9 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine; using UnityEngine;
namespace BITKit.Sensors namespace BITKit.Sensors
{ {
@ -11,8 +13,11 @@ namespace BITKit.Sensors
[Header(Constant.Header.Settings)] [Header(Constant.Header.Settings)]
[SerializeField] private float radius = 0.16f; [SerializeField] private float radius = 0.16f;
public float distance; 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 RaycastHit[] raycasts = new RaycastHit[16];
private readonly Queue<(Vector3,Vector3)> _drawGizmosQueue = new();
private readonly CacheList<Transform> detected = new();
public override UniTask Execute(float delta) public override UniTask Execute(float delta)
{ {
var _transform = transform; var _transform = transform;
@ -28,25 +33,43 @@ namespace BITKit.Sensors
} }
else else
{ {
var ray = new Ray(_transform.position,_transform.forward); var ray = new Ray(_transform.position, _transform.forward);
size = Physics.RaycastNonAlloc(ray, raycasts, distance, detectLayer); size = Physics.RaycastNonAlloc(ray, raycasts, distance, detectLayer);
} }
//var reportBuilder = new StringBuilder();
detected = raycasts
.Take(size) detected.Clear();
.Select(x => x.collider) foreach (var hit in raycasts
.Where(IsValid) .Take(size)
.Select(x=>x.transform) .Where(IsValid)
.ToArray(); .OrderBy(ByDistance))
{
detected.Add(hit.transform);
}
//Debug.Log(reportBuilder);
return UniTask.CompletedTask; 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 bool IsValid(Collider _collider) => ignoreColliders.Contains(_collider) is false;
public override float GetDistance() => distance; 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);
} }
} }
} }

View File

@ -16,8 +16,6 @@ namespace BITKit.Sensors
[SerializeField,ReadOnly] private int _position; [SerializeField,ReadOnly] private int _position;
private static int[] _keys;
public static void Register(int id,ISensor sensor) public static void Register(int id,ISensor sensor)
{ {
Sensors.Add(id,sensor); Sensors.Add(id,sensor);
@ -33,7 +31,6 @@ namespace BITKit.Sensors
IsDirty = true; IsDirty = true;
} }
[SerializeField] private MonoBehaviour[] sensors;
[SerializeReference,SubclassSelector] private ITicker ticker; [SerializeReference,SubclassSelector] private ITicker ticker;
private bool _isBusy; private bool _isBusy;
@ -56,9 +53,7 @@ namespace BITKit.Sensors
if(IsDirty) if(IsDirty)
{ {
_position = 0; _position = 0;
_keys = Sensors.Where(IsEnabled).Select(x=>x.Key).ToArray();
IsDirty = false; IsDirty = false;
sensors = Sensors.Values.Where(IsEnabled).OfType<MonoBehaviour>().ToArray();
} }
if (Sensors.Count is 0) if (Sensors.Count is 0)
@ -68,26 +63,22 @@ namespace BITKit.Sensors
} }
var current = Sensors.ElementAt(_position++).Value; var current = Sensors.ElementAt(_position++).Value;
var currentUpdateTime = LastDetectedTime.GetOrAdd(current.Id,Time.time); if (current.AutoUpdate)
{
var currentUpdateTime = LastDetectedTime.GetOrAdd(current.Id,Time.time);
await current.Execute(Time.time-currentUpdateTime); await current.Execute(Time.time-currentUpdateTime);
float UpdateValueFactory(int key, float old) => Time.time;
LastDetectedTime.AddOrUpdate(current.Id,Time.time,UpdateValueFactory); LastDetectedTime.AddOrUpdate(current.Id,Time.time,UpdateValueFactory);
if (destroyCancellationToken.IsCancellationRequested) { if (destroyCancellationToken.IsCancellationRequested) {
_isBusy = false; _isBusy = false;
return; return;
}
} }
_position %= Sensors.Count; _position %= Sensors.Count;
_isBusy = false; _isBusy = false;
} return;
private bool IsEnabled(ISensor sensor) float UpdateValueFactory(int key, float old) => Time.time;
{
return sensor.AutoUpdate;
}
private bool IsEnabled(KeyValuePair<int,ISensor> pair)
{
return pair.Value.AutoUpdate;
} }
} }

View File

@ -30,6 +30,7 @@ namespace BITKit.Sensors
[SerializeField] private AudioSensor audioSensor; [SerializeField] private AudioSensor audioSensor;
public int Id { get; set; } public int Id { get; set; }
private readonly CacheList<Transform> _detected=new(); private readonly CacheList<Transform> _detected=new();
public HashSet<int> Ignores { get; } = new();
private void OnEnable() private void OnEnable()
{ {
Id = GetInstanceID(); Id = GetInstanceID();

View File

@ -28,6 +28,7 @@ namespace BITKit.Sensors
[Header(Constant.Header.InternalVariables)] [Header(Constant.Header.InternalVariables)]
// ReSharper disable once FieldCanBeMadeReadOnly.Local // ReSharper disable once FieldCanBeMadeReadOnly.Local
private List<Collider> detected = new(); private List<Collider> detected = new();
public HashSet<int> Ignores { get; } = new();
private readonly Queue<Collider> triggerEnterQueue = new(); private readonly Queue<Collider> triggerEnterQueue = new();
private readonly Queue<Collider> triggerExitQueue = new(); private readonly Queue<Collider> triggerExitQueue = new();
@ -171,7 +172,7 @@ namespace BITKit.Sensors
if (!agent || detectedContainer is null) return; if (!agent || detectedContainer is null) return;
if (BITAppForUnity.IsPlaying is false) return; if (BITAppForUnity.IsPlaying is false) return;
detectedContainer.Clear(); detectedContainer.Clear();
foreach (var x in agent.detected) foreach (var x in agent.Get())
{ {
ObjectField objectField = new() ObjectField objectField = new()
{ {

View File

@ -8,7 +8,8 @@
"GUID:49b49c76ee64f6b41bf28ef951cb0e50", "GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:d8b63aba1907145bea998dd612889d6b", "GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:6de01b04fa4e14662b03fa46366da151", "GUID:6de01b04fa4e14662b03fa46366da151",
"GUID:f19bbd83e3c264a5680926bf75d7e494" "GUID:f19bbd83e3c264a5680926bf75d7e494",
"GUID:1c2aa13aa706ffc49a1a0044cad55436"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@ -1,99 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using SkiaSharp;
using UnityEngine;
namespace BITKit.UX
{
public class SKPaintComponent : MonoBehaviour
{
[SerializeField] private Texture2D texture;
[SerializeField] private float[] data;
[BIT]
private void Draw()
{
var info = new SKImageInfo(
width: 384,
height: 128,
colorType: SKColorType.Rgba8888,
alphaType: SKAlphaType.Premul
);
using var surface = SKSurface.Create(info);
using var canvas = surface.Canvas;
//canvas.Clear(new Color32(31,31,31,255).ToSKColor());
using var linePaint = new SKPaint();
linePaint.Color = new SKColor(255, 0, 0, 255);
linePaint.StrokeWidth = 8;
linePaint.IsAntialias = true;
linePaint.Style = SKPaintStyle.Stroke;
using var helpLinePaint = new SKPaint();
helpLinePaint.Color = new SKColor(200, 200, 200, 200);
helpLinePaint.StrokeWidth = 4;
helpLinePaint.Style = SKPaintStyle.Stroke;
using var textPaint = new SKPaint();
textPaint.TextAlign = SKTextAlign.Center;
textPaint.TextSize = 14;
textPaint.ColorF = new SKColor(0, 255, 0, 255);
using var filePaint = new SKPaint();
filePaint.Color = new SKColor(200, 200, 200, 200);
filePaint.Style=SKPaintStyle.Fill;
var min = data.Min();
var max = data.Max();
DoubleBuffer<SKPoint> buffer = new();
var path = new SKPath { FillType = SKPathFillType.EvenOdd };
path.MoveTo(0,0);
path.LineTo(0,0);
for (var i = 0; i < data.Length; i++)
{
var value = data[i];
var posX = (float)info.Width / (data.Length - 1) * (i);
var d = max - min;
var p = (value - min) / d;
var poxY = info.Height * p;
var currentPoint = new SKPoint(posX, poxY);
if (buffer.TryGetRelease(out var previousPoint))
{
canvas.DrawLine(previousPoint, currentPoint, linePaint);
}
canvas.DrawText(
value.ToString()
, currentPoint
, new SKFont(
SKTypeface.FromFile(@"D:\Iris\Documents\GitHub\iFactory-YL106.Unity\Assets\BITKit\Unity\Art\Fonts\TTF\Roboto\Roboto-Regular.ttf")
), textPaint);
canvas.DrawLine(posX, 0, posX, poxY, helpLinePaint);
path.LineTo(posX,poxY);
buffer.Release(currentPoint);
}
path.LineTo(info.Width,0);
path.Close();
//canvas.DrawPath(path,filePaint);
texture = info.ToTexture2D(surface);
}
}
}

View File

@ -1,5 +1,5 @@
{ {
"name": "BITKit.UX.Chart.Tests", "name": "BITKit.UX.Painter.Runtime",
"rootNamespace": "", "rootNamespace": "",
"references": [ "references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4", "GUID:14fe60d984bf9f84eac55c6ea033a8f4",
@ -9,7 +9,7 @@
"GUID:d8b63aba1907145bea998dd612889d6b", "GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:6de01b04fa4e14662b03fa46366da151", "GUID:6de01b04fa4e14662b03fa46366da151",
"GUID:f19bbd83e3c264a5680926bf75d7e494", "GUID:f19bbd83e3c264a5680926bf75d7e494",
"GUID:994a3fb33a5627740b0712e7c483cc1f" "GUID:1c2aa13aa706ffc49a1a0044cad55436"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@ -0,0 +1,104 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets.Kcp;
using SkiaSharp;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.UX
{
public class SkiaPainter : VisualElement
{
public new class UxmlFactory : UxmlFactory<SkiaPainter, UxmlTraits> { }
public SkiaPainter()
{
RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
RegisterCallback<MouseDownEvent>(OnMouseDown);
RegisterCallback<MouseUpEvent>(OnMouseUp);
RegisterCallback<MouseMoveEvent>(OnMouseMove);
}
private bool _isPainting;
private readonly List<Vector2> _points = new();
private SKImageInfo _info;
private SKCanvas _canvas;
private SKSurface _surface;
private Rect _rect;
private readonly SKPaint _linePaint = new()
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Red,
StrokeWidth = 5
};
public void ClearCanvas()
{
_points.Clear();
Rebuild();
}
private void OnMouseMove(MouseMoveEvent evt)
{
if (_isPainting is false) return;
var pos = evt.localMousePosition;
pos.y = layout.height - pos.y;
if (_rect.Contains(pos) is false)
{
var last = _points.LastOrDefault();
if (last == default) return;
_points.Add(default);
return;
}
_points.Add(pos);
Rebuild();
}
private void OnMouseUp(MouseUpEvent evt)
{
_isPainting = false;
var last = _points.LastOrDefault();
if (last != default)
_points.Add(default);
}
private void OnMouseDown(MouseDownEvent evt)
{
_isPainting = true;
}
private void OnGeometryChanged(GeometryChangedEvent evt)
{
if(float.IsNaN(layout.width) || float.IsNaN(layout.height))
return;
_linePaint.Color = resolvedStyle.color.ToSKColor();
_surface?.Dispose();
_info = new SKImageInfo((int)layout.width, (int)layout.height);
_surface = SKSurface.Create(_info);
_canvas = _surface.Canvas;
_rect = new Rect(0, 0, layout.width, layout.height);
Rebuild();
}
private void Rebuild()
{
if (_canvas is null) return;
_canvas.Clear();
DoubleBuffer<Vector2> buffer = new();
foreach (var pos in _points)
{
if (pos == default)
{
buffer.Clear();
}
else
{
if (buffer.TryGetRelease(out var previousPoint))
{
_canvas.DrawLine(previousPoint.x, previousPoint.y, pos.x, pos.y, _linePaint);
}
buffer.Release(pos);
}
}
var texture = _info.ToTexture2D(_surface);
style.backgroundImage = texture;
}
public string Base64 => _surface?.GetBase64();
}
}

View File

@ -4,17 +4,12 @@ using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.IO;
using System.Runtime.CompilerServices;
using UnityEngine.Networking;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text; using System.Text;
using System.IO.Compression;
using System.Data;
using UnityEngine.UIElements; using UnityEngine.UIElements;
namespace BITKit namespace BITKit
{ {
@ -402,18 +397,6 @@ namespace BITKit
text = text.Remove(0, text.Split('\n')[0].Length + 1); text = text.Remove(0, text.Split('\n')[0].Length + 1);
return text; return text;
} }
public static TaskAwaiter GetAwaiter(this AsyncOperation asyncOp)
{
var tcs = new TaskCompletionSource<object>();
asyncOp.completed += obj => { tcs.SetResult(null); };
return ((Task)tcs.Task).GetAwaiter();
}
public static TaskAwaiter GetAwaiter(this System.Action action)
{
var tcs = new TaskCompletionSource<object>();
action += () => { tcs.SetResult(null); };
return ((Task)tcs.Task).GetAwaiter();
}
public static float GetDifference(this IEnumerable<float> self) public static float GetDifference(this IEnumerable<float> self)
{ {
return self.Max() - self.Min(); return self.Max() - self.Min();
@ -665,13 +648,32 @@ namespace BITKit
public static Vector2 GetScreenPosition(this VisualElement self, Vector3 worldPosition) public static Vector2 GetScreenPosition(this VisualElement self, Vector3 worldPosition)
{ {
var pos = RuntimePanelUtils try
.CameraTransformWorldToPanel(self.panel, worldPosition, Camera.main); {
var panel = self.panel;
if (panel is null)
{
panel = self.parent.panel;
}
pos.x -= self.layout.width / 2; if (panel is null)
pos.y -= self.layout.height / 2; {
panel = self.parent.parent.panel;
}
return pos; var pos = RuntimePanelUtils
.CameraTransformWorldToPanel(panel, worldPosition, Camera.main);
pos.x -= self.layout.width / 2;
pos.y -= self.layout.height / 2;
return pos;
}
catch (Exception e)
{
Debug.LogException(e);
}
return default;
} }
public static Vector2 GetPosition(this VisualElement self) public static Vector2 GetPosition(this VisualElement self)

View File

@ -16,7 +16,7 @@ namespace BITKit.OpenWorld
base.OnLodChanged(oldLod, newLod); base.OnLodChanged(oldLod, newLod);
OnLodChangedEvent?.Invoke(oldLod,newLod); OnLodChangedEvent?.Invoke(oldLod,newLod);
} }
#if UNITY_EDITOR
[BIT] [BIT]
private void CalculateBounds() private void CalculateBounds()
{ {
@ -41,6 +41,7 @@ namespace BITKit.OpenWorld
offset = bounds.center - transform.position; offset = bounds.center - transform.position;
EditorUtility.SetDirty(this); EditorUtility.SetDirty(this);
} }
#endif
} }
} }

View File

@ -3,7 +3,9 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Quadtree; using Quadtree;
#if UNITY_EDITOR
using UnityEditor.SceneManagement; using UnityEditor.SceneManagement;
#endif
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using YooAsset; using YooAsset;
@ -16,9 +18,7 @@ namespace BITKit.OpenWorld
[SerializeField] private Vector3 size; [SerializeField] private Vector3 size;
[SerializeField] private Vector3 position; [SerializeField] private Vector3 position;
[SerializeField, ReadOnly] private int lod = -1; [SerializeField, ReadOnly] private int lod = -1;
private SceneHandle _sceneHandle; private SceneHandle _sceneHandle;
[BIT] [BIT]
public async void Load() public async void Load()
{ {

View File

@ -314,3 +314,6 @@ Label {
.armorPlate-container:hover { .armorPlate-container:hover {
background-color: rgba(255, 255, 255, 0.78); background-color: rgba(255, 255, 255, 0.78);
} }
.flex-center {
}

View File

@ -0,0 +1,24 @@
{
"name": "BITKit.Extensions.SkiaSharp",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:6ef4ed8ff60a7aa4bb60a8030e6f4008",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:6de01b04fa4e14662b03fa46366da151",
"GUID:f19bbd83e3c264a5680926bf75d7e494"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [
"_SkiaSharp"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text;
using SkiaSharp; using SkiaSharp;
using UnityEngine; using UnityEngine;
@ -31,5 +34,31 @@ namespace BITKit.UX
{ {
return new SKColor(color.r, color.g, color.b, color.a); return new SKColor(color.r, color.g, color.b, color.a);
} }
public static string GetBase64(this SKSurface self)
{
try
{
using var image = self.Snapshot();
using var data = image.Encode(SKEncodedImageFormat.Png, 50);
//using var stream = File.OpenWrite(exportPath.Value);
var ms = new MemoryStream();
// save the data to a stream
data.SaveTo(ms);
var bytes = ms.ToArray();
var base64 = Convert.ToBase64String(bytes);
return "data:image/jpeg;base64," + base64;
}
catch (Exception e)
{
StringBuilder exceptionBuilder = new();
exceptionBuilder.AppendLine($"Surface:{self is not null}");
BIT4Log.LogException( new InGameException(exceptionBuilder.ToString(),e));
throw;
}
}
} }
} }