diff --git a/README-RU.md b/README-RU.md index 1cdad1c..e0b5d9a 100644 --- a/README-RU.md +++ b/README-RU.md @@ -14,9 +14,6 @@ Данный [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Фреймворк нацелен на максимальную удобность, модульность, расширяемость и производительность динамического изменения сущностей. Без генерации кода и зависимостей. Вднохновлен [LeoEcs](https://github.com/Leopotam/ecslite). -> [!IMPORTANT] -> 新年快乐! - > [!WARNING] > Проект в стадии разработки. API может меняться. > Readme еще не завершен @@ -35,18 +32,18 @@ - [Слои](#слои) - [Процессы](#процессы) - [Мир](#мир) - - [Компоненты мира](#компоненты-мира) - - [Конфигурация мира](#конфигурация-мира) - [Пул](#пул) - [Аспект](#аспект) - [Запросы](#запросы) - [Группа](#группа) - [Корень ECS](#корень-ecs) - - [Гибридность](#гибридность) - [Debug](#debug) - - [Атрибуты](#атрибуты) + - [Мета-Атрибуты](#мета-атрибуты) - [EcsDebug](#ecsdebug) - [Профилирование](#профилирование) +- [Расширение фреймворка](#расширение-фреймворка) + - [Компоненты мира](#компоненты-мира) + - [Конфиги](#конфиги) - [Расширения](#расширения) - [FAQ](#faq) - [Обратная связь](#обратная-связь) @@ -60,6 +57,7 @@ + Минимальная версия C# 7.3; Опционально: ++ Поддержка NativeAOT + Минимальная версия Unity 2020.1.0; ## Установка для Unity @@ -78,7 +76,7 @@ https://github.com/DCFApixels/DragonECS.git **Сущности** - это то к чему крепятся данные. Реализованы в виде идентификаторов, которых есть 2 вида: * `int` - однократный идентификатор, применяется в пределах одного тика. Не рекомендуется хранить `int` идентификаторы, в место этого используйте `entlong`; * `entlong` - долговременный идентификатор, содержит в себе полный набор информации для однозначной идентификации; -``` csharp +``` c# // Создание новой сущности в мире. int entityID = _world.NewEntity(); @@ -95,7 +93,7 @@ int newEntityID = _world.CloneEntity(entityID);
Работа с entlong -``` csharp +``` c# // Конвертация int в entlong. entlong entity = _world.GetEntityLong(entityID); // или @@ -125,14 +123,13 @@ struct Health : IEcsComponent struct PlayerTag : IEcsTagComponent {} ``` Встроенные виды компонентов: -* `IEcsComponent` - Компоненты с данными. +* `IEcsComponent` - Компоненты с данными. Универсальный тип компонентов. * `IEcsTagComponent` - Компоненты-теги. Без данных. -* `IEcsHybridComponent` - Гибридные компоненты. Испольщуются для реализации [гибридности](#Гибридность). ## System **Системы** - это основная логика, тут задается поведение сущностей. Существуют в виде пользовательских классов, реализующих как минимум один из интерфейсов процессов. Основные процессы: ```c# -class SomeSystem : IEcsPreInitProcess, IEcsInitProcess, IEcsRunProcess, IEcsDestroyProcess +class SomeSystem : IEcsPreInit, IEcsInit, IEcsRun, IEcsDestroy { // Будет вызван один раз в момент работы EcsPipeline.Init() и до срабатывания IEcsInitProcess.Init() public void PreInit () { } @@ -170,46 +167,31 @@ pipeline.Init(); // Инициализация пайплайна ``` > Для одновременного построения и инициализации есть метод Builder.BuildAndInit(); ### Внедрение зависимостей -Внедрение зависимостей - это процесс который запускается вместе с инициализацией пайплайна и внедряет данные переданные в Builder. - -> [!WARNING] -> Внедрение идет параллельно с PreInit, поэтому в PreInit инъекция - не гарантируется. - -> [!WARNING] -> Экземпляр EcsPipeline автоматически внедряется еще до PreInit. +Фреймворк реализует внедрение зависимостей для систем. это процесс который запускается вместе с инициализацией пайплайна и внедряет данные переданные в Builder. +> Использование встроенного внедрения зависимостей опционально. ``` c# -SomeData _someData; +class SomeDataA { /*...*/ } +class SomeDataB : SomeDataA { /*...*/ } + //... +SomeDataB _someDataB = new SomeDataB(); EcsPipelone pipeline = EcsPipeline.New() //... - .Inject(_someData) // Внедрит в системы экземпляр _someData + // Внедрит _someDataB в системы реализующие IEcsInject. + .Inject(_someDataB) + // Добавит системы реализующие IEcsInject в дерево инъекции + // теперь эти системы так же получат _someDataB. + .Injector.AddNode() // //... .BuildAndInit(); //... - -class SomeSystem : IEcsInject, IEcsRunProcess +// Для внедрения используется интерфейс IEcsInject и его метод Inject(T obj) +class SomeSystem : IEcsInject, IEcsRunProcess { - // Для внедрения используется интерфейс IEcsInject и его метод Inject(T obj) - SomeData _someData - public void Inject(SomeData obj) => _someData = obj; - - public void PreInit () - { - // тут возможно еще не внедрен _someData - } - public void Init () - { - // тут можно пользовать _someData - } - public void Run () - { - // тут можно пользовать _someData - } - public void Destroy () - { - // тут можно пользовать _someData - } + SomeDataA _someDataA + //obj будет экземпляром типа SomeDataB + public void Inject(SomeDataA obj) => _someDataA = obj; } ``` ### Модули @@ -226,7 +208,7 @@ class Module : IEcsModule } } ``` -``` csharp +``` c# EcsPipelone pipeline = EcsPipeline.New() //... .AddModule(new Module()) @@ -252,118 +234,78 @@ EcsPipelone pipeline = EcsPipeline.New() * `EcsConst.POST_END_LAYER` ## Процессы -Процессы - это очереди систем реализующие общий интерфейс, например `IEcsRunProcess`. Для запуска процессов используются Runner-ы. Встроенные процессы вызываются автоматически, для запуска пользовательских процессов используйте раннеры получаемые из `EcsPipeline.GetRunner()`. -> Рекомендуется кешировать полученные через GetRunner раннеры. +Процессы - это очереди систем реализующие общий интерфейс, например `IEcsRun`. Для запуска процессов используются Runner-ы. Втроенные процессы запускаются автоматически. Есть возможность реализации пользовательских процессов.
Встроенные процессы -* `IEcsPreInitProcess`, `IEcsInitProcess`, `IEcsRunProcess`, `IEcsDestroyProcess` - процессы жизненого цикла `EcsPipeline`. -* `IEcsPreInject`, `IEcsInject` - Процессы системы [внедрения зависимостей](#Внедрение-зависимостей). -* `IEcsPreInitInjectProcess` - Так же процесс системы [внедрения зависимостей](#Внедрение-зависимостей), но работает в пределах до выполнения IEcsInitProcess, сигнализирует о начале и окончании предварительных внедрений. +* `IEcsPreInit`, `IEcsInit`, `IEcsRun`, `IEcsDestroy` - процессы жизненого цикла `EcsPipeline`. +* `IEcsInject` - Процессы системы [внедрения зависимостей](#Внедрение-зависимостей). +* `IOnInitInjectionComplete` - Так же процесс системы [внедрения зависимостей](#Внедрение-зависимостей), но сигнализирует о завершении инициализирующей инъекции.
Пользовательские процессы -Для добавления нового процесса создайте интерфейс наследованный от `IEcsProcess` и создайте раннер для него. Раннер это класс реализующий интерфейс запускаемого процесса и наследуемый от EcsRunner. А после к интерфейсу добавте атрибут `BindWithEcsRunner` для связи. Пример: - ```c# -[BindWithEcsRunner(typeof(DoSomethingProcessRunner))] +Для добавления нового процесса создайте интерфейс наследованный от `IEcsProcess` и создайте раннер для него. Раннер это класс реализующий интерфейс запускаемого процесса и наследуемый от `EcsRunner`. Пример: +``` c# +//Интерфейс. interface IDoSomethingProcess : IEcsProcess { void Do(); } +//Реализация раннера. Пример реализации можно так же посмотреть в встроенных процессах sealed class DoSomethingProcessRunner : EcsRunner, IDoSomethingProcess { - public void Do() + public void Do() { - foreach (var item in targets) item.Do(); + foreach (var item in Process) item.Do(); } } +//... + +//Добавление раннера при создании пайплайна. +_pipeline = EcsPipeline.New() + //... + .AddRunner() + //... + .BuildAndInit(); + +//Запуск раннера если раннер был добавлен. +_pipeline.GetRunner.Do() + +//Или если раннер небыл добавлен(Вызов GetRunnerInstance так же добавит раннер в пайплайн). +_pipeline.GetRunnerInstance.Do() ``` > Раннеры имеют ряд требований к реализации: -> * Для одного интерфейса может быть только одна реализация раннера; -> * Наследоваться от `EcsRunner` можно только напрямую; -> * Раннер может содержать только один интерфейс(за исключением `IEcsSystem`); -> * Наследуемый класс `EcsRunner,` в качестве `TInterface` должен принимать реализованный интерфейс; -> * Раннер не может быть размещен внутри другого класса. +> * Наследоваться от `EcsRunner` можно только напрямую; +> * Раннер может содержать только один интерфейс(за исключением `IEcsProcess`); +> * Наследуемый класс `EcsRunner,` далжен так же реализовавыть интерфейс `T`; +> Не рекомендуется в цикле вызывать `GetRunner`, иначе кешируйте полученный раннер.
## Мир Является контейнером для сущностей и компонентов. -> **NOTICE:** Необходимо вызывать EcsWorld.Destroy() у экземпляра мира если он больше не нужен. -### Компоненты мира -С помощью компонентов можно прикреплять дополнительные данные к мирам. В качестве компонентов используются `struct` типы. -``` csharp -ref WorldComponent component = ref _world.Get(); +``` c# +//Создание экземпляра мира +_world = new EcsDefaultWorld(); +//Пример из раздела Сущности +var e = _world.NewEntity(); +_world.DelEntity(e); ``` -Реализация компонента: -``` csharp -public struct WorldComponent -{ - // Данные. -} -``` -Или: -``` csharp -public struct WorldComponent : IEcsWorldComponent -{ - // Данные. - void IEcsWorldComponent.Init(ref WorldComponent component, EcsWorld world) - { - // Действия при инициализации компонента. Вызывается до первого возвращения из EcsWorld.Get - } - void IEcsWorldComponent.OnDestroy(ref WorldComponent component, EcsWorld world) - { - // Действия когда вызывается EcsWorld.Destroy. - // Вызов OnDestroy, обязует пользователя вручную обнулять компонент, если это необходимо. - component = default; - } -} -``` - -
-Пример использования - -События интерфейса IEcsWorldComponent, могут быть использованы для автоматической инициализации полей компонента, и освобождения ресурсов. -``` csharp -public struct WorldComponent : IEcsWorldComponent -{ - private SomeClass _object; // Объект который будет утилизироваться. - private SomeReusedClass _resusedObject; // Объект который будет переиспользоваться. - public SomeClass Object => _object; - public SomeReusedClass ResusedObject => _resusedObject; - void IEcsWorldComponent.Init(ref WorldComponent component, EcsWorld world) - { - if (component._resusedObject == null) - component._resusedObject = new SomeReusedClass(); - component._object = new SomeClass(); - // Теперь при получении компонента через EcsWorld.Get, _resusedObject и _object уже будут созданы. - } - void IEcsWorldComponent.OnDestroy(ref WorldComponent component, EcsWorld world) - { - // Утилизируем не нужный объект, и освобождаем ссылку на него, чтобы GC мог его собрать. - component._object.Dispose(); - component._object = null; - - // Как вариант тут можно сделать сброс значений у переиспользуемого объекта. - //component._resusedObject.Reset(); - - //Так как в этом примере не нужно полное обнуление компонента, то строчка ниже не нужна. - //component = default; - } -} -``` -
+> **NOTICE:** Необходимо вызывать EcsWorld.Destroy() у экземпляра мира если он больше не используется, иначе он будет висеть в памяти. ### Конфигурация мира -При создании мира, в конструктор можно передать реализацию интерфейса `IEcsWorldConfig`. Реализующие его классы своего рода контейнеры для конфигов. По умолчанию уже реализован стандартный контейнер `EcsWorldConfig` и `Get`/`Set` методы для базовой конфигурации мира. +При создании мира, в конструктор можно передать экземпляр `EcsWorldConfig`. -``` csharp -EcsWorldConfig config = new EcsWorldConfig() - .Set_EntitiesCapacity(512); +``` c# +EcsWorldConfig config = new EcsWorldConfig( + //предварительно инициализирует вместимость мира для 2000 сущностей + entitiesCapacity: 2000, + //предварительно инициализирует вместимость пулов для 2000 компонентов + poolComponentsCapacity: 2000); _world = new EcsDefaultWorld(config); ``` @@ -371,11 +313,10 @@ _world = new EcsDefaultWorld(config); ## Пул Является контейнером для компонентов, предоставляет методы для добавления/чтения/редактирования/удаления компонентов на сущности. Есть несколько видов пулов, для разных целей: * `EcsPool` - универсальный пул, хранит struct-компоненты реализующие интерфейс `IEcsComponent`; -* `EcsTagPool` - подходит для хранения пустых компонентов-тегов, в сравнении с `EcsPool` имеет лучше оптимизацию памяти и скорости, хранит struct-компоненты `IEcsTagComponent`; -* `EcsHybridPool` - пул для гибридных компонентов. Испольщуются для реализации [гибридности](#Гибридность), хранит struct-компоненты `IEcsHybridComponent`; +* `EcsTagPool` - подходит для хранения пустых компонентов-тегов, в сравнении с `EcsPool` имеет лучше оптимизацию памяти и скорости, хранит struct-компоненты с `IEcsTagComponent`; Пулы имеют 5 основных метода и их разновидности: -``` csharp +``` c# // Один из способов получить пул из мира. EcsPool poses = _world.GetPool(); @@ -401,7 +342,7 @@ poses.Del(entityID); ## Аспект Это пользовательские классы наследуемые от `EcsAspect`, которые используются как посредник для взаимодействия с сущностями. Аспекты одновременно являются кешем пулов и ограничением для фильтрации сущностей. -``` csharp +``` c# using DCFApixels.DragonECS; ... class Aspect : EcsAspect @@ -424,7 +365,7 @@ class Aspect : EcsAspect } ``` В аспекты можно добавлять другие аспекты, тем самым комбинируя их. Ограничения так же будут скомбинированы -``` csharp +``` c# using DCFApixels.DragonECS; ... class Aspect : EcsAspect @@ -458,7 +399,7 @@ class Aspect : EcsAspect Используйте метод-запрос `EcsWorld.Where(out TAspcet aspect)` для получения необходимого системе набора сущностей. Запросы работают в связке с аспектами, аспекты определяют ограничения запросов, результатом запроса становится группа сущностей удовлетворяющая условиям аспекта. По умолчанию запрос делает выборку из всех сущностей в мире, но так же можно сделать выборку из определенной группы сущностей, для этого используйте `EcsWorld.WhereFor(EcsReadonlyGroup sourceGroup, out TAspcet aspect)` ## Группа -Группы это структуры данных для хранения множества сущностей с быстрыми операциями добавления/удаления/проверки наличия и т.д. Реализованы классом `EcsGroup` и структурой `EcsReadonlyGroup`. +Группы это структуры данных для хранения множества сущностей с O(1) операциями добавления/удаления/проверки наличия и т.д. Реализованы классом `EcsGroup` и структурой `EcsReadonlyGroup`. ``` c# //Получем новую группу. EcsWorld содержит в себе пул групп, @@ -514,7 +455,7 @@ EcsGroup newGroup = EcsGroup.Inverse(groupA); ## Корень ECS Это пользовательский класс который явялестя точкой входа для ECS. Основное назначение инициализация, запуск систем на каждый Update движка и очистка по окончанию сипользования. ### Пример для Unity -``` csharp +``` c# using DCFApixels.DragonECS; using UnityEngine; public class EcsRoot : MonoBehaviour @@ -560,7 +501,7 @@ public class EcsRoot : MonoBehaviour } ``` ### Общий пример -``` csharp +``` c# using DCFApixels.DragonECS; public class EcsRoot { @@ -609,94 +550,12 @@ public class EcsRoot } } ``` -## Гибридность -Для смешивания архитектурных подходов классического OOP и ECS используется специальный пул `EcsHybridPool`. Принцип работы этого пула несколько отличается от других и он упрощает поддержу наследования и полиморфизма. - -
-Как это работает? - -При добавлении элемента в пул, пул сканирует его иерархию наследования и реализуемые интерфейсы в поиске типов у которых есть интерфес `IEcsHybridComponent` и автоматически добавляет компонент в соответсвующие этим типам пулы. Таким же образом происходит удаление. Сканирвоание просиходит не для типа T а для типа экземпляра, поэтому в примере ниже строчка в `_world.GetPool().Add(entity, _rigidbody);` добавляет не только в пул `EcsHybridPool` но и в остальные. - -
- -Пример использования: -``` csharp -public interface ITransform : IEcsHybridComponent -{ - Vector3 Position { get; set; } - // ... -} -public class Transform : ITransform -{ - public Vector3 Position { get; set; } - // ... -} -public class Rigidbody : Transform -{ - public Vector3 Position { get; set; } - public float Mass { get; set; } - // ... -} -public class Camera : ITransform -{ - Vector3 Position { get; set; } - // ... -} -public TransformAspect : EcsAspect -{ - public EcsHybridPool transforms; - public Aspect(Builder b) - { - transforms = b.Include(); - } -} -// ... - -EcsWorld _world; -Rigidbody _rigidbody; -// ... - -// Создадим пустую сущность. -int entity = _world.NewEmptyEntity(); -// Получаем пул EcsHybridPool и добавляем в него для сущности компонент _rigidbody. -// Если вместо ITransform подставить Transform или Rigidbody, то результат будет одинаковый -_world.GetPool().Add(entity, _rigidbody); -// ... - -//Все эти строчки вернут экземпляр _rigidbody. -ITransform iTransform = _world.GetPool().Get(entity); -Transform transform = _world.GetPool().Get(entity); -Rigidbody rigidbody = _world.GetPool().Get(entity); -//Исключение - отсутсвует компонент. Camera не является наследником или наследуемым классом для _rigidbody. -Camera camera = _world.GetPool().Get(entity); - -//Вернет True. Поэтому фишка гибридных пулов будет работать и в запросах сущностей -bool isMatches = _world.GetAspect().IsMatches(entity); - -//Все эти строчки вернут True. -bool isITransform = _world.GetPool().Has(entity); -bool isTransform = _world.GetPool().Has(entity); -bool isRigidbody = _world.GetPool().Has(entity); -//Эта строчка вернет False. -bool isCamera = _world.GetPool().Has(entity); -// ... - -// Удалим у сущности компонент. -_world.GetPool().Del(entity); -// ... -//Все эти строчки вернут False. -bool isITransform = _world.GetPool().Has(entity); -bool isTransform = _world.GetPool().Has(entity); -bool isRigidbody = _world.GetPool().Has(entity); -bool isCamera = _world.GetPool().Has(entity); -// ... -```
# Debug Фреймворк предоставляет дополнительные инструменты для отладки и логирования, не зависящие от среды. Так же многие типы имеют свой DebuggerProxy для более информативного отображения в IDE. -## Атрибуты +## Мета-Атрибуты В чистом виде мета-атрибуты не имеют применения, но могут быть использованы для генерации автоматической документации и используются в интеграциях с движками для задания отображения в отладочных инструментах и редакторах. ``` c# using DCFApixels.DragonECS; @@ -708,21 +567,41 @@ using DCFApixels.DragonECS; [MetaGroup("Abilities/Passive/")] // Задает цвет типа в системе rgb, где каждый канал принимает значение от 0 до 255, по умолчанию белый. -[MetaColor(MetaColor.Red)] // или [DebugColor(255, 0, 0)] +[MetaColor(MetaColor.Red)] // или [MetaColor(255, 0, 0)] // Добавляет описание типу. [MetaDescription("The quick brown fox jumps over the lazy dog")] // Добавляет строковые теги. -[MetaTags(...)] // [MetaTags(MetaTags.HIDDEN))] чтобы скрыть в редакторе +[MetaTags("Tag1", "Tag2", ...)] // [MetaTags(MetaTags.HIDDEN))] чтобы скрыть в редакторе public struct Component { } ``` +Получение мета-информации. С помощью TypeMeta: +``` c# +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; +``` +С помощью EcsDebugUtility: +``` c# +EcsDebugUtility.GetMetaName(someComponent); +EcsDebugUtility.GetColor(someComponent); +EcsDebugUtility.GetDescription(someComponent); +EcsDebugUtility.GetGroup(someComponent); +EcsDebugUtility.GetTags(someComponent); +``` ## EcsDebug Имеет набор методов для отладки и логирования. Реализован как статический класс вызывающий методы Debug-сервисов. Debug-сервисы - это посредники между системами отладки среды и EcsDebug. Это позволяет не изменяя отладочный код проекта, переносить проект на другие движки, достаточно только реализовать специальный Debug-сервис. По умолчанию используется `DefaultDebugService` который выводит логи в консоль. Для реализации пользовательского создайте класс наследуемый от `DebugService` и реализуйте абстрактные члены класса. -``` csharp +``` c# // Логирование. EcsDebug.Print("Message"); @@ -737,7 +616,7 @@ EcsDebug.Set(); ``` ## Профилирование -``` csharp +``` c# // Создание маркера с именем SomeMarker. private static readonly EcsProfilerMarker marker = new EcsProfilerMarker("SomeMarker"); @@ -757,6 +636,96 @@ using (marker.Auto())
+# Расширение фреймворка +Для большей расширемости фреймворкеа есть дополнительные инструменты. + +## Конфиги +Конструкторы классов `EcsWorld` и `EcsPipeline` могут принимать контейнеры конфигов реализующие интерфейс `IConfigContainer` или `IConfigContainerWriter`. С помощью этих контейнеров можно передавать данные и зависимости. Встроенная реализация контейнера - `ConfigContainer`
+Пример использования конфигов для мира: +``` c# +var configs = new ConfigContainer() + .Set(new EcsWorldConfig(entitiesCapacity: 2000, poolsCapacity: 2000) + .Set(new SomeDataA(/* ... */)) + .Set(new SomeDataB(/* ... */))); +EcsDefaultWorld _world = new EcsDefaultWorld(configs); +``` +Пример использования конфигов для пайплайна: +``` c# +_pipeline = EcsPipeline.New()// аналогично _pipeline = EcsPipeline.New(new ConfigContainer()) + .Configs.Set(new SomeDataA(/* ... */)) + .Configs.Set(new SomeDataB(/* ... */)) + //... + .BuildAndInit(); +//... +var _someDataA = _pipeline.Configs.Get(); +``` + +## Компоненты Миры +С помощью компонентов можно прикреплять дополнительные данные к мирам. В качестве компонентов используются `struct` типы. +``` c# +ref WorldComponent component = ref _world.Get(); +``` +Реализация компонента: +``` c# +public struct WorldComponent +{ + // Данные. +} +``` +Или: +``` c# +public struct WorldComponent : IEcsWorldComponent +{ + // Данные. + void IEcsWorldComponent.Init(ref WorldComponent component, EcsWorld world) + { + // Действия при инициализации компонента. Вызывается до первого возвращения из EcsWorld.Get + } + void IEcsWorldComponent.OnDestroy(ref WorldComponent component, EcsWorld world) + { + // Действия когда вызывается EcsWorld.Destroy. + // Вызов OnDestroy, обязует пользователя вручную обнулять компонент, если это необходимо. + component = default; + } +} +``` + +
+Пример использования + +События интерфейса IEcsWorldComponent, могут быть использованы для автоматической инициализации полей компонента, и освобождения ресурсов. +``` c# +public struct WorldComponent : IEcsWorldComponent +{ + private SomeClass _object; // Объект который будет утилизироваться. + private SomeReusedClass _resusedObject; // Объект который будет переиспользоваться. + public SomeClass Object => _object; + public SomeReusedClass ResusedObject => _resusedObject; + void IEcsWorldComponent.Init(ref WorldComponent component, EcsWorld world) + { + if (component._resusedObject == null) + component._resusedObject = new SomeReusedClass(); + component._object = new SomeClass(); + // Теперь при получении компонента через EcsWorld.Get, _resusedObject и _object уже будут созданы. + } + void IEcsWorldComponent.OnDestroy(ref WorldComponent component, EcsWorld world) + { + // Утилизируем не нужный объект, и освобождаем ссылку на него, чтобы GC мог его собрать. + component._object.Dispose(); + component._object = null; + + // Как вариант тут можно сделать сброс значений у переиспользуемого объекта. + //component._resusedObject.Reset(); + + //Так как в этом примере не нужно полное обнуление компонента, то строчка ниже не нужна. + //component = default; + } +} +``` +
+ +
+ # Расширения * [Автоматическое внедрение зависимостей](https://github.com/DCFApixels/DragonECS-AutoInjections) * [Поддержка классической C# многопоточности](https://github.com/DCFApixels/DragonECS-ClassicThreads) diff --git a/README.md b/README.md index 6866760..94127d8 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,34 @@ 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). -> [!IMPORTANT] -> 新年快乐! - > [!WARNING] > The project is a work in progress, API may change. > > While the English version of the README is incomplete, you can view the [Russian version](https://github.com/DCFApixels/DragonECS/blob/main/README-RU.md). -# Versioning -DragonECS uses this versioning semantics: [Open](https://gist.github.com/DCFApixels/c3b178a308b411f530361d1d56f1f929#file-dcfapixels_versioning_en-md) +
+ +# Installation +Versioning semantics - [Open](https://gist.github.com/DCFApixels/e53281d4628b19fe5278f3e77a7da9e8#file-dcfapixels_versioning_ru-md) +## Environment +Requirements: ++ Minimum C# version 7.3; + +Optional: ++ NativeAOT support; ++ Minimum Unity version 2020.1.0; + +## Unity Installation +* ### Unity Package +The framework can be installed as a Unity package by adding the Git URL [in the PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) or manually adding it to `Packages/manifest.json`: +``` +https://github.com/DCFApixels/DragonECS.git +``` +* ### Source Code +The framework can also be added to the project as source code. + +
+ # Extensions * [Dependency autoinjections](https://github.com/DCFApixels/DragonECS-AutoInjections) * [Classic C# multithreading support](https://github.com/DCFApixels/DragonECS-ClassicThreads) diff --git a/package.json b/package.json index 51cafba..85c9369 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "displayName": "DragonECS", "description": "C# Entity Component System Framework", "unity": "2020.3", - "version": "0.8.8", + "version": "0.8.20", "repository": { "type": "git", "url": "https://github.com/DCFApixels/DragonECS.git"