From 0f3b1c1e1f1c2aa6ac97662099522f6469565fcf Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:04:56 +0800 Subject: [PATCH] update readme --- README-RU.md | 146 ++++++++++++++++++++++++++++++++++++++++----------- README-ZH.md | 2 +- README.md | 2 +- 3 files changed, 116 insertions(+), 34 deletions(-) diff --git a/README-RU.md b/README-RU.md index 926366f..ebddcc4 100644 --- a/README-RU.md +++ b/README-RU.md @@ -41,7 +41,7 @@
-DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system) фреймворк нацеленный на максимальную удобность, модульность, расширяемость и производительность динамического изменения сущностей. Разработан на чистом C#, без зависимостей и генерации кода. Вдохновлен [LeoEcs](https://github.com/Leopotam/ecslite). +DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system) фреймворк нацеленный на максимальную удобность, модульность, расширяемость и производительность динамического изменения сущностей. Разработан на чистом C#, без зависимостей и генерации кода. Вдохновлен [LeoEcs Lite](https://github.com/Leopotam/ecslite). > [!WARNING] > Проект предрелизной версии, поэтому API может меняться. В ветке main актуальная и рабочая версия.
@@ -58,7 +58,7 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system) - [Построение](#построение) - [Внедрение зависимостей](#внедрение-зависимостей) - [Модули](#модули) - - [Слои](#слои) + - [Сортировка](#сортировка) - [Процессы](#процессы) - [Мир](#мир) - [Пул](#пул) @@ -149,18 +149,17 @@ if (entity.TryGetID(out int entityID)) { } > **NOTICE:** Сущности не могут существовать без компонентов, пустые сущности будут автоматически удаляться сразу после удаления последнего компонента либо в конце тика. ## Component -**Компоненты** - это данные для сущностей. Обязаны реализовывать интерфейс `IEcsComponent` или другой указывающий вид компонента. +**Компоненты** - это данные которые крепятся к сущностям. ```c# +// Компоненты IEcsComponent хранятся в обычном хранилище. struct Health : IEcsComponent { public float health; public int armor; } +// Компоненты с IEcsTagComponent хранятся в оптимизированном для тегов хранилище. struct PlayerTag : IEcsTagComponent {} ``` -Встроенные виды компонентов: -* `IEcsComponent` - Компоненты с данными. Универсальный тип компонентов. -* `IEcsTagComponent` - Компоненты-теги. Без данных. ## System **Системы** - это основная логика, тут задается поведение сущностей. Существуют в виде пользовательских классов, реализующих как минимум один из интерфейсов процессов. Основные процессы: @@ -271,8 +270,10 @@ EcsPipeline pipeline = EcsPipeline.New() .BuildAndInit(); ``` -### Слои -Очередь систем можно разбить на слои. Слой определяет место в очереди для вставки систем. Например, если необходимо чтобы какая-то система была вставлена в конце очереди, вне зависимости от места добавления, эту систему можно добавить в слой EcsConsts.END_LAYER. +### Сортировка +Дла управления расположением систем в пайплайне, вне зависимости от порядка добавления, есть 2 способа: Слои и Порядок сортировки. +#### Слои +Слой определяет место в пайплайне для вставки систем. Например, если необходимо чтобы система была вставлена в конце пайплайна, эту систему можно добавить в слой `EcsConsts.END_LAYER`. ``` c# const string SOME_LAYER = nameof(SOME_LAYER); EcsPipeline pipeline = EcsPipeline.New() @@ -287,9 +288,20 @@ EcsPipeline pipeline = EcsPipeline.New() Встроенные слои расположены в следующем порядке: * `EcsConst.PRE_BEGIN_LAYER` * `EcsConst.BEGIN_LAYER` -* `EcsConst.BASIC_LAYER` (Если при добавлении системы не указать слой, то она будет добавлена сюда) +* `EcsConst.BASIC_LAYER` (По умолчанию системы добавляются сюда) * `EcsConst.END_LAYER` * `EcsConst.POST_END_LAYER` +#### Порядок сортировки +Для сортировки систем в рамках слоя используется int значение порядка сортировки. По умолчанию системы добавляются с sortOrder = 0. +``` c# +EcsPipeline pipeline = EcsPipeline.New() + // ... + // Система SomeSystem будет вставлена в слой EcsConsts.BEGIN_LAYER + // и расположена после систем с sortOrder меньше 10. + .Add(New SomeSystem(), EcsConsts.BEGIN_LAYER, 10) + // ... + .BuildAndInit(); +``` ## Процессы Процессы - это очереди систем реализующие общий интерфейс, например `IEcsRun`. Для запуска процессов используются Runner-ы. Встроенные процессы запускаются автоматически. Есть возможность реализации пользовательских процессов. @@ -345,17 +357,20 @@ _pipeline.GetRunnerInstance.Do() ## Мир -Является контейнером для сущностей и компонентов. +Контейнер для сущностей и компонентов. ``` c# // Создание экземпляра мира. _world = new EcsDefaultWorld(); + // Создание и удаление сущности по примеру из раздела Сущности. var e = _world.NewEntity(); _world.DelEntity(e); -``` -> **NOTICE:** Необходимо вызывать EcsWorld.Destroy() у экземпляра мира если он больше не используется, иначе он будет висеть в памяти. -### Конфигурация мира +// Уничтожение мира и освобождение ресурсов. Обязательно вызывать, иначе он будет висеть в памяти. +_world.Destroy(); +``` +> Миры изолированы друг от друга и могут обрабатываться в отдельных потоках. Но мультипоточная обработка одного мира поддерживается только при отсутсвии добавления/удаляения компонентов у сущностей. + Для инициализации мира сразу необходимого размера и сокращения времени прогрева, в конструктор можно передать экземпляр `EcsWorldConfig`. ``` c# @@ -363,14 +378,16 @@ EcsWorldConfig config = new EcsWorldConfig( // Предварительно инициализирует вместимость мира для 2000 сущностей. entitiesCapacity: 2000, // Предварительно инициализирует вместимость пулов для 2000 компонентов. - poolComponentsCapacity: 2000); + poolComponentsCapacity: 2000 + // ... Есть и другие параметры + ); _world = new EcsDefaultWorld(config); ``` ## Пул -Является хранилищем для компонентов, предоставляет методы для добавления/чтения/редактирования/удаления компонентов на сущности. Есть несколько видов пулов, для разных целей: +Хранилище для компонентов, пул предоставляет методы для добавления/чтения/редактирования/удаления компонентов на сущности. Есть несколько видов пулов, для разных видов компонентов: * `EcsPool` - универсальный пул, хранит struct-компоненты реализующие интерфейс `IEcsComponent`; -* `EcsTagPool` - специальный пул для пустых компонентов-тегов, хранит struct-компоненты с `IEcsTagComponent` как bool значения, что в сравнении с реализацией `EcsPool` имеет лучше оптимизацию памяти и скорости; +* `EcsTagPool` - специальный пул, оптимизированный под компоненты-теги, хранит struct-компоненты с `IEcsTagComponent`; Пулы имеют 5 основных метода и их разновидности: ``` c# @@ -392,12 +409,50 @@ if (poses.Has(entityID)) { /* ... */ } // Удалит компонент у сущности, бросит исключение если у сущности нет этого компонента. poses.Del(entityID); ``` +> [!WARNING] +> В `Release` сброке отключаются проверки на исключения. + > Есть "безопасные" методы, которые сначала выполнят проверку наличия/отсутствия компонента, названия таких методов начинаются с `Try`. > Имеется возможность реализации пользовательского пула. Эта функция будет описана в ближайшее время. +## Маска +Применяется для фильтрации сущностей по наличию или отсутствию компонентов. +``` c# +// Создание маски которая проверяет что у сущностей есть компоненты +// SomeCmp1 и SomeCmp2, но нет компонента SomeCmp3. +EcsMask mask = EcsMask.New(_world) + // Inc - Условие наличия компонента. + .Inc() + .Inc() + // Exc - Условие отсутствия компонента. + .Exc() + .Build(); +``` + +
+Статическая маска + +`EcsMask` привязаны к конкретным экземплярам мира которые необходимо передавать в `EcsMask.New(world)`, но есть `EcsStaticMask` которую можно создать без привязки к миру. + +``` c# +class SomeSystem : IEcsRun +{ + // EcsStaticMask можно создавать в статических полях. + static EcsStaticMask _staticMask = EcsStaticMask.Inc().Inc().Exc().Build(); + + // ... +} +``` +``` c# +// Конвертация в обычную маску. +EcsMask mask = _staticMask.ToMask(_world); +``` + +
+ ## Аспект -Это пользовательские классы наследуемые от `EcsAspect` и используемые для взаимодействия с сущностями. Аспекты одновременно являются кешем пулов и маской компонентов для фильтрации сущностей. Можно рассматривать аспекты как описание того с какими сущностями работает система. +Пользовательские классы наследуемые от `EcsAspect` и используемые для взаимодействия с сущностями. Аспекты одновременно являются кешем пулов и содержат маску. Можно рассматривать аспекты как описание того с какими сущностями работает система. Упрощенный синтаксис: ``` c# @@ -418,7 +473,9 @@ class Aspect : EcsAspect } ``` -Явный синтаксис (результат идентичен примеру выше): +
+Явный синтаксис (результат идентичен примеру выше): + ``` c# using DCFApixels.DragonECS; // ... @@ -435,6 +492,8 @@ class Aspect : EcsAspect } ``` +
+
Комбинирование аспектов @@ -470,16 +529,23 @@ class Aspect : EcsAspect
## Запросы -Что бы получить необходимый набор сущностей используется метод-запрос `EcsWorld.Where(out TAspect aspect)`. В качестве `TAspect` указывается аспект, сущности будут отфильтрованны по маске указанного аспекта. Запрос `Where` применим как к `EcsWorld` так и коллекциям фреймворка (в этом плане Where чем-то похож на аналогичный из Linq). -Пример: +Фильтруют сущности и выдают коллекции сущностей удовлетворяющие определенным условиям. Встроенный запрос `Where` фильтрует на соответствие условиям маски компонентов и имеет несколько перегрузок: ++ `EcsWorld.Where(EcsMask mask)` - Обычная фильтрация по маске; ++ `EcsWorld.Where(out TAspect aspect)` - Сочетает в себе фильтрацию по маске из аспекта и получение аспекта; + +Запрос `Where` применим как к `EcsWorld` так и коллекциям фреймворка (в этом плане Where чем-то похож на аналогичный из Linq). Так же имеются перегрузки для сортировки сущностей по `Comparison`. + +Пример системы: ``` c# public class SomeDamageSystem : IEcsRun, IEcsInject { class Aspect : EcsAspect { - public EcsPool healths = Inc; - public EcsPool damageSignals = Inc; + public EcsPool healths = Inc; + public EcsPool damageSignals = Inc; public EcsTagPool isInvulnerables = Exc; + // Наличие или отсутвие этого компонента не проверяется. + public EcsTagPool isDiedSignals = Opt; } EcsDefaultWorld _world; public void Inject(EcsDefaultWorld world) => _world = world; @@ -489,7 +555,15 @@ public class SomeDamageSystem : IEcsRun, IEcsInject foreach (var e in _world.Where(out Aspect a)) { // Сюда попадают сущности с компонентами Health, DamageSignal и без IsInvulnerable. - a.healths.Get(e).points -= a.damageSignals.Get(e).points; + ref var health = ref a.healths.Get(e); + if(health.points > 0) + { + health.points -= a.damageSignals.Get(e).points; + if(health.points <= 0) + { // Создаем сигнал другим системам о том что сущность умерла. + a.isDiedSignals.TryAdd(e); + } + } } } } @@ -689,6 +763,9 @@ using DCFApixels.DragonECS; // Добавляет описание типу. [MetaDescription("The quick brown fox jumps over the lazy dog")] + +// Добавляет строковый уникальный идентификатор. +[MetaID("8D56F0949201D0C84465B7A6C586DCD6")] // Строки должны быть уникальными, и не допускают символы ,<> . // Добавляет строковые теги. [MetaTags("Tag1", "Tag2", ...)] // [MetaTags(MetaTags.HIDDEN))] чтобы скрыть в редакторе @@ -700,17 +777,16 @@ TypeMeta typeMeta = someComponent.GetMeta(); // или TypeMeta typeMeta = pool.ComponentType.ToMeta(); -var name = typeMeta.Name; -var color = typeMeta.Color; -var description = typeMeta.Description; -var group = typeMeta.Group; -var tags = typeMeta.Tags; +var name = typeMeta.Name; // [MetaName] +var group = typeMeta.Group; // [MetaGroup] +var color = typeMeta.Color; // [MetaColor] +var description = typeMeta.Description; // [MetaDescription] +var metaID = typeMeta.MetaID; // [MetaID] +var tags = typeMeta.Tags; // [MetaTags] ``` ## EcsDebug -Имеет набор методов для отладки и логирования. Реализован как статический класс вызывающий методы Debug-сервисов. Debug-сервисы - это посредники между системами отладки среды и EcsDebug. Это позволяет не изменяя отладочный код проекта, переносить проект на другие движки, достаточно только реализовать соответствующий Debug-сервис. - -По умолчанию используется `DefaultDebugService` который выводит логи в консоль. Для реализации пользовательского создайте класс наследуемый от `DebugService` и реализуйте абстрактные члены класса. +Вспомогательный тип с набором методов для отладки и логирования. Реализован как статический класс вызывающий методы Debug-сервисов. Debug-сервисы - это посредники между EcsDebug и инструментами отладки среды. Такая реализация позволяет не изменяя отладочный код, менять его поведение или переносить проект в другие среды, достаточно только реализовать соответствующий Debug-сервис. ``` c# // Вывод лога. @@ -726,12 +802,17 @@ EcsDebug.Break(); EcsDebug.Set(); ``` +> По умолчанию используется `DefaultDebugService` который выводит логи в консоль. Для реализации пользовательского создайте класс наследуемый от `DebugService` и реализуйте абстрактные члены класса. + +> `EcsDebug` потокобезопасен, за счет того что каждый поток использует свой изолированный экземпляр сервиса. Экземпляры для потоков создаются в абстрактном методе `DebugService.CreateThreadInstance`. + ## Профилирование +За реализацию профайлера так же отвечает Debug-сервис. Для выделения участка кода используется `EcsProfilerMarker`; ``` c# // Создание маркера с именем SomeMarker. private static readonly EcsProfilerMarker marker = new EcsProfilerMarker("SomeMarker"); -... +// ... marker.Begin(); // Код для которого замеряется скорость. @@ -744,6 +825,7 @@ using (marker.Auto()) // Код для которого замеряется скорость. } ``` +> `DefaultDebugService` использует реализацию на основе `Stopwatch` и выводом в консоль.
diff --git a/README-ZH.md b/README-ZH.md index 1aa0314..40bbbcf 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -41,7 +41,7 @@
-DragonECS 是一个[实体组件系统](https://www.imooc.com/article/331544)框架。专注于提升便利性、模块性、可扩展性和动态实体修改性能。 用纯C#开发的,没有依赖和代码生成。灵感来自于[LeoEcs](https://github.com/Leopotam/ecslite)。 +DragonECS 是一个[实体组件系统](https://www.imooc.com/article/331544)框架。专注于提升便利性、模块性、可扩展性和动态实体修改性能。 用纯C#开发的,没有依赖和代码生成。灵感来自于[LeoEcs Lite](https://github.com/Leopotam/ecslite)。 > [!WARNING] > 该框架是预发布版本,因此 API 可能会有变化。在 `main` 分支中是当前的工作版本。
diff --git a/README.md b/README.md index 7c15fb3..aa39c02 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@
-The [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Framework aims to maximize usability, modularity, extensibility and performance of dynamic entity changes. Without code generation and dependencies. Inspired by [LeoEcs](https://github.com/Leopotam/ecslite). +The [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Framework aims to maximize usability, modularity, extensibility and performance of dynamic entity changes. Without code generation and dependencies. Inspired by [LeoEcs Lite](https://github.com/Leopotam/ecslite). > [!WARNING] > The project is a work in progress, API may change.