This commit is contained in:
CortexCore
2024-04-16 04:06:46 +08:00
parent 37e7fcea51
commit c798b224be
67 changed files with 1305 additions and 425 deletions

View File

@@ -63,6 +63,11 @@ namespace BITKit
/// </summary> /// </summary>
ItemQuality Quality { get; } ItemQuality Quality { get; }
bool CopyItemsFrom(IBasicItem item); bool CopyItemsFrom(IBasicItem item);
/// <summary>
/// 价值
/// </summary>
/// <returns></returns>
int Value=>10;
} }
/// <summary> /// <summary>
/// 可配置化物品,通常用于配置 /// 可配置化物品,通常用于配置
@@ -84,6 +89,7 @@ namespace BITKit
public string AddressablePath { get; set; } public string AddressablePath { get; set; }
public string Description; public string Description;
public ItemQuality Quality; public ItemQuality Quality;
public int Value { get; set; }
/// <summary> /// <summary>
/// 本地属性 /// 本地属性
/// </summary> /// </summary>
@@ -122,6 +128,7 @@ namespace BITKit
public bool CopyItemsFrom(IBasicItem item) public bool CopyItemsFrom(IBasicItem item)
{ {
Value = item.Value;
Id=item.Id; Id=item.Id;
Name = item.Name; Name = item.Name;
AddressablePath = item.AddressablePath; AddressablePath = item.AddressablePath;

View File

@@ -75,6 +75,21 @@ namespace BITKit
/// 已重构Items的回调 /// 已重构Items的回调
/// </summary> /// </summary>
event Action<IBasicItemContainer> OnRebuild; event Action<IBasicItemContainer> OnRebuild;
/// <summary>
/// 是否已完成物品交换,例如false就是开始交换物品true就是已完成交换物品,可以处理物品了
/// </summary>
event Action<bool> OnRelease;
/// <summary>
/// 添加挂起句柄
/// </summary>
/// <param name="id"></param>
void AddHandle(int id);
/// <summary>
/// 移除挂起句柄
/// </summary>
/// <param name="id"></param>
void RemoveHandle(int id);
} }
} }

View File

