更新Ecs

更新Ecs
This commit is contained in:
ALEXTANG
2022-08-05 17:28:16 +08:00
parent 53a929366c
commit ac81cc3bc2
21 changed files with 213 additions and 154 deletions

View File

@@ -32,7 +32,7 @@ namespace TEngine
[DebuggerDisplay("Count = {Count}")]
public class ArrayPool<T> where T:IIndex
{
internal T[] m_Items = new T[256];
internal T[] Items = new T[256];
internal bool[] Buckets = new bool[256];
private int m_Index;
private int count;
@@ -41,11 +41,11 @@ namespace TEngine
{
get
{
return m_Items[index];
return Items[index];
}
set
{
m_Items[index] = value;
Items[index] = value;
}
}
@@ -60,11 +60,11 @@ namespace TEngine
public T[] ToArray()
{
List<T> elements = new List<T>();
for (int i = 0; i < m_Items.Length; i++)
for (int i = 0; i < Items.Length; i++)
{
if (Buckets[i])
{
elements.Add(m_Items[i]);
elements.Add(Items[i]);
}
}
return elements.ToArray();
@@ -74,7 +74,7 @@ namespace TEngine
{
lock (this)
{
m_Items[item.Index] = default;
Items[item.Index] = default;
Buckets[item.Index] = false;
}
}
@@ -87,23 +87,23 @@ namespace TEngine
{
if (!Buckets[item.Index])
{
m_Items[item.Index] = item;
Items[item.Index] = item;
Buckets[item.Index] = true;
return;
}
}
m_Items[m_Index] = item;
Items[m_Index] = item;
Buckets[m_Index] = true;
item.Index = m_Index;
m_Index++;
if (m_Index >= m_Items.Length)
if (m_Index >= Items.Length)
{
T[] newItems = new T[m_Items.Length * 2];
bool[] newBuckets = new bool[m_Items.Length * 2];
Array.Copy(m_Items,0,newItems,0,m_Items.Length);
T[] newItems = new T[Items.Length * 2];
bool[] newBuckets = new bool[Items.Length * 2];
Array.Copy(Items,0,newItems,0,Items.Length);
Array.Copy(Buckets, 0, newBuckets, 0, Buckets.Length);
m_Items = newItems;
Items = newItems;
Buckets = newBuckets;
}
count = m_Index;

View File

@@ -1,25 +1,24 @@
using TEngine;
using UnityEngine;
public class ECSDemoApp : MonoBehaviour
public class EcsDemoApp : MonoBehaviour
{
public ECSGameSystem EcsGameSystem = new ECSGameSystem();
public GameObject @object;
void Start()
{
var entity = EcsGameSystem.Create<Entity>();
ECSActor actor = entity.AddComponent<ECSActor>();
actor.Name = typeof(ECSActor).ToString();
var entity = EcsSystem.Instance.Create<Entity>();
EcsActor actor = entity.AddComponent<EcsActor>();
actor.Name = typeof(EcsActor).ToString();
actor.gameObject = Instantiate(@object);
actor.transform = actor.gameObject.GetComponent<Transform>();
entity.AddComponent<ECSComponent>();
entity.AddComponent<EcsComponent>();
Debug.Log(entity.ToString());
}
void Update()
{
EcsGameSystem.OnUpdate();
EcsSystem.Instance.Update();
}
}

View File

@@ -1,9 +0,0 @@
using TEngine;
public class ECSGameSystem : ECSSystem
{
public void OnUpdate()
{
Update();
}
}

View File

@@ -1,9 +1,9 @@
namespace TEngine
{
/// <summary>
/// ECS Actor
/// Ecs Actor
/// </summary>
public class ECSActor : ECSComponent
public class EcsActor : EcsComponent
{
public string Name;
public UnityEngine.GameObject gameObject;

View File

@@ -1,10 +1,10 @@
namespace TEngine
{
/// <summary>
/// ECS构架可以将此组件从Entity上移除这个组件并丢入对象池给其他此刻需要此组件的Entity使用
/// 因此可以节省大量的内存反复创建和释放, 这也是ECS的特性可以大量重复使用组件
/// Ecs构架可以将此组件从Entity上移除这个组件并丢入对象池给其他此刻需要此组件的Entity使用
/// 因此可以节省大量的内存反复创建和释放, 这也是Ecs的特性可以大量重复使用组件
/// </summary>
public class ECSComponent:ECSObject
public class EcsComponent:EcsObject
{
#pragma warning disable IDE1006
public Entity Entity { get; set; }

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace TEngine
{
public enum ECSDebugType
public enum EcsDebugType
{
Entity,
System,
@@ -11,31 +11,31 @@ namespace TEngine
}
[Serializable]
public class ECSCmptDebugKeyInfo
public class EcsCmptDebugKeyInfo
{
public string m_name;
public string val;
}
[Serializable]
public class ECSCmptDebugInfo
public class EcsCmptDebugInfo
{
public string m_name;
public ECSDebugType Type = ECSDebugType.Component;
public List<ECSCmptDebugKeyInfo> m_info = new List<ECSCmptDebugKeyInfo>();
public EcsDebugType Type = EcsDebugType.Component;
public List<EcsCmptDebugKeyInfo> m_info = new List<EcsCmptDebugKeyInfo>();
}
public class ECSDebugBehaviour : UnityEngine.MonoBehaviour
public class EcsDebugBehaviour : UnityEngine.MonoBehaviour
{
public List<ECSCmptDebugInfo> m_ECSInfo = new List<ECSCmptDebugInfo>();
public ECSCmptDebugInfo AddDebugCmpt(string cmptName)
public List<EcsCmptDebugInfo> m_EcsInfo = new List<EcsCmptDebugInfo>();
public EcsCmptDebugInfo AddDebugCmpt(string cmptName)
{
var cmptInfo = m_ECSInfo.Find((item) => { return item.m_name == cmptName; });
var cmptInfo = m_EcsInfo.Find((item) => { return item.m_name == cmptName; });
if (cmptInfo == null)
{
cmptInfo = new ECSCmptDebugInfo();
cmptInfo = new EcsCmptDebugInfo();
cmptInfo.m_name = cmptName;
m_ECSInfo.Add(cmptInfo); ;
m_EcsInfo.Add(cmptInfo); ;
}
return cmptInfo;
@@ -43,7 +43,7 @@ namespace TEngine
public void RmvDebugCmpt(string cmptName)
{
m_ECSInfo.RemoveAll((item) => { return item.m_name == cmptName; });
m_EcsInfo.RemoveAll((item) => { return item.m_name == cmptName; });
}
public void SetDebugInfo(string cmptName, string key, string val)
@@ -52,7 +52,7 @@ namespace TEngine
var entry = cmptInfo.m_info.Find((t) => { return t.m_name == key; });
if (entry == null)
{
entry = new ECSCmptDebugKeyInfo();
entry = new EcsCmptDebugKeyInfo();
entry.m_name = key;
cmptInfo.m_info.Add(entry);
}
@@ -62,7 +62,7 @@ namespace TEngine
public void RemoveAllDebugInfo(string cmpName)
{
var cmpInfo = m_ECSInfo.Find((item) => { return item.m_name == cmpName; });
var cmpInfo = m_EcsInfo.Find((item) => { return item.m_name == cmpName; });
if (cmpInfo != null)
{
cmpInfo.m_info.Clear();

View File

@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
namespace TEngine
{
public class ECSEventCmpt : ECSComponent
public class EcsEventCmpt : EcsComponent
{
private GameEvent _gameEvent;

View File

@@ -4,15 +4,15 @@ using System.Collections.Generic;
namespace TEngine
{
/// <summary>
/// ECS架构基类Object
/// Ecs架构基类Object
/// </summary>
public class ECSObject
public class EcsObject
{
internal int HashCode;
internal ECSSystem System;
internal EcsSystem System;
public ECSObject()
public EcsObject()
{
HashCode = GetType().GetHashCode();
}
@@ -22,13 +22,13 @@ namespace TEngine
public virtual void OnDestroy() { }
/// <summary>
/// Remove The ECSEntity or Component And Throw the ECSObject to ArrayPool When AddComponent Or Create Can Use Again
/// Remove The EcsEntity or Component And Throw the EcsObject to ArrayPool When AddComponent Or Create Can Use Again
/// </summary>
/// <param name="ecsObject"></param>
/// <param name="reuse">此对象是否可以复用复用会将对象丢入System对象池中 等待再次使用如果是Entity对象并且不复用的话则把Entity所使用的组件也不复用</param>
public static void Destroy(ECSObject ecsObject, bool reuse = true)
public static void Destroy(EcsObject ecsObject, bool reuse = true)
{
if (ecsObject is ECSComponent ecsComponent)
if (ecsObject is EcsComponent ecsComponent)
{
ecsComponent.Entity.Components.Remove(ecsComponent);
if (ecsComponent is IUpdate update)
@@ -48,7 +48,7 @@ namespace TEngine
entity.OnDestroy();
while (entity.Components.Count > 0)
{
ECSComponent ecsComponentTemp = entity.Components[0];
EcsComponent ecsComponentTemp = entity.Components[0];
entity.Components.RemoveAt(0);
ecsComponentTemp.OnDestroy();
if (reuse)
@@ -65,7 +65,7 @@ namespace TEngine
}
}
public T FindObjectOfType<T>() where T : ECSObject
public T FindObjectOfType<T>() where T : EcsObject
{
Type type = typeof(T);
var elements = System.Entities.ToArray();
@@ -86,7 +86,7 @@ namespace TEngine
return null;
}
public T[] FindObjectsOfType<T>() where T : ECSObject
public T[] FindObjectsOfType<T>() where T : EcsObject
{
Type type = typeof(T);
var items = System.Entities.ToArray();

View File

@@ -5,16 +5,33 @@ using System.Threading.Tasks;
namespace TEngine
{
/// <summary>
/// ECS系统 管理Entity、ECSComponent复用对象池
/// Ecs系统
/// </summary>
[Serializable]
public class ECSSystem : IDisposable
public class EcsSystem : IDisposable
{
private static ECSSystem instance = new ECSSystem();
public static ECSSystem Instance => instance;
private readonly Dictionary<int,Stack<ECSObject>> m_ObjectPool = new Dictionary<int, Stack<ECSObject>>();
private static EcsSystem _instance;
public static EcsSystem Instance
{
get
{
if (_instance == null)
{
_instance = new EcsSystem();
}
return _instance;
}
}
private EcsSystem()
{
}
/// <summary>
/// Key -> HashSet(type) / Value -> Stack(EcsObject)
/// </summary>
internal readonly Dictionary<int, Stack<EcsObject>> ObjectPool = new Dictionary<int, Stack<EcsObject>>();
internal readonly ArrayPool<Entity> Entities = new ArrayPool<Entity>();
private bool m_IsDispose = false;
public void AddEntity(Entity entity)
{
@@ -28,42 +45,34 @@ namespace TEngine
Entities.Remove(entity);
}
/// <summary>
/// Get Object From ECSSystem
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Get<T>() where T : ECSObject, new()
public T Get<T>() where T : EcsObject, new()
{
int type = typeof(T).GetHashCode();
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
if (ObjectPool.TryGetValue(type, out Stack<EcsObject> stack))
{
if (stack.Count > 0)
{
return (T) stack.Pop();
return (T)stack.Pop();
}
goto Instantiate;
}
stack = new Stack<ECSObject>();
m_ObjectPool.Add(type,stack);
stack = new Stack<EcsObject>();
ObjectPool.Add(type, stack);
Instantiate: T ecsObject = new T();
return ecsObject;
}
/// <summary>
/// Push Object To ECSSystem
/// </summary>
public void Push(ECSObject ecsObject)
public void Push(EcsObject ecsObject)
{
int type = ecsObject.HashCode;
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
if (ObjectPool.TryGetValue(type, out Stack<EcsObject> stack))
{
stack.Push(ecsObject);
return;
}
stack = new Stack<ECSObject>();
m_ObjectPool.Add(type,stack);
stack = new Stack<EcsObject>();
ObjectPool.Add(type, stack);
stack.Push(ecsObject);
}
@@ -81,7 +90,7 @@ namespace TEngine
}
/// <summary>
/// 更新ECS系统
/// 更新Ecs系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void Update(bool worker = false)
@@ -90,7 +99,7 @@ namespace TEngine
}
/// <summary>
/// 更新ECS物理系统
/// 更新Ecs物理系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void FixedUpdate(bool worker = false)
@@ -99,7 +108,7 @@ namespace TEngine
}
/// <summary>
/// 运行ECS系统
/// 运行Ecs系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void Run(bool worker = false)
@@ -176,16 +185,15 @@ namespace TEngine
}
}
#region Dispose
public void Dispose()
{
if (m_IsDispose)
{
return;
}
m_IsDispose = true;
_instance = null;
}
#endregion
public T FindObjectOfType<T>() where T : ECSObject
#region FindObjectOfType
public T FindObjectOfType<T>() where T : EcsObject
{
Type type = typeof(T);
var elements = Entities.ToArray();
@@ -207,7 +215,7 @@ namespace TEngine
return null;
}
public T[] FindObjectsOfType<T>() where T : ECSObject
public T[] FindObjectsOfType<T>() where T : EcsObject
{
Type type = typeof(T);
var entities = Entities.ToArray();
@@ -228,6 +236,7 @@ namespace TEngine
}
return elements.ToArray();
}
#endregion
}
}

View File

@@ -1,24 +1,60 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using UnityEngine;
namespace TEngine
{
public class Entity : ECSObject, IIndex
[Flags]
public enum EntityStatus : byte
{
None = 0,
IsFromPool = 1,
IsRegister = 1 << 1,
IsComponent = 1 << 2,
IsCreated = 1 << 3,
IsNew = 1 << 4,
}
public class Entity : EcsObject, IIndex
{
[IgnoreDataMember]
private EntityStatus status = EntityStatus.None;
#region Status
[IgnoreDataMember]
private bool IsFromPool
{
get => (this.status & EntityStatus.IsFromPool) == EntityStatus.IsFromPool;
set
{
if (value)
{
this.status |= EntityStatus.IsFromPool;
}
else
{
this.status &= ~EntityStatus.IsFromPool;
}
}
}
#endregion
[SerializeField]
internal List<ECSComponent> Components = new List<ECSComponent>();
internal List<EcsComponent> Components = new List<EcsComponent>();
internal List<IUpdate> Updates = new List<IUpdate>();
internal List<IFixedUpdate> FixedUpdates = new List<IFixedUpdate>();
internal bool InActive;
internal bool CanUpdate;
internal bool CanFixedUpdate;
public int Index { get; set; } = -1;
public ECSEventCmpt Event { get; set; }
public EcsEventCmpt Event { get; set; }
public Entity()
{
InActive = true;
System = ECSSystem.Instance;
System = EcsSystem.Instance;
}
~Entity()
@@ -42,7 +78,7 @@ namespace TEngine
}
}
public void RmvComponent<T>() where T : ECSComponent, new()
public void RmvComponent<T>() where T : EcsComponent, new()
{
for (int i = 0; i < Components.Count; i++)
{
@@ -56,7 +92,6 @@ namespace TEngine
{
FixedUpdates.Remove(fixedUpdate);
}
System.Push(component);
CanUpdate = Updates.Count > 0;
@@ -89,7 +124,7 @@ namespace TEngine
CanFixedUpdate = FixedUpdates.Count > 0;
}
//if (componentType is ECSComponent component)
//if (componentType is EcsComponent component)
//{
// System.Push(component);
//}
@@ -100,7 +135,7 @@ namespace TEngine
#endif
}
public T AddComponent<T>() where T : ECSComponent, new()
public T AddComponent<T>() where T : EcsComponent, new()
{
#if UNITY_EDITOR
CheckDebugInfo();
@@ -123,7 +158,7 @@ namespace TEngine
return component;
}
public ECSComponent AddComponent(ECSComponent component)
public EcsComponent AddComponent(EcsComponent component)
{
#if UNITY_EDITOR
CheckDebugInfo();
@@ -145,7 +180,7 @@ namespace TEngine
return component;
}
public T GetComponent<T>() where T : ECSComponent
public T GetComponent<T>() where T : EcsComponent
{
for (int i = 0; i < Components.Count; i++)
{
@@ -158,7 +193,7 @@ namespace TEngine
return null;
}
public ECSComponent GetComponent(Type componentType)
public EcsComponent GetComponent(Type componentType)
{
for (int i = 0; i < Components.Count; i++)
{
@@ -171,7 +206,7 @@ namespace TEngine
return null;
}
public T[] GetComponents<T>() where T : ECSComponent
public T[] GetComponents<T>() where T : EcsComponent
{
List<T> elements = new List<T>();
for (int i = 0; i < Components.Count; i++)
@@ -184,7 +219,7 @@ namespace TEngine
return elements.ToArray();
}
public List<T> GetComponentsList<T>() where T : ECSComponent
public List<T> GetComponentsList<T>() where T : EcsComponent
{
List<T> elements = new List<T>();
for (int i = 0; i < Components.Count; i++)
@@ -197,9 +232,9 @@ namespace TEngine
return elements;
}
public ECSComponent[] GetComponents(Type comType)
public EcsComponent[] GetComponents(Type comType)
{
List<ECSComponent> elements = new List<ECSComponent>();
List<EcsComponent> elements = new List<EcsComponent>();
for (int i = 0; i < Components.Count; i++)
{
{
@@ -234,8 +269,8 @@ namespace TEngine
return;
}
var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(gameObject);
debugBehaviour.m_ECSInfo.Clear();
var debugBehaviour = UnityUtil.AddMonoBehaviour<EcsDebugBehaviour>(gameObject);
debugBehaviour.m_EcsInfo.Clear();
for (int i = 0; i < this.Components.Count; i++)
{
var component = this.Components[i];
@@ -259,8 +294,8 @@ namespace TEngine
// return;
//}
//var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(actorEntity.gameObject);
//debugBehaviour.m_ECSInfo.Clear();
//var debugBehaviour = UnityUtil.AddMonoBehaviour<EcsDebugBehaviour>(actorEntity.gameObject);
//debugBehaviour.m_EcsInfo.Clear();
//for (int i = 0; i < this.Components.Count; i++)
//{
// var component = this.Components[i];

View File

@@ -1,11 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
public class HotfixComponent : ECSComponent,IUpdate
public class HotfixComponent : EcsComponent,IUpdate
{
public object[] Values;
public Action OnAwake, OnUpdate, OnDestroyExt;

View File

@@ -1,7 +1,7 @@
namespace TEngine
{
/// <summary>
/// ECS组件更新接口减少组件for循环开销
/// Ecs组件更新接口减少组件for循环开销
/// </summary>
public interface IFixedUpdate
{

View File

@@ -1,10 +0,0 @@
namespace TEngine
{
/// <summary>
/// ECS组件更新接口减少组件for循环开销
/// </summary>
public interface IUpdate
{
void Update();
}
}

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
using System;
namespace TEngine
{
public interface ISystemType
{
Type Type();
Type SystemType();
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 02463b27b6971f0408bb517c32c66553
guid: 4807792c3fd17824e9e7cc8ce8ba9e05
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

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

View File

@@ -0,0 +1,37 @@
using System;
namespace TEngine
{
/// <summary>
/// Ecs组件更新接口减少组件for循环开销
/// </summary>
public interface IUpdate
{
void Update();
}
public interface IUpdateSystem : ISystemType
{
void Run(object o);
}
public abstract class UpdateSystem<T> : IUpdateSystem where T : IUpdate
{
public void Run(object o)
{
this.Update((T)o);
}
public Type Type()
{
return typeof(T);
}
public Type SystemType()
{
return typeof(IUpdateSystem);
}
public abstract void Update(T self);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d9d458a85873d744ab382e86008b89a0
guid: 48e6061eb63189142bb682b49473156e
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,13 +0,0 @@
namespace TEngine
{
/// <summary>
/// 热更层由此组件进行更新ILRuntime不支持多继承, 接口继承)
/// </summary>
public class UpdateComponent :ECSComponent, IUpdate
{
public virtual void Update()
{
}
}
}