diff --git a/DragonECS.csproj b/DragonECS.csproj
index 44dcf4f..3fdfabc 100644
--- a/DragonECS.csproj
+++ b/DragonECS.csproj
@@ -10,7 +10,7 @@
DCFApixels.DragonECS
-
+
Русский
@@ -31,7 +31,7 @@
|
-
+
中文
@@ -50,6 +50,7 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system)
## Оглавление
- [Установка](#установка)
+- [Расширения](#расширения)
- [Основные концепции](#основные-концепции)
- [Entity](#entity)
- [Component](#component)
@@ -77,7 +78,6 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system)
- [Компоненты мира](#компоненты-мира)
- [Конфиги](#конфиги)
- [Проекты на DragonECS](#Проекты-на-DragonECS)
-- [Расширения](#расширения)
- [FAQ](#faq)
- [Обратная связь](#обратная-связь)
@@ -94,24 +94,49 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system)
+ Игровые движки с C#: Unity, Godot, MonoGame и т.д.
Протестировано:
-+ **Unity:** Минимальная версия 2020.1.0;
++ **Unity:** Минимальная версия 2020.3.0;
## Установка для Unity
> Рекомендуется так же установить расширение [Интеграция с движком Unity](https://github.com/DCFApixels/DragonECS-Unity)
* ### Unity-модуль
-Поддерживается установка в виде Unity-модуля в при помощи добавления git-URL [в PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) или ручного добавления в `Packages/manifest.json`:
+Поддерживается установка в виде Unity-модуля при помощи добавления git-URL [в PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html):
```
https://github.com/DCFApixels/DragonECS.git
```
+Или ручного добавления этой строчки в `Packages/manifest.json`:
+```
+"com.dcfa_pixels.dragonecs": "https://github.com/DCFApixels/DragonECS.git",
+```
+
* ### В виде исходников
-Фреймворк так же может быть добавлен в проект в виде исходников.
+Можно так же напрямую скопировать в проект исходники фреймворка.
+
+
+
+# Расширения
+* Интеграции:
+ * [Unity](https://github.com/DCFApixels/DragonECS-Unity)
+ * [Godot](https://gitlab.com/InauniusOwn/Libraries/DraGodot)
+* Пакеты:
+ * [Автоматическое внедрение зависимостей](https://github.com/DCFApixels/DragonECS-AutoInjections)
+ * [Классическая C# многопоточность](https://github.com/DCFApixels/DragonECS-ClassicThreads)
+ * [Recursivity](https://github.com/DCFApixels/DragonECS-Recursivity)
+ * [Hybrid](https://github.com/DCFApixels/DragonECS-Hybrid)
+ * [Графы](https://github.com/DCFApixels/DragonECS-Graphs)
+* Утилиты:
+ * [Упрощенный синтаксис](https://gist.github.com/DCFApixels/d7bfbfb8cb70d141deff00be24f28ff0)
+ * [Таймеры](https://gist.github.com/DCFApixels/71a416275660c465ece76242290400df)
+ * [Однокадровые компоненты](https://gist.github.com/DCFApixels/46d512dbcf96c115b94c3af502461f60)
+ * [Шаблоны кода IDE](https://gist.github.com/ctzcs/0ba948b0e53aa41fe1c87796a401660b) и [для Unity](https://gist.github.com/ctzcs/d4c7730cf6cd984fe6f9e0e3f108a0f1)
+> *Твое расширение? Если разрабатываешь расширение для DragonECS, пиши [сюда](#обратная-связь).
+
# Основные концепции
## Entity
-**Сущности** - это то к чему крепятся данные. Реализованы в виде идентификаторов, которых есть 2 вида:
-* `int` - однократный идентификатор, применяется в пределах одного тика. Не рекомендуется хранить `int` идентификаторы, в место этого используйте `entlong`;
-* `entlong` - долговременный идентификатор, содержит в себе полный набор информации для однозначной идентификации;
+**Сущности** - это то к чему крепятся данные. Для доступа к сущности используются идентификаторы двух типов:
+* `int` - однократный идентификатор, применяется в пределах одного тика. Не рекомендуется использовать для хранения;
+* `entlong` - долговременный идентификатор, содержит метку поколения, что делает его уникальным навсегда. Подходит для хранения.
``` c#
// Создание новой сущности в мире.
int entityID = _world.NewEntity();
@@ -129,10 +154,11 @@ int newEntityID = _world.CloneEntity(entityID);
Работа с entlong
+
``` c#
// Конвертация int в entlong.
entlong entity = _world.GetEntityLong(entityID);
-// или
+// упрощенная версия
entlong entity = (_world, entityID);
// Проверка что сущность еще жива.
@@ -148,6 +174,8 @@ if (entity.TryGetID(out int entityID)) { }
```
+
+>
> Сущности не могут существовать без компонентов, пустые сущности будут автоматически удаляться сразу после удаления последнего компонента либо в конце тика.
## Component
@@ -183,6 +211,48 @@ class SomeSystem : IEcsPreInit, IEcsInit, IEcsRun, IEcsDestroy
```
> Для реализации дополнительных процессов перейдите к разделу [Процессы](#Процессы).
+
+Пример системы
+
+
+``` c#
+// Система
+class DamageSystem : IEcsRun, IEcsInject
+{
+ // Аспекты описаны в соответствующей главе
+ class Aspect : EcsAspect
+ {
+ public EcsPool DamageRequests = Inc;
+ public EcsPool Healths = Inc;
+ }
+ // Мир - хранилище сущностей, так же описан в соответствующей главе
+ EcsDefaultWorld world;
+ // Процесс Run
+ public void Run()
+ {
+ // Итерируемся по сущностям, в рамках Run можно использовать int идентификаторы сущностей
+ foreach (int e in world.Where(out Aspect a))
+ {
+ // Логика нанесения урона
+ a.Healths[e].Points -= a.DamageRequests[e].Points;
+ }
+ }
+ // Процесс Inject. Получение инстанса EcsDefaultWorld
+ void IEcsInject.Inject(EcsDefaultWorld obj) => world = obj;
+}
+// Компоненты
+public struct DamageRequest : IEcsComponent
+{
+ public float Points;
+}
+public struct Health : IEcsComponent
+{
+ public float Points;
+}
+```
+
+
+
# Концепции фреймворка
@@ -466,10 +536,13 @@ poses.Del(entityID);
## Маска
-Применяется для фильтрации сущностей по наличию или отсутствию компонентов.
+Набор требований к компонентам сущности: какие компоненты должны присутствовать, а какие отсутствовать. Маска — это просто данные, она не выполняет поиск, а используется запросами для фильтрации сущностей.
+
+Обычно маски не используются в чистом виде, а являются частью [Аспекта](#Аспект).
+
``` c#
-// Создание маски которая проверяет что у сущностей есть компоненты
-// SomeCmp1 и SomeCmp2, но нет компонента SomeCmp3.
+// Создание маски с улосвием наличия компонентов SomeCmp1 и SomeCmp2,
+// и с улосвием отсутсвия компонента SomeCmp3.
EcsMask mask = EcsMask.New(_world)
// Inc - Условие наличия компонента.
.Inc()
@@ -501,42 +574,47 @@ EcsMask mask = _staticMask.ToMask(_world);
## Аспект
-Пользовательские классы наследуемые от `EcsAspect` и используемые для взаимодействия с сущностями. Аспекты одновременно являются кешем пулов и содержат маску. Можно рассматривать аспекты как описание того с какими сущностями работает система.
-Упрощенный синтаксис:
+Пользовательские классы наследуемые от `EcsAspect`, описывающие наборы компонентов, с которыми работает система. Аспект одновременно выполняет две функции:
++ Маска — инициализирует и хранит [маску](#Маска), за счет чего может использоваться в запросах.
++ Кэш пулов — предоставляет быстрый доступ к пулам компонентов.
+
+
+Проще говоря, аспект — это удобный способ описать "с какими сущностями я работаю и как получать их компоненты".
+
+
+Пример:
``` c#
-using DCFApixels.DragonECS;
-// ...
class Aspect : EcsAspect
{
- // Кешируется пул и Pose добавляется во включающее ограничение.
+ // Кешируется пул и тип Pose добавляется во включающее условие.
public EcsPool poses = Inc;
- // Кешируется пул и Velocity добавляется во включающее ограничение.
+ // Кешируется пул и тип Velocity добавляется во включающее условие.
public EcsPool velocities = Inc;
- // Кешируется пул и FreezedTag добавляется в исключающее ограничение.
+ // Кешируется пул и тип FreezedTag добавляется в исключающее условие.
public EcsTagPool freezedTags = Exc;
-
- // При запросах будет проверяться наличие компонентов
- // из включающего ограничения маски и отсутствие из исключающего.
- // Так же есть Opt - только кеширует пул, не влияя на маску.
}
```
+Назначение статических свойств:
++ Inc — компонент должен быть у сущности (включающее условие) + кеширует пул
++ Exc — компонента не должно быть у сущности (исключающее условие) + кеширует пул
++ Opt — компонент может быть, но не влияет на фильтрацию (только кеширует пул для доступа)
++ Any — хотя бы один из компонентов с Any должен присутствовать + кеширует пул
+
-Явный синтаксис (результат идентичен примеру выше):
+Инициализация через метод (результат идентичен примеру выше):
``` c#
-using DCFApixels.DragonECS;
-// ...
class Aspect : EcsAspect
{
public EcsPool poses;
public EcsPool velocities;
protected override void Init(Builder b)
{
- poses = b.Include();
- velocities = b.Include();
- b.Exclude();
+ poses = b.IncludePool();
+ velocities = b.IncludePool();
+ b.ExcludePool();
}
}
```
@@ -546,10 +624,8 @@ class Aspect : EcsAspect
Комбинирование аспектов
-В аспекты можно добавлять другие аспекты, тем самым комбинируя их. Ограничения так же будут скомбинированы.
+В аспекты можно добавлять другие аспекты, тем самым комбинируя их. Маски так же будут скомбинированы.
``` c#
-using DCFApixels.DragonECS;
-// ...
class Aspect : EcsAspect
{
public OtherAspect1 otherAspect1;
@@ -562,7 +638,7 @@ class Aspect : EcsAspect
otherAspect1 = b.Combine(1);
// Хотя для OtherAspect1 метод Combine был вызван раньше, сначала будет скомбинирован с OtherAspect2, так как по умолчанию order = 0.
otherAspect2 = b.Combine();
- // Если в OtherAspect1 или в OtherAspect2 было ограничение b.Exclude() тут оно будет заменено на b.Include().
+ // Если в OtherAspect1 или в OtherAspect2 было условие b.Exclude() тут оно будет заменено на b.Include().
poses = b.Include();
}
}
@@ -578,11 +654,11 @@ class Aspect : EcsAspect
## Запросы
-Фильтруют сущности и выдают коллекции сущностей удовлетворяющие определенным условиям. Встроенный запрос `Where` фильтрует на соответствие условиям маски компонентов и имеет несколько перегрузок:
+Запросы позволяют отфильтровать и получать коллекции сущностей, удовлетворяющих заданным условиям. Основной метод — `Where`, который фильтрует по маске компонентов и имеет несколько перегрузок:
++ `EcsWorld.Where(out TAspect aspect)` - Фильтрация по маске, определённой в аспекте, плюс получение самого аспекта с закешированными пулами.
+ `EcsWorld.Where(EcsMask mask)` - Обычная фильтрация по маске;
-+ `EcsWorld.Where(out TAspect aspect)` - Сочетает в себе фильтрацию по маске из аспекта и получение аспекта;
-Запрос `Where` применим как к `EcsWorld` так и коллекциям фреймворка (в этом плане Where чем-то похож на аналогичный из Linq). Так же имеются перегрузки для сортировки сущностей по `Comparison`.
+`Where` можно вызывать не только у мира, но и у любых коллекций фреймворка (в этом плане Where чем-то похож на аналогичный из Linq). Также доступны перегрузки для сортировки сущностей с помощью `Comparison`.
Пример системы:
``` c#
@@ -597,10 +673,9 @@ public class SomeDamageSystem : IEcsRun, IEcsInject
public EcsTagPool isDiedSignals = Opt;
}
EcsDefaultWorld _world;
- public void Inject(EcsDefaultWorld world) => _world = world;
-
public void Run()
{
+ // Запрашиваем сущности удовлетворяющее маске из Aspect
foreach (var e in _world.Where(out Aspect a))
{
// Сюда попадают сущности с компонентами Health, DamageSignal и без IsInvulnerable.
@@ -615,6 +690,7 @@ public class SomeDamageSystem : IEcsRun, IEcsInject
}
}
}
+ public void Inject(EcsDefaultWorld world) => _world = world;
}
```
@@ -623,7 +699,7 @@ public class SomeDamageSystem : IEcsRun, IEcsInject
## Коллекции
### EcsSpan
-Коллекция сущностей, доступная только для чтения и выделяемая только в стеке. Состоит из ссылки на массив, длинны и идентификатора мира. Аналог `ReadOnlySpan`.
+`ref struct` коллекция сущностей, доступная только для чтения. Состоит из ссылки на массив, длинны и идентификатора мира. Аналог `ReadOnlySpan`.
``` c#
// Запрос Where возвращает сущности в виде EcsSpan.
EcsSpan es = _world.Where(out Aspect a);
@@ -641,7 +717,7 @@ for (int i = 0; i < es.Count; i++)
> Хотя `EcsSpan` является просто массивом, в нем не допускается дублирование сущностей.
### EcsGroup
-Вспомогательная коллекция основанная на Sparse Set для хранения множества сущностей с O(1) операциями добавления/удаления/проверки и т.д.
+Вспомогательная коллекция основанная на Sparse Set для хранения множества сущностей с `O(1)` операциями добавления/удаления/проверки и т.д.
``` c#
// Получаем новую группу. EcsWorld содержит в себе пул групп,
// поэтому будет переиспользована свободная или создана новая.
@@ -1011,6 +1087,23 @@ public struct WorldComponent : IEcsWorldComponent
## Опубликованные проекты:
-# Расширения
-* Пакеты:
- * [Интеграция с движком Unity](https://github.com/DCFApixels/DragonECS-Unity)
- * [Автоматическое внедрение зависимостей](https://github.com/DCFApixels/DragonECS-AutoInjections)
- * [Классическая C# многопоточность](https://github.com/DCFApixels/DragonECS-ClassicThreads)
- * [Recursivity](https://github.com/DCFApixels/DragonECS-Recursivity)
- * [Hybrid](https://github.com/DCFApixels/DragonECS-Hybrid)
- * [Графы](https://github.com/DCFApixels/DragonECS-Graphs)
-* Утилиты:
- * [Упрощенный синтаксис](https://gist.github.com/DCFApixels/d7bfbfb8cb70d141deff00be24f28ff0)
- * [Однокадровые компоненты](https://gist.github.com/DCFApixels/46d512dbcf96c115b94c3af502461f60)
- * [Шаблоны кода IDE](https://gist.github.com/ctzcs/0ba948b0e53aa41fe1c87796a401660b) и [для Unity](https://gist.github.com/ctzcs/d4c7730cf6cd984fe6f9e0e3f108a0f1)
-> *Твое расширение? Если разрабатываешь расширение для DragonECS, пиши [сюда](#обратная-связь).
-
-
# FAQ
+
## 'ReadOnlySpan<>' could not be found
В версии Unity 2020.1.х в консоли может выпадать ошибка:
```
diff --git a/README-ZH.md b/README-ZH.md
index 7266641..6e6777c 100644
--- a/README-ZH.md
+++ b/README-ZH.md
@@ -19,7 +19,7 @@
-
+
Русский
@@ -31,7 +31,7 @@
|
-
+
中文
diff --git a/README.md b/README.md
index 8edb090..c3f9193 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
|
-
+
Русский
@@ -33,7 +33,7 @@
|
-
+
中文
diff --git a/package.json b/package.json
index e596002..53672b0 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"displayName": "DragonECS",
"description": "C# Entity Component System Framework",
"unity": "2020.3",
- "version": "0.9.20",
+ "version": "0.9.21",
"repository": {
"type": "git",
"url": "https://github.com/DCFApixels/DragonECS.git"
diff --git a/src/DebugUtils/TypeMeta.cs b/src/DebugUtils/TypeMeta.cs
index 7c3d8c9..0422993 100644
--- a/src/DebugUtils/TypeMeta.cs
+++ b/src/DebugUtils/TypeMeta.cs
@@ -370,6 +370,14 @@ namespace DCFApixels.DragonECS
#endregion
#region Other
+ public static void ClearCache()
+ {
+ lock (_lock)
+ {
+ _metaCache.Clear();
+ _metaCache.Add(typeof(void), NullTypeMeta);
+ }
+ }
ITypeMeta ITypeMeta.BaseMeta
{
get { return null; }
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index 75a3be2..0a2afc9 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -411,6 +411,10 @@ namespace DCFApixels.DragonECS
#endregion
#region Other
+ public static void ClearCache()
+ {
+ _staticMaskCache.Clear();
+ }
EcsMask IComponentMask.ToMask(EcsWorld world) { return _mask; }
#endregion
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 2ce52bb..b68ca3d 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -175,10 +175,6 @@ namespace DCFApixels.DragonECS
// тут сложно однозначно посчитать, так как нужно еще место под аспекты и запросы
int controllersCount = config.PoolsCapacity * 4;
_worldComponentPools = new StructList(controllersCount);
- if (controllersCount < _allWorldComponentPools.Capacity)
- {
- _allWorldComponentPools.Capacity = controllersCount;
- }
if (worldID < 0 || (worldID == NULL_WORLD_ID && nullWorld == false))
{
@@ -234,6 +230,13 @@ namespace DCFApixels.DragonECS
#endif
return;
}
+
+ for (int i = Entities.Count - 1; i >= 0; i--)
+ {
+ DelEntity(Entities[i]);
+ }
+ ReleaseDelEntityBufferAll();
+
_isDestroyed = true;
_listeners.InvokeOnWorldDestroy();
_entityDispenser = null;
@@ -253,7 +256,6 @@ namespace DCFApixels.DragonECS
//_entities - не обнуляется для работы entlong.IsAlive
}
}
- //public void Clear() { }
#endregion
#region Getters
diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs
index 033321a..91699e1 100644
--- a/src/EcsWorld.static.cs
+++ b/src/EcsWorld.static.cs
@@ -147,10 +147,7 @@ namespace DCFApixels.DragonECS
private static short _recycledItemsCount;
private static readonly IEcsWorldComponent _interface = EcsWorldComponentHandler.instance;
private static readonly Abstract _controller = new Abstract();
- static WorldComponentPool()
- {
- _allWorldComponentPools.Add(_controller);
- }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetItem(int itemIndex)
{// ts
diff --git a/src/Injections/Injector.cs b/src/Injections/Injector.cs
index df558b0..c68c965 100644
--- a/src/Injections/Injector.cs
+++ b/src/Injections/Injector.cs
@@ -357,6 +357,12 @@ namespace DCFApixels.DragonECS
instance.Inject(_injectedData);
}
}
+
+ internal static void Clear()
+ {
+ _Empty_Internal._injections.Clear();
+ _Empty_Internal._nodes.Clear();
+ }
}
#endregion
}
| |