@@ -7,6 +7,17 @@ namespace BITKit
{ {
public static class MathE public static class MathE
{ {
public static int GetHash<T>(IEnumerable<T> self)
{
var hash = 0;
foreach (var x in self)
{
if (x is not null)
hash += x.GetHashCode();
}
return hash;
}
public static bool IndexInRange<T>(this IEnumerable<T> self, int index) public static bool IndexInRange<T>(this IEnumerable<T> self, int index)
{ {
return index >= 0 && index < self.Count(); return index >= 0 && index < self.Count();

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e517c312e735e1042b911efc79deb1f6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "BITKit.Probability",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2f7d7f857f30f484ea163931f3bc4e0a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using System.Collections;
using System.Collections.Generic;
namespace BITKit.Probability
{
/// <summary>
/// 概率属性
/// </summary>
public interface IProbabilityProperty
{
}
/// <summary>
/// 概率服务
/// </summary>
public interface IProbabilityService
{
/// <summary>
/// 根据概率属性获取值
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
object GetValueObject(params IProbabilityProperty[] properties);
/// <summary>
/// 根据概率属性获取值
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
object[] GetValuesObject(params IProbabilityProperty[] properties);
}
/// <summary>
/// 泛型概率服务
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IProbabilityService<T>:IProbabilityService
{
/// <summary>
/// 根据概率属性获取值
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
T GetValue(params IProbabilityProperty[] properties);
/// <summary>
/// 根据概率属性获取值
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
T[] GetValues(params IProbabilityProperty[] properties);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: d6c28a6107497be44bfecb5e31b960c5 guid: 8e4f1cbf25a4f494d89fc3831dbc82ab
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -70,87 +70,84 @@ namespace BITKit
{ {
foreach (var x in factory) foreach (var x in factory)
{ {
AddPropertyInternal(x); properties.Add(x);
} }
} }
Dictionary<string, object> properties=new(); private readonly List<object> properties=new();
public T GetProperty<T>() public T GetProperty<T>()
{ {
return (T)properties[typeof(T).FullName]; return properties.OfType<T>().First();
} }
public void SetProperty<T>(T value) public void SetProperty<T>(T value)
{ {
properties.Insert(typeof(T).FullName, value); for (var i = 0; i < properties.Count; i++)
{
if (properties[i] is T)
properties[i] = value;
}
} }
public bool Contains<T>() public bool Contains<T>()
{ {
return properties.ContainsKey(typeof(T).FullName); return properties.OfType<T>().FirstOrDefault() is not null;
} }
public T GetOrCreateProperty<T>() public T GetOrCreateProperty<T>()
{ {
return GetOrAddProperty(Activator.CreateInstance<T>); return GetOrAddProperty(Activator.CreateInstance<T>);
} }
public T GetOrAddProperty<T>(Func<T> addFactory) public T GetOrAddProperty<T>(Func<T> addFactory)
{ {
if (properties.TryGetValue(typeof(T).FullName, out var x)) foreach (var obj in properties)
{ {
return (T)x; if (obj is T t) return t;
}
else
{
AddPropertyInternal(x =addFactory.Invoke());
//properties.Add(typeof(T).FullName, x = addFactory.Invoke());
return (T)x;
} }
T x;
properties.Add(x = addFactory.Invoke());
return x;
} }
public bool TryGetProperty<T>(out T value) public bool TryGetProperty<T>(out T value)
{ {
if (properties.TryGetValue(typeof(T).FullName, out var x)) try
{ {
value = (T)x; value = properties.OfType<T>().First();
return true; return true;
} }
else catch (InvalidOperationException)
{ {
value=default(T); value = default;
return false; return false;
} }
} }
public bool TryRemoveProperty<T>() public bool TryRemoveProperty<T>()
{ {
foreach (var pair in properties.Where(x=>x.Value is T)) var removed=false;
foreach (var value in properties.OfType<T>().ToArray())
{ {
properties.Remove(pair.Key); properties.Remove(value);
return true; removed = true;
} }
// if(properties.TryGetValue(typeof(T).FullName, out var x)) // if(properties.TryGetValue(typeof(T).FullName, out var x))
// { // {
// properties.Remove(typeof(T).Name); // properties.Remove(typeof(T).Name);
// return true; // return true;
// } // }
return false; return removed;
} }
public bool TrySetProperty<T>(T value) public bool TrySetProperty<T>(T value)
{ {
bool result = false; var current = properties.OfType<T>().FirstOrDefault();
foreach (var pair in properties.Where(x=>x.Value is T).ToArray()) if (current is not null)
{ {
properties[pair.Key] = value; properties.Remove(current);
result = true; return true;
} }
return result; properties.Add(value);
// if (properties.TryGetValue(typeof(T).FullName, out var x)) return false;
// {
// properties[typeof(T).FullName] = value;
// return true;
// }
// else
// {
// return false;
// }
} }
public object[] GetProperties()=>properties.Values.Distinct().ToArray();
public object[] GetProperties() => properties.ToArray();
public void Read(BinaryReader r) public void Read(BinaryReader r)
{ {
@@ -174,23 +171,8 @@ namespace BITKit
public bool CopyPropertiesFrom(IPropertable propertable) public bool CopyPropertiesFrom(IPropertable propertable)
{ {
ClearProperties(); ClearProperties();
foreach (var x in propertable.GetProperties()) properties.AddRange( propertable.GetProperties());;
{
AddPropertyInternal(x);
}
return true; return true;
} }
private void AddPropertyInternal(object value)
{
if (value is ICloneable cloneable)
{
value = cloneable.Clone();
}
properties.Set(value.GetType().FullName, value);
foreach (var att in value.GetType().GetCustomAttributes<CustomTypeAttribute>())
{
properties.Set(att.Type!.FullName, value);
}
}
} }
} }

View File

@@ -2,6 +2,7 @@ namespace BITKit
{ {
public interface ITag public interface ITag
{ {
int Hash { get; }
string[] GetTags(); string[] GetTags();
} }
} }

View File

@@ -145,6 +145,13 @@ namespace BITKit
{ {
value = _directDirection.Get(key); value = _directDirection.Get(key);
} }
public T GetOrAddDirect<T>(int key,Func<T> factory)
{
if (_directDirection.TryGetValue(key, out var v)) return v is T t ? t : default;
var value = factory.Invoke();
_directDirection.Add(key, value);
return value;
}
public void GetDirect<T>(int key,out T value) public void GetDirect<T>(int key,out T value)
{ {
try try

View File

@@ -26,6 +26,7 @@ RenderTexture:
m_UseDynamicScale: 0 m_UseDynamicScale: 0
m_BindMS: 0 m_BindMS: 0
m_EnableCompatibleFormat: 1 m_EnableCompatibleFormat: 1
m_EnableRandomWrite: 0
m_TextureSettings: m_TextureSettings:
serializedVersion: 2 serializedVersion: 2
m_FilterMode: 1 m_FilterMode: 1

View File

@@ -1,28 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BITKit.Sensors;
namespace BITKit.Entities
{
public class EntityAudioObject : EntityBehavior, IAudioObject
{
float volume;
public override void OnStart()
{
UnityEntity.AddListener<AudioSO>(OnAuioSO);
}
public override void OnFixedUpdate(float deltaTime)
{
volume = Mathf.Lerp(volume, 0, deltaTime);
}
public float GetVolume()
{
return volume;
}
void OnAuioSO(AudioSO so)
{
if (so.distance > volume)
volume = so.distance;
}
}
}

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using BITKit.Mod; using BITKit.Mod;
using UnityEngine; using UnityEngine;
@@ -15,6 +16,7 @@ namespace BITKit.Animations
public class ScriptableMotionMatchingService : MonoBehaviour,IMotionMatchingService public class ScriptableMotionMatchingService : MonoBehaviour,IMotionMatchingService
{ {
internal static ScriptableMotionMatchingService Singleton { get; private set; } internal static ScriptableMotionMatchingService Singleton { get; private set; }
internal static readonly ConcurrentDictionary<int, IMotionMatchingObject> Cache = new();
private ObjectMatcher<string,IMotionMatchingObject> _objects; private ObjectMatcher<string,IMotionMatchingObject> _objects;
@@ -40,16 +42,23 @@ namespace BITKit.Animations
public bool TryMatch(out IMotionMatchingObject value, string[] key) public bool TryMatch(out IMotionMatchingObject value, string[] key)
{ {
if (_objects.TryMatch(out value, key)) value = Cache.GetOrAdd(MathE.GetHash(key),Add);
return value is not null;
IMotionMatchingObject Add(int hash)
{ {
return true; if (_objects.TryMatch(out IMotionMatchingObject x, key) is false)
{
BIT4Log.Log<ScriptableMotionMatchingService>($"找不到对应的MotionMatchingObject:{string.Join(",", key)}");
return null;
}
return x;
} }
BIT4Log.Log<ScriptableMotionMatchingService>($"找不到对应的MotionMatchingObject:{string.Join(",", key)}");
return false;
} }
private void Rebuild() private void Rebuild()
{ {
Cache.Clear();
var list = new List<ScriptableMotionMatchingObject>(); var list = new List<ScriptableMotionMatchingObject>();
var tags = new []{nameof(IMotionMatchingObject)}; var tags = new []{nameof(IMotionMatchingObject)};
foreach (var x in YooAssets.GetAssetInfos(tags)) foreach (var x in YooAssets.GetAssetInfos(tags))

View File

@@ -25,6 +25,7 @@ namespace BITKit
if (UnityEngine.Physics.Raycast(root.position, root.forward, out var raycastHit, distance, layerMask)) if (UnityEngine.Physics.Raycast(root.position, root.forward, out var raycastHit, distance, layerMask))
{ {
var collider = raycastHit.collider; var collider = raycastHit.collider;
if (collider.isTrigger) return false;
switch (collider) switch (collider)
{ {
case MeshCollider meshCollider: case MeshCollider meshCollider:

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
using BITKit.Core.Tuple; using BITKit.Core.Tuple;
using UnityEngine; using UnityEngine;
namespace BITKit.Physics namespace BITKit
{ {
[Serializable] [Serializable]
public class JointConfigure public class JointConfigure

View File

@@ -1,10 +1,9 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using BITKit.Events; using BITKit.Events;
using UnityEditor;
using UnityEngine; using UnityEngine;
namespace BITKit.Physics namespace BITKit
{ {
public class Prop_Physics : MonoBehaviour public class Prop_Physics : MonoBehaviour
{ {

View File

@@ -41,6 +41,15 @@ namespace BITKit.SceneManagement
/// 场景加载完成的回调 /// 场景加载完成的回调
/// </summary> /// </summary>
event Action<string> OnSceneLoaded; event Action<string> OnSceneLoaded;
/// <summary>
/// 注册加载任务
/// </summary>
void RegisterLoadTaskAsync(Func<UniTask> task);
/// <summary>
/// 注销加载任务
/// </summary>
/// <param name="task"></param>
void UnRegisterLoadTaskAsync(Func<UniTask> task);
/// <summary> /// <summary>
/// 当开始卸载场景时 /// 当开始卸载场景时
/// </summary> /// </summary>
@@ -89,6 +98,16 @@ namespace BITKit.SceneManagement
remove => _sceneServiceImplementation.OnSceneLoaded -= value; remove => _sceneServiceImplementation.OnSceneLoaded -= value;
} }
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.RegisterLoadTaskAsync(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.UnRegisterLoadTaskAsync(task);
}
public event Action<string> OnUnloadScene public event Action<string> OnUnloadScene
{ {
add => _sceneServiceImplementation1.OnUnloadScene += value; add => _sceneServiceImplementation1.OnUnloadScene += value;

View File

@@ -58,6 +58,16 @@ namespace BITKit.SceneManagement
remove => SceneService.OnSceneLoaded -= value; remove => SceneService.OnSceneLoaded -= value;
} }
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.RegisterLoadTaskAsync(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.UnRegisterLoadTaskAsync(task);
}
public event Action<string> OnUnloadScene public event Action<string> OnUnloadScene
{ {
add => _sceneServiceImplementation.OnUnloadScene += value; add => _sceneServiceImplementation.OnUnloadScene += value;
@@ -198,9 +208,15 @@ namespace BITKit.SceneManagement
OnSceneLoadProgress?.Invoke(sceneName, progress); OnSceneLoadProgress?.Invoke(sceneName, progress);
} }
LoadedObjects.Add(sceneName, handle.SceneObject); LoadedObjects.Add(sceneName, handle.SceneObject);
OnSceneLoadProgress?.Invoke(sceneName, 1); OnSceneLoadProgress?.Invoke(sceneName, 1);
await Task.Delay(384, cancellationToken); await Task.Delay(384, cancellationToken);
foreach (var x in _onSceneLoadedAsyncList.ToArray())
{
await x.Invoke();
if (destroyCancellationToken.IsCancellationRequested) return;
}
OnSceneLoaded?.Invoke(sceneName); OnSceneLoaded?.Invoke(sceneName);
stopwatchWatcher.Stop(); stopwatchWatcher.Stop();
// if (activateOnLoad is false) // if (activateOnLoad is false)
@@ -252,6 +268,16 @@ namespace BITKit.SceneManagement
remove => OnSceneLoaded -= value; remove => OnSceneLoaded -= value;
} }
private readonly List<Func<UniTask>> _onSceneLoadedAsyncList=new();
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_onSceneLoadedAsyncList.Add(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_onSceneLoadedAsyncList.Remove(task);
}
public event Action<string> OnUnloadScene; public event Action<string> OnUnloadScene;
public event Action<string> OnSceneUnloaded; public event Action<string> OnSceneUnloaded;
} }

View File

@@ -1,49 +1,49 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Cysharp.Threading.Tasks; 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
{ {
public interface IAudioObject public interface IAudioObject
{ {
float GetVolume(); float GetVolume();
} }
public class AudioSensor : Sensor public class AudioSensor : MonoBehaviour,ISensor
{ {
[Header(Constant.Header.Settings)] [Header(Constant.Header.Settings)]
public float radius; [SerializeField] private bool autoUpdate;
[Header(Constant.Header.InternalVariables)] [SerializeField]private float radius;
IAudioObject currentAudioObject; private readonly CacheList<Transform> cache = new();
Collider currentCollider; private void OnEnable()
Collider[] colliders = new Collider[32];
public override IEnumerable<Transform> Get() => detected;
public override UniTask Execute()
{ {
var cacheList = ListPool<Transform>.Get(); Id = GetInstanceID();
for (int i = 0; i < Physics.OverlapSphereNonAlloc(transform.position, radius, colliders, detectLayer); i++) SensorQueue.Register(Id,this);
}
private void OnDisable()
{
SensorQueue.UnRegister(Id);
}
public UniTask Execute(float delta)
{
var position = transform.position;
cache.Clear();
foreach (var x in AudioSensorService.QuadtreeRoot.Find(new Bounds(position, Vector3.one * radius)))
{ {
currentCollider = colliders[i]; var distance = Vector3.Distance(position, x.Position);
if (IsValid(currentCollider)) if(distance>radius) continue;
{ cache.Add(x.Transform);
cacheList.Add(currentCollider.transform);
}
} }
detected = cacheList.ToArray();
ListPool<Transform>.Release(cacheList);
return UniTask.CompletedTask; return UniTask.CompletedTask;
} }
public override bool IsValid(Collider _collider) public int Id { get; set; }
{ public IEnumerable<Transform> Get() => cache.ValueArray;
if (ignoreColliders.Contains(_collider) is false) public bool IsValid(Collider _collider) => false;
if (Vector3.Distance(transform.position, _collider.transform.position) <= radius) public float GetDistance() => radius;
if (_collider.TryGetComponent<IAudioObject>(out currentAudioObject)) public bool AutoUpdate=>autoUpdate;
{
return currentAudioObject.GetVolume() >= 1;
}
return false;
}
public override float GetDistance() => radius;
} }
} }

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using kcp2k;
using Quadtree;
using Quadtree.Items;
using UnityEngine;
using UnityEngine.Pool;
namespace BITKit.Sensors
{
public class AudioSensorService : MonoBehaviour
{
public class AudioSensorData:IItem<AudioSensorData,Node<AudioSensorData>>
{
public int Id;
public Vector3 Position;
public float Radius;
public Transform Transform;
public Bounds Bounds;
public ITag Tag;
public Bounds GetBounds() => Bounds;
public Node<AudioSensorData> ParentNode { get; set; }
public void QuadTree_Root_Initialized(IQuadtreeRoot<AudioSensorData, Node<AudioSensorData>> root){}
}
internal static readonly QuadtreeRoot<AudioSensorData, Node<AudioSensorData>> QuadtreeRoot =
new(default, Vector3.one * 2048);
private static Pool<AudioSensorData> pool = new(()=>new(), x=>{}, 1000);
private static int count;
public static async void MakeNoise(Vector3 position,Transform transform)
{
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);
}
private static bool disposed;
[SerializeReference, SubclassSelector] private ITicker ticker;
private void Start()
{
disposed = false;
ticker.Add(OnTick);
destroyCancellationToken.Register(Dispose);
pool.Clear();
}
private void Dispose()
{
ticker.Remove(OnTick);
disposed = true;
QuadtreeRoot.Clear();
}
private void OnTick(float obj)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db1536b0b240b724f8741f900b2da455
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -9,7 +9,8 @@
"GUID:f51ebe6a0ceec4240a699833d6309b23", "GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:be17a8778dbfe454890ed8279279e153", "GUID:be17a8778dbfe454890ed8279279e153",
"GUID:14fe60d984bf9f84eac55c6ea033a8f4", "GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:9400d40641bab5b4a9702f65bf5c6eb5" "GUID:9400d40641bab5b4a9702f65bf5c6eb5",
"GUID:1193c2664d97cc049a6e4c486c6bce71"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@@ -17,6 +17,7 @@ namespace BITKit.Sensors
/// </summary> /// </summary>
public interface ISensor public interface ISensor
{ {
int Id { get; }
/// <summary> /// <summary>
/// 自动更新 /// 自动更新
/// </summary> /// </summary>
@@ -45,7 +46,7 @@ namespace BITKit.Sensors
/// 传感器执行检测 /// 传感器执行检测
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
UniTask Execute(); UniTask Execute(float delta);
} }
[Serializable] [Serializable]
@@ -53,6 +54,8 @@ namespace BITKit.Sensors
{ {
[SerializeField] private GameObject gameObject; [SerializeField] private GameObject gameObject;
private ISensor _sensorImplementation => gameObject.GetComponent<ISensor>(); private ISensor _sensorImplementation => gameObject.GetComponent<ISensor>();
public int Id => _sensorImplementation.Id;
public IEnumerable<Transform> Get() public IEnumerable<Transform> Get()
{ {
return _sensorImplementation.Get(); return _sensorImplementation.Get();
@@ -67,10 +70,9 @@ namespace BITKit.Sensors
{ {
return _sensorImplementation.GetDistance(); return _sensorImplementation.GetDistance();
} }
public UniTask Execute(float delta)
public UniTask Execute()
{ {
return _sensorImplementation.Execute(); return _sensorImplementation.Execute(delta);
} }
} }
[System.Serializable] [System.Serializable]
@@ -78,6 +80,8 @@ namespace BITKit.Sensors
{ {
[SerializeField] private MonoBehaviour monoBehaviour; [SerializeField] private MonoBehaviour monoBehaviour;
private ISensor _sensorImplementation=>monoBehaviour as ISensor; private ISensor _sensorImplementation=>monoBehaviour as ISensor;
public int Id => _sensorImplementation.Id;
public IEnumerable<Transform> Get() public IEnumerable<Transform> Get()
{ {
return _sensorImplementation.Get(); return _sensorImplementation.Get();
@@ -93,9 +97,9 @@ namespace BITKit.Sensors
return _sensorImplementation.GetDistance(); return _sensorImplementation.GetDistance();
} }
public UniTask Execute() public UniTask Execute(float delta)
{ {
return _sensorImplementation.Execute(); return _sensorImplementation.Execute(delta);
} }
} }
public abstract class Sensor : MonoBehaviour, ISensor public abstract class Sensor : MonoBehaviour, ISensor
@@ -106,16 +110,15 @@ namespace BITKit.Sensors
[Header(Constant.Header.Gameobjects)] [Header(Constant.Header.Gameobjects)]
public Collider[] ignoreColliders; public Collider[] ignoreColliders;
[Header(Constant.Header.InternalVariables)] [Header(Constant.Header.InternalVariables)]
[NonSerialized] [SerializeField,ReadOnly]
public Transform[] detected = Array.Empty<Transform>(); 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 UniTask Execute();
public abstract float GetDistance(); public abstract float GetDistance();
public virtual UniTask Execute(float delta)=>UniTask.CompletedTask;
public int Id { get; private set; }
bool ISensor.AutoUpdate => autoUpdate; bool ISensor.AutoUpdate => autoUpdate;
protected int Id;
protected Transform Transform; protected Transform Transform;
protected virtual void OnEnable() protected virtual void OnEnable()

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Sensors
{
public interface ISensorTarget
{
public int Id { get; }
Bounds Bounds { get; }
Transform Transform { get; }
void Detected(float weight,ISensor sensor,object sender);
event Action<float, ISensor, object> OnDetected;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6b2f04f438f7bd4c812fb6441a5ca4a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,7 +12,7 @@ namespace BITKit.Sensors
public override IEnumerable<Transform> Get()=>sensors.SelectMany(x => x.Get()); public override IEnumerable<Transform> Get()=>sensors.SelectMany(x => x.Get());
public override bool IsValid(Collider _collider) => sensors.Any(x => x.IsValid(_collider) is false) is false; public override bool IsValid(Collider _collider) => sensors.Any(x => x.IsValid(_collider) is false) is false;
public override float GetDistance() => sensors.Min(x => x.GetDistance()); public override float GetDistance() => sensors.Min(x => x.GetDistance());
public override UniTask Execute() => UniTask.WhenAll(sensors.Select(x => x.Execute())); public override UniTask Execute(float delta) => UniTask.WhenAll(sensors.Select(x => x.Execute(delta)));
} }
} }

View File

@@ -7,24 +7,25 @@ using Cysharp.Threading.Tasks;
using UnityEngine.Jobs; using UnityEngine.Jobs;
using UnityEngine.Pool; using UnityEngine.Pool;
using UnityEngine.Profiling; using UnityEngine.Profiling;
using Physics=UnityEngine.Physics;
namespace BITKit.Sensors namespace BITKit.Sensors
{ {
public class RangeSensor : Sensor public class RangeSensor : Sensor
{ {
[Header(Constant.Header.Settings)] [Header(Constant.Header.Settings)] public float radius;
public float radius;
public int fov; public int fov;
public bool requireSight; public bool requireSight;
[Header(Constant.Header.Settings)]
public LayerMask blockLayer;
[Header(Constant.Header.InternalVariables)]
private FrameUpdate frameUpdater;
private readonly Collider[] colliders = new Collider[32];
private RaycastHit[] hits;
private bool isExecuting; [Header(Constant.Header.Settings)] public LayerMask blockLayer;
[Header(Constant.Header.Debug)] [Header(Constant.Header.InternalVariables)]
private FrameUpdate frameUpdater;
private readonly Collider[] colliders = new Collider[32];
private RaycastHit[] hits = new RaycastHit[32];
private readonly HashSet<int> tempHashSet = new();
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;
@@ -33,12 +34,13 @@ namespace BITKit.Sensors
Profiler.EndSample(); Profiler.EndSample();
return _detectedBuffer; return _detectedBuffer;
} }
private readonly DoubleBuffer<IEnumerable<Transform>> _detectedDoubleBuffer=new();
private IEnumerable<Transform> _detectedBuffer;
private readonly DoubleBuffer<IEnumerable<Transform>> _detectedDoubleBuffer = new();
public override UniTask Execute() private IEnumerable<Transform> _detectedBuffer=Array.Empty<Transform>();
public override UniTask Execute(float delta)
{ {
tempHashSet.Clear();
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;
@@ -54,7 +56,7 @@ namespace BITKit.Sensors
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 fov > 0 && CheckFov(ref _collider) is false:
case var _ when requireSight && CheckSight(ref _collider) is false: case var _ when requireSight && CheckSight(ref _collider) is false:
return false; return false;
default: default:
return true; return true;
@@ -62,18 +64,21 @@ namespace BITKit.Sensors
} }
public override float GetDistance() => radius; public override float GetDistance() => radius;
private bool CheckFov(ref Collider _collider) private bool CheckFov(ref Collider _collider)
{ {
var _dir = _collider.transform.position - transform.position; var _dir = _collider.bounds.center - transform.position;
if (_dir.sqrMagnitude <= 0) return false; if (_dir.sqrMagnitude <= 0) return false;
var dir = Quaternion.LookRotation(_dir); var dir = Quaternion.LookRotation(_dir);
return Vector3.Dot(transform.forward, _dir) > 0 && fov > Quaternion.Angle(transform.rotation, dir); return Vector3.Dot(transform.forward, _dir) > 0 && fov > Quaternion.Angle(transform.rotation, dir);
} }
private bool CheckSight(ref Collider _collider) private bool CheckSight(ref Collider _collider)
{ {
if (!requireSight) return false; if (!requireSight) return false;
var transform1 = _collider.transform; var position = _collider.bounds.center;
var position = transform1.position; //是检测bounds的顶部
position.y += _collider.bounds.extents.y;
var location = new Location(Transform); var location = new Location(Transform);
var length = Physics.RaycastNonAlloc( var length = Physics.RaycastNonAlloc(
location.position, location.position,
@@ -82,23 +87,32 @@ namespace BITKit.Sensors
Vector3.Distance(location, position), Vector3.Distance(location, position),
blockLayer blockLayer
); );
switch (length) switch (length)
{ {
case 0: case 0:
Debug.DrawLine(location, position, Color.green, 1);
return true; return true;
case 1: case 1:
if (hits[0].collider == _collider) return hits[0].collider == _collider;
{ default:
return true; var collider1 = _collider;
} if (hits.Take(length).Any(Predicate))
break;
default:
if (hits.Take(length).Any(x => ignoreColliders.Contains(x.collider) is false))
{ {
return false; return false;
} }
break; break;
bool Predicate(RaycastHit x)
{
var result = ignoreColliders.Contains(x.collider) is false && x.collider != collider1;
if (result)
{
Debug.DrawLine(location, x.point, Color.red, 1);
}
return result;
}
} }
return true; return true;
} }
} }

View File

@@ -13,7 +13,7 @@ namespace BITKit.Sensors
public float distance; public float distance;
public override IEnumerable<Transform> Get() => detected; public override IEnumerable<Transform> Get() => detected;
private readonly RaycastHit[] raycasts = new RaycastHit[16]; private readonly RaycastHit[] raycasts = new RaycastHit[16];
public override UniTask Execute() public override UniTask Execute(float delta)
{ {
var _transform = transform; var _transform = transform;
var forward = _transform.forward; var forward = _transform.forward;
@@ -46,7 +46,7 @@ namespace BITKit.Sensors
{ {
if (autoUpdate) if (autoUpdate)
{ {
Execute().Forget(); Execute(Time.deltaTime).Forget();
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
@@ -10,6 +11,7 @@ namespace BITKit.Sensors
public class SensorQueue : MonoBehaviour public class SensorQueue : MonoBehaviour
{ {
internal static readonly Dictionary<int,ISensor> Sensors=new(); internal static readonly Dictionary<int,ISensor> Sensors=new();
internal static readonly ConcurrentDictionary<int, float> LastDetectedTime = new();
private static bool IsDirty; private static bool IsDirty;
[SerializeField,ReadOnly] private int _position; [SerializeField,ReadOnly] private int _position;
@@ -32,10 +34,25 @@ namespace BITKit.Sensors
} }
[SerializeField] private MonoBehaviour[] sensors; [SerializeField] private MonoBehaviour[] sensors;
[SerializeReference,SubclassSelector] private ITicker ticker;
private void Update()
private bool _isBusy;
private void Start()
{ {
ticker.Add(OnTick);
destroyCancellationToken.Register(Dispose);
}
private void Dispose()
{
ticker.Remove(OnTick);
}
private async void OnTick(float obj)
{
if (_isBusy) return;
if (SensorGlobalSettings.Enabled is false) return; if (SensorGlobalSettings.Enabled is false) return;
_isBusy = true;
if(IsDirty) if(IsDirty)
{ {
_position = 0; _position = 0;
@@ -44,11 +61,25 @@ namespace BITKit.Sensors
sensors = Sensors.Values.Where(IsEnabled).OfType<MonoBehaviour>().ToArray(); sensors = Sensors.Values.Where(IsEnabled).OfType<MonoBehaviour>().ToArray();
} }
if(Sensors.Count is 0) return; if (Sensors.Count is 0)
{
Sensors.ElementAt(_position++).Value.Execute().Forget(); _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;
}
_position %= Sensors.Count; _position %= Sensors.Count;
_isBusy = false;
} }
private bool IsEnabled(ISensor sensor) private bool IsEnabled(ISensor sensor)
{ {
@@ -60,4 +91,4 @@ namespace BITKit.Sensors
} }
} }
} }

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using BITKit.Sensors.States;
using BITKit.StateMachine;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor; using UnityEditor;
@@ -16,212 +18,38 @@ using UnityEngine.UIElements;
namespace BITKit.Sensors namespace BITKit.Sensors
{ {
public interface ISmartTargetProperty{}
public interface ISmartTargetState:IState{}
/// <summary> /// <summary>
/// 智能目标传感器,根据条件,智能选择目标 /// 智能目标传感器,根据条件,智能选择目标
/// </summary> /// </summary>
public class SmartTargetSensor :MonoBehaviour,ISensor,IAction public class SmartTargetSensor :StateBasedMonoBehaviour<ISmartTargetState>,ISensor
{ {
/// <summary> [SerializeField] private float radius;
/// 自动更新 [SerializeField] private RangeSensor rangeSensor;
/// </summary> [SerializeField] private AudioSensor audioSensor;
[Header(Constant.Header.Settings)] public int Id { get; set; }
[SerializeField] private bool autoUpdate; private readonly CacheList<Transform> _detected=new();
[SerializeField] private Optional<string[]> ignoreTags;
[SerializeField] private Optional<IntervalUpdate> optionalRetargetInterval;
/// <summary>
/// 主传感器
/// </summary>
[Header(nameof(Sensor))]
[SerializeField,SerializeReference,SubclassSelector] private ISensor sensor;
[Header(Constant.Header.Debug)]
[SerializeReference, ReadOnly] private int updateCount;
public IEnumerable<Transform> Get() =>CurrentTarget is not null ? new[] { CurrentTarget }:Enumerable.Empty<Transform>();
bool ISensor.AutoUpdate => autoUpdate;
internal StringBuilder reportBuilder;
internal DoubleBuffer<string> report=new();
public bool IsValid(Collider _collider)
{
if (!_collider) return false;
if (ignoreTags.Allow)
{
if (_collider.TryGetComponent<ITag>(out var iTags))
{
var tags = iTags.GetTags();
foreach (var x in ignoreTags.Value)
{
if (tags.Contains(x))
{
return false;
}
}
}
}
return true;
}
public float GetDistance() => sensor.GetDistance();
public Transform CurrentTarget { get; private set; }
private IEnumerable<Transform> detected = ArraySegment<Transform>.Empty;
private Vector3 _currentPosition;
private int Id;
private CancellationTokenSource timeoutCancellationTokenSource=new();
private void OnEnable() private void OnEnable()
{ {
SensorQueue.Register(Id=GetInstanceID(),this); Id = GetInstanceID();
SensorQueue.Register(Id,this);
}
private void Start()
{
TransitionState<Idle>();
} }
private void OnDisable() private void OnDisable()
{ {
SensorQueue.UnRegister(Id); SensorQueue.UnRegister(Id);
} }
public async UniTask Execute() public IEnumerable<Transform> Get() => _detected.ValueArray;
public bool IsValid(Collider _collider) => false;
public float GetDistance() => radius;
public UniTask Execute(float delta)
{ {
try CurrentState?.OnStateUpdate(delta);
{ return UniTask.CompletedTask;
_currentPosition = transform.position;
updateCount++;
timeoutCancellationTokenSource?.Cancel();
timeoutCancellationTokenSource = new CancellationTokenSource();
await sensor.Execute();
reportBuilder?.AppendLine($"-----BEGIN------{updateCount}");
Profiler.BeginSample("Release Detected Buffer");
var newDetected = sensor.Get();
if (reportBuilder is not null)
{
reportBuilder.AppendLine($"Detected:{newDetected.Count()}");
foreach (var x in newDetected)
{
reportBuilder.AppendLine(x.name);
}
reportBuilder.AppendLine();
}
Profiler.EndSample();
// ReSharper disable once PossibleMultipleEnumeration
if (newDetected.Contains(CurrentTarget))
{
if (optionalRetargetInterval.Allow && optionalRetargetInterval.Value.AllowUpdate)
{
reportBuilder?.AppendLine("Retarget Interval Catch,Search New Target");
}
else
{
reportBuilder?.AppendLine("Current Target Detected,Keep Target");
return;
}
}
Profiler.BeginSample("Filter Detected");
foreach (var x in newDetected.OrderBy(KeySelector))
{
if(IsValid(x.GetComponent<Collider>()) is false)continue;
CurrentTarget = x;
reportBuilder?.AppendLine($"New Target:{x.name},Is oder by distance");
break;
}
Profiler.EndSample();
reportBuilder?.AppendLine($"-----Complete------{updateCount}");
if(reportBuilder is not null)
{
report.Release(reportBuilder.ToString());
reportBuilder.Clear();
}
else
{
report.Clear();
}
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
private float KeySelector(Transform x)
{
var distance = Vector3.Distance(_currentPosition, x.position);
reportBuilder?.AppendLine($"Distance:{distance}@{x.name}");
return distance;
}
void IAction.Execute()
{
Execute().Forget();
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
try
{
if (!CurrentTarget) return;
Gizmos.DrawLine(transform.position,CurrentTarget.position);
}
catch (UnassignedReferenceException)
{
}
}
#endif
}
#if UNITY_EDITOR
[CustomEditor(typeof(SmartTargetSensor))]
public class SmartTargetSensorInspector:BITInspector<SmartTargetSensor>
{
private ObjectField _objectField;
private Label _reportLabel;
public override VisualElement CreateInspectorGUI()
{
FillDefaultInspector();
CreateSubTitle("Editor Debug Field");
_objectField = root.Create<ObjectField>();
_objectField.objectType = typeof(Transform);
_objectField.SetEnabled(false);
_reportLabel = root.Create<Label>();
_reportLabel.text = "Waiting agent report";
return root;
}
protected override void OnEnabled()
{
base.OnEnabled();
agent.reportBuilder = new();
}
protected override void OnDisabled()
{
base.OnDisabled();
agent.reportBuilder = null;
}
protected override void OnUpdate()
{
if (_objectField is not null)
{
_objectField.value = agent.CurrentTarget;
}
if (agent.reportBuilder is not null && _reportLabel is not null && agent.report.TryGetRelease(out var value))
{
_reportLabel.text = value;
}
} }
} }
#endif
} }

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections;
using System.Collections.Generic;
using BITKit.StateMachine;
using UnityEngine;
namespace BITKit.Sensors.States
{
public abstract class SmartTargetSensorStates : ISmartTargetState
{
public bool Enabled { get; set; }
public virtual void Initialize()
{
}
public virtual void OnStateEntry(IState old)
{
}
public virtual void OnStateUpdate(float deltaTime)
{
}
public virtual void OnStateExit(IState old, IState newState)
{
}
}
[Serializable]
public sealed class Idle : SmartTargetSensorStates
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d55e592432e5ca648b8b9eddee224932
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -61,6 +61,8 @@ namespace BITKit.Sensors
onLost.Invoke(_collider); onLost.Invoke(_collider);
} }
} }
public int Id => _id is 0 ? _id = GetInstanceID() : _id;
private int _id;
public IEnumerable<Transform> Get() public IEnumerable<Transform> Get()
{ {
@@ -89,13 +91,11 @@ namespace BITKit.Sensors
if (ignores.Contains(detectedObject)) return false; if (ignores.Contains(detectedObject)) return false;
return !detectedLayer.Allow || detectedLayer.Value.Includes(_collider.gameObject.layer); return !detectedLayer.Allow || detectedLayer.Value.Includes(_collider.gameObject.layer);
} }
public float GetDistance() public float GetDistance()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public UniTask Execute(float delta = 0)=>
public UniTask Execute()=>
UniTask.CompletedTask; UniTask.CompletedTask;
private void Update() private void Update()

View File

@@ -13,7 +13,8 @@ namespace BITKit
[SerializeField] private string[] tags; [SerializeField] private string[] tags;
[Tooltip("Disable when tags is not empty")] [Tooltip("Disable when tags is not empty")]
[SerializeReference,SubclassSelector] private IReference[] reference; [SerializeReference,SubclassSelector] private IReference[] reference;
public int Hash => _id is 0 ? _id = MathE.GetHash(GetTags()) : _id;
private int _id;
public string[] GetTags() => CacheTags ??= reference?.Length > 0 ? reference.Select(x => x.Value).ToArray() : tags; public string[] GetTags() => CacheTags ??= reference?.Length > 0 ? reference.Select(x => x.Value).ToArray() : tags;
private string[] CacheTags; private string[] CacheTags;
public void SetTags(IReference[] newReference) public void SetTags(IReference[] newReference)

View File

@@ -55,7 +55,7 @@ namespace BITKit
{ {
await UniTask.SwitchToMainThread(); await UniTask.SwitchToMainThread();
#if UNITY_EDITOR #if UNITY_EDITOR
if (EditorApplication.isPlaying is false) if (EditorApplication.isPlaying is false || EditorApplication.isPaused)
{ {
return; return;
} }

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 67732f32069d3bb4ca436ef8de5710e2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
{
"name": "BITKit.UX.Chart.Runtime",
"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

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 994a3fb33a5627740b0712e7c483cc1f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,202 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using SkiaSharp;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.UX
{
public class SkiaChart : VisualElement
{
public new class UxmlTraits : VisualElement.UxmlTraits
{
private readonly UxmlStringAttributeDescription m_JsonAttribute = new ()
{
name = "Json"
};
private readonly UxmlBoolAttributeDescription m_allowWarningsAttribute = new ()
{
name = "allowWarnings",
defaultValue = false
};
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var x = (SkiaChart)ve;
x.Json = m_JsonAttribute.GetValueFromBag(bag, cc);
x.AllowWarning = m_allowWarningsAttribute.GetValueFromBag(bag, cc);
}
}
public new class UxmlFactory : UxmlFactory<SkiaChart, UxmlTraits> { }
public SkiaChart()
{
RegisterCallback<GeometryChangedEvent>(x =>
{
if (visible)
{
Rebuild();
}
}); RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
style.flexDirection = FlexDirection.Row;
_dataContainer = this.Create<VisualElement>();
_chartContainer = this.Create<VisualElement>();
_chartContainer.style.flexGrow = 1;
_dataContainer.style.justifyContent = Justify.SpaceBetween;
_dataContainer.name = "Data";
_chartContainer.name = "Chart";
}
private void OnCustomStyleResolved(CustomStyleResolvedEvent evt)
{
if(evt.customStyle.TryGetValue(new CustomStyleProperty<Color>("--chart-secondary-color"), out var helpLineColor))
{
_secondaryColor = helpLineColor;
}
Rebuild();
}
public string Json
{
get => _json;
set
{
_json = value;
Rebuild();
}
}
private string _json;
public bool AllowWarning { get; set; }
public Color SecondaryColor
{
get => _secondaryColor;
set
{
_secondaryColor = value;
Rebuild();
}
}
private Color _secondaryColor;
private readonly VisualElement _dataContainer;
private readonly VisualElement _chartContainer;
private void Rebuild()
{
var data = Array.Empty<float>();
try
{
data = JsonConvert.DeserializeObject<float[]>(Json);
}
catch (Exception e)
{
if (AllowWarning)
Debug.LogException(e);
return;
}
if(float.IsNaN(layout.width) || float.IsNaN(layout.height))
return;
if (data is null or { Length: 0 }) return;
_dataContainer.Clear();
_chartContainer.Clear();
var max = data.Max();
var min = data.Min();
//假如min是x,max是y,将中间的差用data.Length划分
_dataContainer.style.flexDirection = FlexDirection.ColumnReverse;
for (var i = 0; i < data.Length; i++)
{
var label = _dataContainer.Create<Label>();
var value = (max - min) / (data.Length - 1) * i + min;
label.text = value.ToString();
}
if(_chartContainer.layout.width is float.NaN or <10 || _chartContainer.layout.height is float.NaN or <10)
return;
var info = new SKImageInfo(
width: (int)_chartContainer.layout.width,
height: (int)_chartContainer.layout.height,
colorType: SKColorType.Rgba8888,
alphaType: SKAlphaType.Premul
);
using var surface = SKSurface.Create(info);
using var canvas = surface.Canvas;
using var linePaint = new SKPaint();
linePaint.Color = resolvedStyle.color.ToSKColor();
linePaint.StrokeWidth = resolvedStyle.unityTextOutlineWidth;
linePaint.IsAntialias = true;
linePaint.Style = SKPaintStyle.Stroke;
using var helpLinePaint = new SKPaint();
helpLinePaint.Color = resolvedStyle.unityTextOutlineColor.ToSKColor();
helpLinePaint.StrokeWidth = 1;
helpLinePaint.Style = SKPaintStyle.Stroke;
using var fillPaint = new SKPaint();
fillPaint.Color = new SKColor(200, 200, 200, 200);
fillPaint.Style=SKPaintStyle.Fill;
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);
}
var label = _chartContainer.Create<Label>();
label.text = value.ToString(CultureInfo.InvariantCulture);
label.style.position = Position.Absolute;
label.style.left = posX;//-label.layout.width/2;
label.style.bottom = poxY;//- label.layout.height/2;
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);
var texture = info.ToTexture2D(surface);
_chartContainer.style.backgroundImage = texture;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 00511c331928b714d919870827a5c326
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using SkiaSharp;
using UnityEngine;
namespace BITKit.UX
{
public static class SkiaExtensions
{
public static Texture2D ToTexture2D(this SKImageInfo info,SKSurface surface)
{
// Okay, we're finished drawing. Now we create a Unity texture.
TextureFormat format = (info.ColorType == SKColorType.Rgba8888) ? TextureFormat.RGBA32 : TextureFormat.BGRA32;
var texture = new Texture2D(info.Width, info.Height, format, false, true);
texture.wrapMode = TextureWrapMode.Clamp;
// Pull a Skia image object out of the canvas...
var pixmap = surface.PeekPixels();
// Copy it to the Unity texture...
texture.LoadRawTextureData(pixmap.GetPixels(), pixmap.RowBytes * pixmap.Height);
texture.Apply(false, true);
// And drop it into the RawImage object.
return texture;
}
public static SKColor ToSKColor(this Color color,byte? alpha=null)
{
return new SKColor((byte)(color.r * 255), (byte)(color.g * 255), (byte)(color.b * 255), alpha??(byte)(color.a * 255));
}
public static SKColor ToSKColor(this Color32 color)
{
return new SKColor(color.r, color.g, color.b, color.a);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c23b988a0ca3904468edef1bd026f977
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 614549820bd3c514eaf369e4895d1ef0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8acc186ca11c9df42b8ab94c1e952e73
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
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

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ce3dedf1c2068047a00040de957cb33
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -30,7 +30,7 @@ namespace BITKit.UX
container = this.visualElement.Q(UXConstant.ContextContainer); container = this.visualElement.Q(UXConstant.ContextContainer);
toggle = this.visualElement.Q<Toggle>(UXConstant.Toggle); toggle = this.visualElement.Q<Toggle>(UXConstant.Toggle);
} }
public T Get<T>(int index) where T : VisualElement => visualElement.Q<T>($"{typeof(T).Name}--{index}"); public T Get<T>(int index = 0) where T : VisualElement => visualElement.Q<T>($"{typeof(T).Name}--{index}");
public void SetProcess(float process) public void SetProcess(float process)
{ {
var radialProgress = visualElement.Q<RadialProgress>(); var radialProgress = visualElement.Q<RadialProgress>();

View File

@@ -69,7 +69,7 @@ namespace BITKit.IData
if(attribute != null) if(attribute != null)
{ {
Name = attribute.Name; Name = attribute.Name;
VisualElement.GetType().GetProperty("label",ReflectionHelper.Flags)!.SetValue(VisualElement, Name); VisualElement.GetType().GetProperty("label",ReflectionHelper.Flags)?.SetValue(VisualElement, Name);
} }
if (fieldInfo.GetCustomAttribute<ReadOnlyAttribute>() is not null) if (fieldInfo.GetCustomAttribute<ReadOnlyAttribute>() is not null)
{ {
@@ -111,11 +111,22 @@ namespace BITKit.IData
} }
public sealed class UXStringBinder:UXDataBinder<string> public sealed class UXStringBinder:UXDataBinder<string>
{ {
protected override VisualElement OnCreateUI() => new TextField() protected override VisualElement OnCreateUI()
{ {
isDelayed = true, if (this.fieldInfo.GetCustomAttribute<ReadOnlyAttribute>() is not null)
multiline = true {
}; return new Label();
}
else
{
return new TextField()
{
isDelayed = true,
multiline = true
};
}
}
} }
public sealed class UXFloat3Binder:UXDataBinder<float3> public sealed class UXFloat3Binder:UXDataBinder<float3>
{ {

View File

@@ -0,0 +1,84 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.UX
{
public class ProgressBlock : VisualElement
{
public new class UxmlTraits : VisualElement.UxmlTraits
{
private readonly UxmlIntAttributeDescription m_ValueAttribute = new ()
{
name = "Value",defaultValue = 50
};
private readonly UxmlIntAttributeDescription m_SeparateAttribute = new ()
{
name = "Separate",defaultValue = 5
};
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var x = (ProgressBlock)ve;
x.Value = m_ValueAttribute.GetValueFromBag(bag, cc);
x.Separate = m_SeparateAttribute.GetValueFromBag(bag, cc);
}
}
public ProgressBlock() : base()
{
}
public new class UxmlFactory : UxmlFactory<ProgressBlock, UxmlTraits> { }
/// <summary>
/// 值,默认50,范围0-100
/// </summary>
public int Value
{
get => value;
set
{
this.value = value;
Rebuild();
}
}
private int value;
/// <summary>
/// 分割线,默认5
/// </summary>
public int Separate
{
get => separate;
set
{
this.separate = value;
Rebuild();
}
}
private int separate;
private void Rebuild()
{
Clear();
//if value is 58
for (var i = 1; i <= Separate; i++)
{
var block = this.Create<VisualElement>();
block.style.flexGrow = 1;
if (i * 10 < Value)
{
block.style.opacity = 1;
}else if ((i + 1) * 10 > value)
{
block.style.opacity = 0.5f;
}
else
{
block.style.opacity = 0;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca822b68d3588fd48abf69d987af2607
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -51,7 +51,12 @@ namespace BITKit.UX
) )
{ {
var bindPathAtt = fieldInfo.GetCustomAttribute<UXBindPathAttribute>(); var bindPathAtt = fieldInfo.GetCustomAttribute<UXBindPathAttribute>();
var ve = document.rootVisualElement.Q(bindPathAtt.Path); VisualElement ve = document.rootVisualElement;
foreach (var path in bindPathAtt.Path.Split("."))
{
ve = ve.Q(path);
}
//ve = document.rootVisualElement.Q(bindPathAtt.Path);
if(bindPathAtt.CanBeNull is false && ve is null) if(bindPathAtt.CanBeNull is false && ve is null)
BIT4Log.LogException(new NullReferenceException($"未找到{bindPathAtt.Path}")); BIT4Log.LogException(new NullReferenceException($"未找到{bindPathAtt.Path}"));
fieldInfo.SetValue(self,ve); fieldInfo.SetValue(self,ve);

View File

@@ -41,7 +41,7 @@ namespace BITKit
{ {
var obj = self.serializedObject.targetObject; var obj = self.serializedObject.targetObject;
var type = obj.GetType(); var type = obj.GetType();
var field = type.GetField(self.propertyPath, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var field = type.GetField(self.propertyPath, ReflectionHelper.Flags);
if (field is null) if (field is null)
{ {
throw new NullReferenceException($"Field {self.propertyPath} is null"); throw new NullReferenceException($"Field {self.propertyPath} is null");
@@ -51,7 +51,6 @@ namespace BITKit
public static void FillDefaultInspector(VisualElement container, SerializedObject serializedObject, bool hideScript) public static void FillDefaultInspector(VisualElement container, SerializedObject serializedObject, bool hideScript)
{ {
container.Clear(); container.Clear();
if (serializedObject.targetObject is null) if (serializedObject.targetObject is null)
{ {
var label = container.Create<Label>(); var label = container.Create<Label>();
@@ -70,7 +69,7 @@ namespace BITKit
var type = serializedObject.targetObject.GetType(); var type = serializedObject.targetObject.GetType();
var fieldInfo = serializedObject.targetObject.GetType().GetField(property.propertyPath, ReflectionHelper.Flags); var fieldInfo = serializedObject.targetObject.GetType().GetField(property.propertyPath, ReflectionHelper.Flags);
if (fieldInfo is not null && Attribute.IsDefined(fieldInfo, typeof(ReadOnlyAttribute),true)) if (fieldInfo is not null && type == typeof(string) && Attribute.IsDefined(fieldInfo, typeof(ReadOnlyAttribute),true))
{ {
var attribute = fieldInfo.GetCustomAttribute<ReadOnlyAttribute>(); var attribute = fieldInfo.GetCustomAttribute<ReadOnlyAttribute>();
var _container = container.Create<VisualElement>(); var _container = container.Create<VisualElement>();
@@ -92,16 +91,60 @@ namespace BITKit
{ {
//var label = container.Create<Label>(); //var label = container.Create<Label>();
//label.text =$"propertyPath:{property.propertyPath} fieldInfo:{fieldInfo} type:{type} fieldInfo:{fieldInfo}"; //label.text =$"propertyPath:{property.propertyPath} fieldInfo:{fieldInfo} type:{type} fieldInfo:{fieldInfo}";
var _container = container;
var field = new PropertyField(property) var field = new PropertyField(property)
{ {
name = "PropertyField:" + property.propertyPath name = "PropertyField:" + property.propertyPath
}; };
if (fieldInfo is not null && Attribute.IsDefined(fieldInfo, typeof(ReadOnlyAttribute), true))
{
field.SetEnabled(false);
field.style.opacity = 1;
}
if (property.propertyPath == "m_Script" && serializedObject.targetObject != null) if (property.propertyPath == "m_Script" && serializedObject.targetObject != null)
{ {
field.SetEnabled(false); field.SetEnabled(false);
} }
// if (fieldInfo?.FieldType == typeof(Texture2D) && fieldInfo.GetValue(serializedObject) is Texture2D texture && texture)
// {
// _container = container.Create<VisualElement>();
//
// var foldout = _container.Create<Foldout>();
// foldout.text = property.displayName;
//
// var icon = foldout.Create<VisualElement>();
// var slider = foldout.Create<Slider>();
//
// var width = 128;
// var m = texture.height /width;
//
// icon.style.width = width;
// icon.style.height = width*m;
// icon.style.backgroundImage = texture;
//
// field.style.flexGrow = 1;
//
// _container.style.backgroundColor =new StyleColor(new Color32(31,31,31,255)) ;
// _container.style.borderBottomLeftRadius = 5;
// _container.style.borderBottomRightRadius = 5;
// _container.style.borderTopLeftRadius = 5;
// _container.style.borderTopRightRadius = 5;
//
// slider.label = "Scale";
// slider.lowValue = 1;
// slider.highValue = 2;
// slider.RegisterValueChangedCallback(x =>
// {
// icon.style.width = width * x.newValue;
// icon.style.height = width*m * x.newValue;
// });
// }
container.Add(field); _container.Add(field);
} }
// try // try
// { // {
@@ -123,7 +166,10 @@ namespace BITKit
{ {
if (method.GetCustomAttribute<BITAttribute>() is null) continue; if (method.GetCustomAttribute<BITAttribute>() is null) continue;
if (method.GetParameters().Length is not 0) continue; if (method.GetParameters().Length is not 0) continue;
var button = new Button(() => method.Invoke(serializedObject.targetObject, null)) var button = new Button(() =>
{
method.Invoke(serializedObject.targetObject, null);
})
{ {
text = method.Name text = method.Name
}; };

View File

@@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -20,11 +21,13 @@ namespace BITKit
private static VFXService sinleton; private static VFXService sinleton;
public VFX[] vfxs; public VFX[] vfxs;
private readonly Dictionary<string, UnityPool<Transform>> pools = new(); private readonly Dictionary<string, UnityPool<Transform>> pools = new();
private readonly ConcurrentDictionary<int, Transform> cache = new();
[SerializeField] private bool debug; [SerializeField] private bool debug;
[SerializeField] private Optional<int> defaultCapacity; [SerializeField] private Optional<int> defaultCapacity;
private void Awake() private void Awake()
{ {
cache.Clear();
sinleton = this; sinleton = this;
DI.Register(this); DI.Register(this);
} }
@@ -68,16 +71,22 @@ namespace BITKit
public bool TryMatch(out Transform value, params string[] key) public bool TryMatch(out Transform value, params string[] key)
{ {
foreach (var vfx in vfxs) value=cache.GetOrAdd(MathE.GetHash(key),Add);
return value is not null;
Transform Add(int arg)
{ {
if (vfx.IsMatch(key)) foreach (var vfx in vfxs)
{ {
value = vfx.prefab; if (vfx.IsMatch(key))
return true; {
var x = vfx.prefab;
return x;
}
} }
return null;
} }
value = null;
return false;
} }
} }
} }

View File

@@ -59,6 +59,7 @@ namespace BITKit.Vehicles
private bool isBraking; private bool isBraking;
private readonly ValidHandle highSpeedHandle = new(); private readonly ValidHandle highSpeedHandle = new();
private IUnityEntity _unityEntity; private IUnityEntity _unityEntity;
public Rigidbody Rigidbody => rigidbody;
[Inject(true)] [Inject(true)]
private IHealth _health; private IHealth _health;

View File

@@ -8,7 +8,8 @@
"GUID:d525ad6bd40672747bde77962f1c401e", "GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50", "GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:e34a5702dd353724aa315fb8011f08c3", "GUID:e34a5702dd353724aa315fb8011f08c3",
"GUID:f51ebe6a0ceec4240a699833d6309b23" "GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:045a42f233e479d41adc32d02b99631e"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@@ -13,7 +13,8 @@ namespace BITKit.OpenWorld
[SerializeField,ReadOnly] private int id; [SerializeField,ReadOnly] private int id;
[SerializeField] protected Vector3 size = Vector3.one; [SerializeField] protected Vector3 size = Vector3.one;
[SerializeField] protected Vector3 offset = Vector3.one * 0.5f; [SerializeField] protected Vector3 offset = Vector3.one * 0.5f;
public Bounds GetBounds()=>new Bounds(transform.position+transform.rotation * offset,transform.rotation * size); public Bounds GetBounds() => _bounds;
private Bounds _bounds;
public Node<IWorldChunkObject> ParentNode { get; set; } public Node<IWorldChunkObject> ParentNode { get; set; }
public void QuadTree_Root_Initialized(IQuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>> root) public void QuadTree_Root_Initialized(IQuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>> root)
{ {
@@ -30,6 +31,7 @@ namespace BITKit.OpenWorld
} }
protected virtual void Start() protected virtual void Start()
{ {
_bounds= new Bounds(transform.position+transform.rotation * offset,transform.rotation * size);
UnityWorldChunkService.Singleton.Register(this); UnityWorldChunkService.Singleton.Register(this);
destroyCancellationToken.Register(Dispose); destroyCancellationToken.Register(Dispose);
} }

View File

@@ -18,8 +18,17 @@ namespace BITKit.OpenWorld
[SerializeField] private ChunkBehaviour chunkBehaviour; [SerializeField] private ChunkBehaviour chunkBehaviour;
private void Start() private void Start()
{ {
chunkBehaviour.OnLodChangedEvent += OnLodChanged; try
if(colliders is {Length:0})colliders = GetComponentsInChildren<Collider>(); {
chunkBehaviour.OnLodChangedEvent += OnLodChanged;
if(colliders is {Length:0})colliders = GetComponentsInChildren<Collider>();
}
catch (Exception e)
{
BIT4Log.Warning<ColliderChunkObject>(gameObject.name);
BIT4Log.LogException(e);
}
} }
private void OnLodChanged(int arg1, int arg2) private void OnLodChanged(int arg1, int arg2)
{ {
@@ -30,22 +39,28 @@ namespace BITKit.OpenWorld
{ {
x.enabled = enabledCollider; x.enabled = enabledCollider;
} }
catch (UnassignedReferenceException)
{
GetCollidersInChildren();
OnLodChanged(arg1, arg2);
return;
}
catch (Exception e) catch (Exception e)
{ {
BIT4Log.Warning<ColliderChunkObject>(gameObject.name); BIT4Log.Warning<ColliderChunkObject>(gameObject.name);
BIT4Log.LogException(e); BIT4Log.LogException(e);
} }
} }
} }
#if UNITY_EDITOR
[BIT] [BIT]
private void GetCollidersInChildren() private void GetCollidersInChildren()
{ {
colliders = GetComponentsInChildren<Collider>(); colliders = GetComponentsInChildren<Collider>();
#if UNITY_EDITOR
EditorUtility.SetDirty(this); EditorUtility.SetDirty(this);
#endif
} }
#endif
} }
} }

View File

@@ -2,8 +2,11 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using BITKit.SceneManagement;
using Cysharp.Threading.Tasks;
using Quadtree; using Quadtree;
using UnityEngine; using UnityEngine;
using UnityEngine.Pool;
namespace BITKit.OpenWorld namespace BITKit.OpenWorld
@@ -21,13 +24,16 @@ namespace BITKit.OpenWorld
private readonly ConcurrentDictionary<int, IWorldChunkObject> dictionary=new(); private readonly ConcurrentDictionary<int, IWorldChunkObject> dictionary=new();
[SerializeReference, SubclassSelector] private ITicker ticker; [SerializeReference, SubclassSelector] private ITicker ticker;
[SerializeReference, SubclassSelector] private ISceneService sceneService;
[SerializeField, ReadOnly] private int count; [SerializeField, ReadOnly] private int count;
[SerializeField, ReadOnly] private int tickTaskCount;
[SerializeField] private bool drawBounds; [SerializeField] private bool drawBounds;
[SerializeField, Range(0, 1024)] private int[] lodDistances; [SerializeField, Range(0, 1024)] private int[] lodDistances;
[SerializeField] private Vector3 size; [SerializeField] private Vector3 size;
private Camera _camera; private Camera _camera;
private readonly HashSet<int> cacheList = new(); private readonly HashSet<int> cacheList = new();
private readonly Queue<(int, IWorldChunkObject)> lodQueue=new();
private bool isBusy;
protected virtual void Awake() protected virtual void Awake()
{ {
Singleton = (T) this; Singleton = (T) this;
@@ -35,20 +41,35 @@ namespace BITKit.OpenWorld
protected virtual void Start() protected virtual void Start()
{ {
sceneService?.RegisterLoadTaskAsync(LoadTask);
ticker.Add(OnTick); ticker.Add(OnTick);
destroyCancellationToken.Register(Dispose); destroyCancellationToken.Register(Dispose);
_quadtree = new QuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>>(transform.position, size); _quadtree = new QuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>>(transform.position, size);
_camera = Camera.main; _camera = Camera.main;
} }
private void Dispose() private async UniTask LoadTask()
{ {
var frame=0;
while (count is 0 || frame++<32)
{
if (destroyCancellationToken.IsCancellationRequested) return;
await UniTask.NextFrame();
}
}
protected virtual void Dispose()
{
sceneService?.UnRegisterLoadTaskAsync(LoadTask);
ticker.Remove(OnTick); ticker.Remove(OnTick);
_registerQueue.Clear(); _registerQueue.Clear();
_unregisterQueue.Clear(); _unregisterQueue.Clear();
} }
protected virtual void OnTick(float deltaTime) protected virtual async void OnTick(float deltaTime)
{ {
if (!enabled) return; if (!enabled) return;
if (isBusy) return;
isBusy = true;
while (_unregisterQueue.TryDequeue(out var obj)) while (_unregisterQueue.TryDequeue(out var obj))
{ {
_quadtree.Remove(obj); _quadtree.Remove(obj);
@@ -63,28 +84,76 @@ namespace BITKit.OpenWorld
} }
var cameraPosition = _camera.transform.position; var cameraPosition = _camera.transform.position;
var cycle = 0;
for (var index = 0; index < lodDistances.Length; index++) await UniTask.SwitchToThreadPool();
foreach (var chunkObject in _quadtree.Find(new Bounds(cameraPosition, Vector3.one * (lodDistances[^1]+lodDistances[0]))))
{ {
var distance = lodDistances[index]; if (cycle++ > 64)
foreach (var chunkObject in _quadtree.Find(new Bounds(cameraPosition, Vector3.one * distance)))
{ {
if (cacheList.Contains(chunkObject.Id)) continue; cycle = 0;
cacheList.Add(chunkObject.Id); await UniTask.NextFrame();
if (destroyCancellationToken.IsCancellationRequested) return;
var lod = chunkObject.Lod;
if (lod == index) continue;
try
{
chunkObject.Lod = index;
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
} }
var distance = Vector3.Distance(cameraPosition, chunkObject.GetBounds().center);
//var distance = Vector3.Distance(cameraPosition, chunkObject.GetBounds().ClosestPoint(cameraPosition));
if (cacheList.Contains(chunkObject.Id)) continue;
cacheList.Add(chunkObject.Id);
var lod = -1;
for (var i = 0; i < lodDistances.Length; i++)
{
if (!(distance < lodDistances[i])) continue;
lod = i;
break;
}
if(chunkObject.Lod==lod)continue;
//chunkObject.Lod = lod;
lodQueue.Enqueue((lod,chunkObject));
}
// for (var index = 0; index < lodDistances.Length; index++)
// {
// var distance = lodDistances[index];
// foreach (var chunkObject in _quadtree.Find(new Bounds(cameraPosition, Vector3.one * distance)))
// {
// if (cacheList.Contains(chunkObject.Id)) continue;
// cacheList.Add(chunkObject.Id);
//
// var lod = chunkObject.Lod;
// if (lod == index) continue;
// try
// {
// chunkObject.Lod = index;
// }
// catch (Exception e)
// {
// BIT4Log.LogException(e);
// }
// }
// }
await UniTask.SwitchToMainThread();
tickTaskCount = lodQueue.Count;
if (destroyCancellationToken.IsCancellationRequested) return;
cycle = 0;
while (lodQueue.TryDequeue(out var value))
{
if (cycle++ > 8)
{
cycle = 0;
await UniTask.NextFrame();
if (destroyCancellationToken.IsCancellationRequested) return;
}
value.Item2.Lod = value.Item1;
} }
isBusy = false;
cacheList.Clear(); cacheList.Clear();
} }
private void OnDrawGizmosSelected() private void OnDrawGizmosSelected()

View File

@@ -25,7 +25,7 @@ namespace BITKit.OpenWorld
if (_sceneHandle is not null) return; if (_sceneHandle is not null) return;
var stopWatcher = new System.Diagnostics.Stopwatch(); var stopWatcher = new System.Diagnostics.Stopwatch();
stopWatcher.Start(); stopWatcher.Start();
_sceneHandle = YooAssets.LoadSceneAsync(sceneName.Value,LoadSceneMode.Additive,suspendLoad:true,priority:8); _sceneHandle = YooAssets.LoadSceneAsync(sceneName.Value,LoadSceneMode.Additive,priority:8);
await _sceneHandle; await _sceneHandle;
stopWatcher.Stop(); stopWatcher.Stop();
Debug.Log($"加载场景 {sceneName.Value} 耗时 {stopWatcher.ElapsedMilliseconds}ms"); Debug.Log($"加载场景 {sceneName.Value} 耗时 {stopWatcher.ElapsedMilliseconds}ms");

View File

@@ -70,7 +70,7 @@ namespace BITKit.GameEditor
} }
} }
} }
catch (Exception e) catch (Exception)
{ {
continue; continue;
} }

View File

@@ -18,7 +18,7 @@ namespace BITKit.GameEditor
protected readonly List<T> List=new(); protected readonly List<T> List=new();
private ListView _listView; private ListView _listView;
private VisualElement _container; protected VisualElement _container { get; private set; }
private Button _createButton; private Button _createButton;
private void OnEnable() private void OnEnable()
@@ -99,7 +99,7 @@ namespace BITKit.GameEditor
$"{GetType().Name} 已初始化,从{AssetsPath}获取到{List.Count}个{typeof(T).Name}"); $"{GetType().Name} 已初始化,从{AssetsPath}获取到{List.Count}个{typeof(T).Name}");
} }
private void ItemsChosen(IEnumerable<object> obj) protected virtual void ItemsChosen(IEnumerable<object> obj)
{ {
var selected = obj.FirstOrDefault() as Object; var selected = obj.FirstOrDefault() as Object;
var serializedObject = new SerializedObject(selected); var serializedObject = new SerializedObject(selected);
@@ -167,6 +167,7 @@ namespace BITKit.GameEditor
).ToArray(); ).ToArray();
List.AddRange(allItem.Cast<T>()); List.AddRange(allItem.Cast<T>());
} }
protected virtual void CreateScriptableObject(string name) protected virtual void CreateScriptableObject(string name)
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
@@ -178,6 +179,8 @@ namespace BITKit.GameEditor
if (EditorUtility.DisplayDialog("创建", $"是否创建{name}与{path}?", "是", "否") is false) return; if (EditorUtility.DisplayDialog("创建", $"是否创建{name}与{path}?", "是", "否") is false) return;
new DirectoryInfo(Path.GetDirectoryName(path)!).Create();
var item = CreateInstance<T>(); var item = CreateInstance<T>();
item.name = name; item.name = name;
AssetDatabase.CreateAsset(item, path); AssetDatabase.CreateAsset(item, path);

View File

@@ -3,7 +3,9 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using MeshCombineStudio; using MeshCombineStudio;
using NGS.AdvancedCullingSystem.Dynamic; using NGS.AdvancedCullingSystem.Dynamic;
using UnityEditor.Build;
using UnityEngine; using UnityEngine;
using UnityEngine.Events;
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor; using UnityEditor;
#endif #endif
@@ -12,15 +14,21 @@ namespace BITKit.OpenWorld
public class OpenWorldCombiner : MonoBehaviour public class OpenWorldCombiner : MonoBehaviour
{ {
[SerializeField] private MeshCombiner meshCombiner; [SerializeField] private MeshCombiner meshCombiner;
[SerializeField] private UnityEvent onCombiningReady;
[SerializeField]
private bool allowCullingSource = true;
private void Start() private void Start()
{ {
meshCombiner.onCombiningReady +=x=> onCombiningReady.Invoke();
meshCombiner.onCombiningReady += AddCullingSource; meshCombiner.onCombiningReady += AddCullingSource;
} }
private void AddCullingSource(MeshCombiner meshcombiner) private void AddCullingSource(MeshCombiner meshcombiner)
{ {
if (enabled) if (allowCullingSource)
AddCullingSource(); AddCullingSource();
} }

View File

@@ -12,20 +12,35 @@ namespace BITKit
public string questName; public string questName;
public string qeustDescription; public string qeustDescription;
public BBParameter<QuestSystem.Info> output; public BBParameter<QuestSystem.Info> output;
private bool isInitiated;
private void Disposed()
{
if (output.isNoneOrNull) return;
if(output.value.State is QuestSystem.State.InProcess)
{
BIT4Log.Log<CreateQuest>($"任务{output.value.Name}已取消");
QuestSystem.Cancel(output.value);
}
}
protected override void OnExecute() protected override void OnExecute()
{ {
var quest = QuestSystem.Create(questName, qeustDescription); var quest = QuestSystem.Create(questName, qeustDescription);
if (output.isDefined) if (output.isDefined)
output.SetValue(quest); output.SetValue(quest);
EndAction(); EndAction();
}
protected override void OnStop(bool interrupted) if(isInitiated)return;
{ agent.As<MonoBehaviour>().destroyCancellationToken.Register(Disposed);
base.OnStop(interrupted); isInitiated = true;
if (!interrupted) return; ; }
if (QuestSystem.quests.TryGetValue(output.value, out var info) && // protected override void OnStop(bool interrupted)
info.State == QuestSystem.State.InProcess) // {
QuestSystem.Cancel(output.value); // base.OnStop(interrupted);
} // if (!interrupted) return;
// if (QuestSystem.quests.TryGetValue(output.value, out var info) &&
// info.State == QuestSystem.State.InProcess)
// QuestSystem.Cancel(output.value);
// }
} }
} }

View File

@@ -34,7 +34,6 @@ namespace BITKit
{ {
blackboard.SetVariableValue("HP", hp); blackboard.SetVariableValue("HP", hp);
} }
public void OnEntryOverride(bool @override) public void OnEntryOverride(bool @override)
{ {
_allow.SetDisableElements(this,@override); _allow.SetDisableElements(this,@override);

View File

@@ -15,7 +15,7 @@ namespace BITKit.NodeCanvas
public BBParameter<Transform> target; public BBParameter<Transform> target;
protected override void OnExecute() protected override void OnExecute()
{ {
target.SetValue(sensor.value.CurrentTarget); //target.SetValue(sensor.value.CurrentTarget);
EndAction(); EndAction();
} }
} }