{"id":13533920,"url":"https://github.com/Leopotam/ecs","last_synced_at":"2025-04-01T22:31:02.457Z","repository":{"id":39351573,"uuid":"472468633","full_name":"Leopotam/ecs","owner":"Leopotam","description":null,"archived":true,"fork":false,"pushed_at":"2023-06-22T09:06:28.000Z","size":110,"stargazers_count":195,"open_issues_count":0,"forks_count":28,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-02T21:31:41.357Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://leopotam.com","language":"C#","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Leopotam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-03-21T18:44:39.000Z","updated_at":"2024-10-30T11:22:28.000Z","dependencies_parsed_at":"2024-01-03T04:14:32.505Z","dependency_job_id":null,"html_url":"https://github.com/Leopotam/ecs","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leopotam%2Fecs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leopotam%2Fecs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leopotam%2Fecs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leopotam%2Fecs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Leopotam","download_url":"https://codeload.github.com/Leopotam/ecs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246720459,"owners_count":20822907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:01:24.333Z","updated_at":"2025-04-01T22:31:02.189Z","avatar_url":"https://github.com/Leopotam.png","language":"C#","readme":"# LeoECS - Легковесный C# Entity Component System фреймворк\nПроизводительность, нулевые или минимальные аллокации, минимизация использования памяти, отсутствие зависимостей от любого игрового движка - это основные цели данного фреймворка.\n\n\u003e **ВАЖНО!** РАЗРАБОТКА ДАННОГО ПРОЕКТА ПРЕКРАЩЕНА, ВМЕСТО НЕГО СЛЕДУЕТ ИСПОЛЬЗОВАТЬ [EcsProto](https://leopotam.com/28/) или [EcsLite](https://github.com/Leopotam/ecslite).\n\n\u003e **ВАЖНО!** Не забывайте использовать `DEBUG`-версии билдов для разработки и `RELEASE`-версии билдов для релизов: все внутренние проверки/исключения будут работать только в `DEBUG`-версиях и удалены для увеличения производительности в `RELEASE`-версиях.\n\n\u003e **ВАЖНО!** LeoEcs-фрейморк **не потокобезопасен** и никогда не будет таким! Если вам нужна многопоточность - вы должны реализовать ее самостоятельно и интегрировать синхронизацию в виде ecs-системы.\n\n\n# Содержание\n* [Социальные ресурсы](#Социальные-ресурсы)\n* [Установка](#Установка)\n    * [В виде unity модуля](#В-виде-unity-модуля)\n    * [В виде исходников](#В-виде-исходников)\n* [Основные типы](#Основные-типы)\n    * [Компонент](#Компонент)\n    * [Сущность](#Сущность)\n    * [Система](#Система)\n* [Инъекция данных](#Инъекция-данных)\n* [Специальные типы](#Специальные-типы)\n    * [EcsFilter\u003cT\u003e](#EcsFilterT)\n    * [EcsWorld](#EcsWorld)\n    * [EcsSystems](#EcsSystems)\n* [Интеграция с движками](#Интеграция-с-движками)\n    * [Unity](#Unity)\n    * [Кастомный движок](#Кастомный-движок)\n* [Статьи](#Статьи)\n* [Проекты, использующие LeoECS](#Проекты-использующие-LeoECS)\n    * [С исходниками](#С-исходниками)\n* [Расширения](#Расширения)\n* [Лицензия](#Лицензия)\n* [ЧаВо](#ЧаВо)\n\n# Социальные ресурсы\n[![discord](https://img.shields.io/discord/404358247621853185.svg?label=enter%20to%20discord%20server\u0026style=for-the-badge\u0026logo=discord)](https://discord.gg/5GZVde6)\n\n# Установка\n\n## В виде unity модуля\nПоддерживается установка в виде unity-модуля через git-ссылку в PackageManager или прямое редактирование `Packages/manifest.json`:\n```\n\"com.leopotam.ecs\": \"https://github.com/Leopotam/ecs.git\",\n```\nПо умолчанию используется последняя релизная версия. Если требуется версия \"в разработке\" с актуальными изменениями - следует переключиться на ветку `develop`:\n```\n\"com.leopotam.ecs\": \"https://github.com/Leopotam/ecs.git#develop\",\n```\n\n## В виде исходников\nКод так же может быть склонирован или получен в виде архива со страницы релизов.\n\n# Основные типы\n\n## Компонент\nЯвляется контейнером для данных пользователя и не должен содержать логику (допускаются минимальные хелперы, но не куски основной логики):\n```c#\nstruct WeaponComponent {\n    public int Ammo;\n    public string GunName;\n}\n```\n\n## Сущность\nСама по себе ничего не значит и не существует, является исключительно контейнером для компонентов. Реализована как `EcsEntity`:\n```c#\n// NewEntity() используется для создания новых сущностей в контексте мира.\nEcsEntity entity = _world.NewEntity ();\n\n// Get() возвращает существующий на сущности компонент. Если компонент не существовал - он будет добавлен автоматически.\n// Следует обратить внимание на \"ref\" - компоненты должны обрабатываться по ссылке.\nref Component1 c1 = ref entity.Get\u003cComponent1\u003e ();\nref Component2 c2 = ref entity.Get\u003cComponent2\u003e ();\n\n// Del() удаляет компонент с сущности. Если это был последний компонент - сущность будет удалена автоматически. Если компонент не существовал - ошибки не будет.\nentity.Del\u003cComponent2\u003e ();\n\n// Replace() выполняет замену компонента новым экземпляром. Если старый компонент не существовал - новый будет добавлен без ошибки.\nWeaponComponent weapon = new WeaponComponent () { Ammo = 10, GunName = \"Handgun\" };\nentity.Replace (weapon);\n\n// Replace() позволяет выполнять \"чейнинг\" создания компонентов:\nEcsEntity entity2 = world.NewEntity ();\nentity2.Replace (new Component1 { Id = 10 }).Replace (new Component2 { Name = \"Username\" });\n\n// Любая сущность может быть скопирована вместе с компонентами:\nEcsEntity entity2Copy = entity2.Copy ();\n\n// Любая сущность может \"передать\" свои компоненты другой сущности (сама будет уничтожена):\nvar newEntity = world.NewEntity ();\nentity2Copy.MoveTo (newEntity); // все компоненты с \"entity2Copy\" переместятся на \"newEntity\", а \"entity2Copy\" будет удалена.\n\n// Любая сущность может быть удалена, при этом сначала все компоненты будут автоматически удалены и только потом энтити будет считаться уничтоженной. \nentity.Destroy ();\n```\n\n\u003e **ВАЖНО!** Сущности не могут существовать без компонентов и будут автоматически уничтожаться при удалении последнего компонента на них.\n\n## Система\nЯвляется контейнером для основной логики для обработки отфильтрованных сущностей. Существует в виде пользовательского класса, реализующего как минимум один из `IEcsInitSystem`, `IEcsDestroySystem`, `IEcsRunSystem` (и прочих поддерживаемых) интерфейсов:\n```c#\nclass UserSystem : IEcsPreInitSystem, IEcsInitSystem, IEcsRunSystem, IEcsDestroySystem, IEcsPostDestroySystem {\n    public void PreInit () {\n        // Будет вызван один раз в момент работы EcsSystems.Init() и до срабатывания IEcsInitSystem.Init().\n    }\n\n    public void Init () {\n        // Будет вызван один раз в момент работы EcsSystems.Init() и после срабатывания IEcsPreInitSystem.PreInit().\n    }\n    \n    public void Run () {\n        // Будет вызван один раз в момент работы EcsSystems.Run().\n    }\n\n    public void Destroy () {\n        // Будет вызван один раз в момент работы EcsSystems.Destroy() и до срабатывания IEcsPostDestroySystem.PostDestroy().\n    }\n\n    public void PostDestroy () {\n        // Будет вызван один раз в момент работы EcsSystems.Destroy() и после срабатывания IEcsDestroySystem.Destroy().\n    }\n}\n```\n\n# Инъекция данных\nВсе поля **ecs-систем**, совместимые c `EcsWorld` и `EcsFilter\u003cT\u003e` будут автоматически инициализированы валидными экземплярами соответствующих типов:\n```c#\nclass HealthSystem : IEcsSystem {\n    // Поля с авто-инъекцией.\n    EcsWorld _world;\n    EcsFilter\u003cWeaponComponent\u003e _weaponFilter;\n}\n```\n\nЭкземпляр любого кастомного типа (класса) может быть инъецирован с помощью метода `EcsSystems.Inject()`:\n```c#\nclass SharedData {\n    public string PrefabsPath;\n}\n...\nSharedData sharedData = new SharedData { PrefabsPath = \"Items/{0}\" };\nEcsSystems systems = new EcsSystems (world);\nsystems\n    .Add (new TestSystem1 ())\n    .Inject (sharedData)\n    .Init ();\n```\n\nКаждая система будет просканирована на наличие полей, совместимых по типу с последующей инъекцией:\n```c#\nclass TestSystem1 : IEcsInitSystem {\n    // Поле с авто-инъекцией.\n    SharedData _sharedData;\n    \n    public void Init() {\n        var prefabPath = string.Format (_sharedData.Prefabspath, 123);\n        // prefabPath = \"Items/123\" к этому моменту.\n    } \n}\n```\n\u003e **ВАЖНО!** Для инъекции подходят только нестатичные public/private-поля конечного класса системы, либо public/protected-поля базовых классов. Все остальные поля будут проигнорированы!\n\n# Специальные типы\n\n## EcsFilter\u003cT\u003e\nЯвляется контейнером для хранения отфильтрованных сущностей по наличию или отсутствию определенных компонентов:\n```c#\nclass WeaponSystem : IEcsInitSystem, IEcsRunSystem {\n    // Поля с авто-инъекцией.\n    EcsWorld _world;\n    // Мы хотим получить все сущности с компонентом \"WeaponComponent\"\n    // и без компонента \"HealthComponent\".\n    EcsFilter\u003cWeaponComponent\u003e.Exclude\u003cHealthComponent\u003e _filter;\n\n    public void Init () {\n        _world.NewEntity ().Get\u003cWeaponComponent\u003e ();\n    }\n\n    public void Run () {\n        foreach (int i in _filter) {\n            // Сущность, которая точно содержит компонент \"WeaponComponent\".\n            ref EcsEntity entity = ref _filter.GetEntity (i);\n\n            // Get1() позволяет получить доступ по ссылке на компонент,\n            // указанный первым в списке ограничений фильтра (\"WeaponComponent\").\n            ref WeaponComponent weapon = ref _filter.Get1 (i);\n            weapon.Ammo = System.Math.Max (0, weapon.Ammo - 1);\n        }\n    }\n}\n```\n\nЛюбые компоненты из `Include`-списка ограничений фильтра могут быть получены через вызовы `EcsFilter.Get1()`, `EcsFilter.Get2()` и т.д - нумерация идет в том же порядке, что и в списке ограничений.\n\nЕсли в компоненте нет данных и он используется исключительно как флаг-признак для фильтрации, то компонент может реализовать интерфейс `IEcsIgnoreInFilter` - это поможет уменьшить потребление памяти фильтром и немного увеличить производительность:\n```c#\nstruct Component1 { }\n\nstruct Component2 : IEcsIgnoreInFilter { }\n\nclass TestSystem : IEcsRunSystem {\n    EcsFilter\u003cComponent1, Component2\u003e _filter;\n\n    public void Run () {\n        foreach (var i in _filter) {\n            // Мы можем получить компонент \"Component1\".\n            ref var component1 = ref _filter.Get1 (i);\n\n            // Мы не можем получить \"Component2\" - кеш внутри фильтра не существует и будет выкинуто исключение.\n            ref var component2 = ref _filter.Get2 (i);\n        }\n    }\n}\n```\n\n\u003e **ВАЖНО!**: Фильтры поддерживают до 6 `Include`-ограничений и 2 `Exclude`-ограничений. Чем меньше ограничений в фильтре - тем он быстрее работает.\n\n\u003e **ВАЖНО!** Нельзя использовать несколько фильтров с одинаковым списком ограничений, но выставленных в разном порядке - в `DEBUG`-версии будет выкинуто исключение с описанием конфликтующих фильтров.\n\n\u003e **ВАЖНО!** Один и тот же компонент не может быть в списках \"Include\" и \"Exclude\" одного фильтра одновременно.\n\n## EcsWorld\nЯвляется контейнером для всех сущностей и фильтров, данные каждого экземпляра уникальны и изолированы от других миров.\n\n\u003e **ВАЖНО!** Необходимо вызывать `EcsWorld.Destroy()` у экземпляра мира если он больше не нужен.\n\n## EcsSystems\nЯвляется контейнером для систем, которыми будет обрабатываться `EcsWorld`-экземпляр мира:\n```c#\nclass Startup : MonoBehaviour {\n    EcsWorld _world;\n    EcsSystems _systems;\n\n    void Start () {\n        // Создаем окружение, подключаем системы.\n        _world = new EcsWorld ();\n        _systems = new EcsSystems (_world)\n            .Add (new WeaponSystem ());\n        _systems.Init ();\n    }\n    \n    void Update () {\n        // Выполняем все подключенные системы.\n        _systems.Run ();\n    }\n\n    void OnDestroy () {\n        // Уничтожаем подключенные системы.\n        _systems.Destroy ();\n        // Очищаем окружение.\n        _world.Destroy ();\n    }\n}\n```\n\nЭкземпляр `EcsSystems` может быть использован как обычная ecs-система (вложена в другую `EcsSystems`):\n```c#\n// Инициализация.\nEcsSystems nestedSystems = new EcsSystems (_world).Add (new NestedSystem ());\n\n// Нельзя вызывать nestedSystems.Init() здесь,\n// \"rootSystems\" выполнит этот вызов автоматически.\nEcsSystems rootSystems = new EcsSystems (_world).Add (nestedSystems);\nrootSystems.Init ();\n\n// В цикле обновления нельзя вызывать nestedSystems.Run(),\n// \"rootSystems\" выполнит этот вызов автоматически.\nrootSystems.Run ();\n\n// Очистка.\n// Нельзя вызывать nestedSystems.Destroy() здесь,\n// \"rootSystems\" выполнит этот вызов автоматически.\nrootSystems.Destroy ();\n```\n\nЛюбая `IEcsRunSystem` система (включая вложенные `EcsSystems`) может быть включен или выключен из списка обработки:\n```c#\nclass TestSystem : IEcsRunSystem {\n    public void Run () { }\n}\nEcsSystems systems = new EcsSystems (_world);\nsystems.Add (new TestSystem (), \"my special system\");\nsystems.Init ();\nvar idx = systems.GetNamedRunSystem (\"my special system\");\n\n// \"state\" будет иметь значение \"true\", все системы включены по умолчанию.\nvar state = systems.GetRunSystemState (idx);\n\n// Выключаем систему по ее индексу.\nsystems.SetRunSystemState (idx, false);\n```\n\n# Интеграция с движками\n\n## Unity\n\u003e Проверено на Unity 2020.3 (не зависит от нее) и содержит asmdef-описания для компиляции в виде отдельных сборок и уменьшения времени рекомпиляции основного проекта.\n\n[Интеграция в Unity editor](https://github.com/Leopotam/ecs-unityintegration) содержит шаблоны кода, а так же предоставляет мониторинг состояния мира.\n\n\n## Кастомный движок\n\u003e Для использования фреймворка требуется C#7.3 или выше.\n\nКаждая часть примера ниже должна быть корректно интегрирована в правильное место выполнения кода движком:\n```c#\nusing Leopotam.Ecs;\n\nclass EcsStartup {\n    EcsWorld _world;\n    EcsSystems _systems;\n\n    // Инициализация окружения.\n    void Init () {        \n        _world = new EcsWorld ();\n        _systems = new EcsSystems (_world);\n        _systems\n            // Системы с основной логикой должны\n            // быть зарегистрированы здесь, порядок важен:\n            // .Add (new TestSystem1 ())\n            // .Add (new TestSystem2 ())\n            \n            // OneFrame-компоненты должны быть зарегистрированы\n            // в общем списке систем, порядок важен:\n            // .OneFrame\u003cTestComponent1\u003e ()\n            // .OneFrame\u003cTestComponent2\u003e ()\n            \n            // Инъекция должна быть произведена здесь,\n            // порядок не важен:\n            // .Inject (new CameraService ())\n            // .Inject (new NavMeshSupport ())\n            .Init ();\n    }\n\n    // Метод должен быть вызван из\n    // основного update-цикла движка.\n    void UpdateLoop () {\n        _systems?.Run ();\n    }\n\n    // Очистка.\n    void Destroy () {\n        if (_systems != null) {\n            _systems.Destroy ();\n            _systems = null;\n            _world.Destroy ();\n            _world = null;\n        }\n    }\n}\n```\n\n# Статьи\n\n* [\"Создание шутера с LeoECS. Часть 1\"](https://habr.com/ru/post/573028/)\n\n  [![](https://habrastorage.org/getpro/habr/upload_files/f77/53f/bd5/f7753fbd5e6d9ad0fd1a6e734750277a.png)](https://habr.com/ru/post/573028/)\n\n* [\"Создание шутера с LeoECS. Часть 2\"](https://habr.com/ru/post/578054/)\n\n  [![](https://habrastorage.org/getpro/habr/upload_files/b76/595/263/b76595263c00346640f27d1e52c66323.png)](https://habr.com/ru/post/578054/)\n\n* [\"Создание шутера с LeoECS. Часть 3\"](https://habr.com/ru/post/585058/)\n\n  [![](https://habrastorage.org/getpro/habr/upload_files/d06/a68/587/d06a68587d3893edbcde2bb346f08abc.png)](https://habr.com/ru/post/585058/)\n\n* [\"Создание шутера с LeoECS. Часть 4\"](https://habr.com/ru/post/647233/)\n\n  [![](https://habrastorage.org/getpro/habr/upload_files/25a/747/725/25a747725de3b33c2964ce728490bb71.png)](https://habr.com/ru/post/647233/)\n\n* [\"Всё что нужно знать про ECS\"](https://habr.com/ru/post/665276/)\n\n  [![](https://habrastorage.org/r/w1560/getpro/habr/upload_files/3fd/5bc/544/3fd5bc5442b03a20d52a8003576056d4.png)](https://habr.com/ru/post/665276/)\n\n\n# Проекты, использующие LeoECS\n## С исходниками\n* [\"MatchTwo\"](https://github.com/cadfoot/unity-ecs-match-two)\n\n  [![](https://img.youtube.com/vi/Y3DwZmPCPSk/0.jpg)](https://www.youtube.com/watch?v=Y3DwZmPCPSk)\n\n\n* [\"Bubble shooter\"](https://github.com/cadfoot/unity-ecs-bubble-shooter)\n\n  [![](https://img.youtube.com/vi/l19wREGUf1k/0.jpg)](https://www.youtube.com/watch?v=l19wREGUf1k)\n\n\n* [\"Frantic Architect Remake\"](https://github.com/cadfoot/unity-ecs-fran-arch)\n\n  [![](https://img.youtube.com/vi/YAfHDyBl7Fg/0.jpg)](https://www.youtube.com/watch?v=YAfHDyBl7Fg)\n\n\n* [\"Mahjong Solitaire\"](https://github.com/cadfoot/unity-ecs-mahjong-solitaire)\n\n  [![](https://img.youtube.com/vi/FxOcqVwue9g/0.jpg)](https://www.youtube.com/watch?v=FxOcqVwue9g)\n\n\n* [\"Tetris\"](https://github.com/fomgleb/tetris)\n\n  [![](https://user-images.githubusercontent.com/60964034/198828588-288efc77-30da-4b54-8879-920327ffb24d.png)](https://github.com/fomgleb/tetris)\n\n\n* [\"3D Platformer\"](https://github.com/supremestranger/3D-Platformer)\n\n  [![](https://camo.githubusercontent.com/dcd2f525130d73f4688c1f1cfb12f6e37d166dae23a1c6fac70e5b7873c3ab21/68747470733a2f2f692e6962622e636f2f686d374c726d342f506c6174666f726d65722e706e67)](https://github.com/supremestranger/3D-Platformer)\n\n\n* [\"SpaceInvaders (Guns\u0026Bullets variation)\"](https://github.com/GoodCatGames/SpaceInvadersEcs)\n\n  [![](https://github.com/GoodCatGames/SpaceInvadersEcs/raw/master/docs/SpaceInvadersImage.png)](https://github.com/GoodCatGames/SpaceInvadersEcs)\n\n\n* [\"Pacman\"](https://github.com/SH42913/pacmanecs)\n\n  [![](https://github.com/SH42913/pacmanecs/raw/master/Screenshots/PacManEcs_fZyXscSovk.png)](https://github.com/SH42913/pacmanecs)\n\n\n* [\"Runner\"](https://github.com/t1az2z/RunnerECS)\n\n\n# Расширения\n* [Интеграция в редактор Unity](https://github.com/Leopotam/ecs-unityintegration)\n* [Поддержка Unity uGui](https://github.com/Leopotam/ecs-ui)\n* [Поддержка многопоточности](https://github.com/Leopotam/ecs-threads)\n* [Unity Physx events support](https://github.com/supremestranger/leoecs-physics)\n\n# Лицензия\nФреймворк выпускается под двумя лицензиями, [подробности тут](./LICENSE.md).\n\nВ случаях лицензирования по условиям MIT-Red не стоит расчитывать на\nперсональные консультации или какие-либо гарантии.\n\n# ЧаВо\n\n### Я хочу знать - существовал ли компонент на сущности до вызова Get() для разной инициализации полученных данных. Как я могу это сделать?\n\nЕсли не важно - существовал компонент ранее и просто нужна уверенность, что он теперь существует достаточно вызова `EcsEntity.Get\u003cT\u003e()`.\n\nЕсли нужно понимание, что компонент существовал ранее - это можно проверить с помощью вызова `EcsEntity.Has\u003cT\u003e()`.  \n\n### Я хочу одну систему вызвать в `MonoBehaviour.Update()`, а другую - в `MonoBehaviour.FixedUpdate()`. Как я могу это сделать?\n\nДля разделения систем на основе разных методов из `MonoBehaviour` необходимо создать под каждый метод отдельную `EcsSystems`-группу:\n```c#\nEcsSystems _update;\nEcsSystems _fixedUpdate;\n\nvoid Start () {\n    var world = new EcsWorld ();\n    _update = new EcsSystems (world).Add (new UpdateSystem ());\n    _update.Init ();\n    _fixedUpdate = new EcsSystems (world).Add (new FixedUpdateSystem ());\n    _fixedUpdate.Init ();\n}\n\nvoid Update () {\n    _update.Run ();\n}\n\nvoid FixedUpdate () {\n    _fixedUpdate.Run ();\n}\n```\n\n### Мне нравится как работает автоматическая инъекция данных, но хотелось бы часть полей исключить. Как я могу сделать это?\n\nДля этого достаточно пометить поле системы атрибутом `[EcsIgnoreInject]`:\n```c#\n// Это поле будет обработано инъекцией.\nEcsFilter\u003cC1\u003e _filter1;\n\n// Это поле будет проигнорировано инъекцией.\n[EcsIgnoreInject] EcsFilter\u003cC2\u003e _filter2;\n```\n\n### Меня не устраивают значения по умолчанию для полей компонентов. Как я могу это настроить?\n\nКомпоненты поддерживают кастомную настройку значений через реализацию интерфейса `IEcsAutoReset\u003c\u003e`:\n```c#\nstruct MyComponent : IEcsAutoReset\u003cMyComponent\u003e {\n    public int Id;\n    public object LinkToAnotherComponent;\n\n    public void AutoReset (ref MyComponent c) {\n        c.Id = 2;\n        c.LinkToAnotherComponent = null;\n    }\n}\n```\nЭтот метод будет автоматически вызываться для всех новых компонентов, а так же для всех только что удаленных, до помещения их в пул.\n\u003e **ВАЖНО!** В случае применения `IEcsAutoReset` все дополнительные очистки/проверки полей компонента отключаются, что может привести к утечкам памяти. Ответственность лежит на пользователе!\n\n\u003e **ВАЖНО!**: Компоненты, реализующие `IEcsAutoReset` не совместимы с вызовами `entity.Replace()`. Рекомендуется не использовать `entity.Replace()` или любые другие способы полной перезаписи компонентов.\n\n### Я использую компоненты как \"события\", которые живут 1 цикл, а потом удаляются в конце отдельной системой. Получается много лишнего кода, есть ли более простой способ?\n\nДля автоматической очистки компонентов, которые должны жить один цикл, место их очистки может быть зарегистрировано в общем списке систем внутри `EcsSystems`:\n```c#\nstruct MyOneFrameComponent { }\n\nEcsSystems _update;\n\nvoid Start () {\n    var world = new EcsWorld ();\n    _update = new EcsSystems (world);\n    _update\n        .Add (new CalculateSystem ())\n        // Все \"MyOneFrameComponent\" компоненты будут\n        // удалены здесь.\n        .OneFrame\u003cMyOneFrameComponent\u003e ()\n        // Здесь можно быть уверенным, что ни один\n        // \"MyOneFrameComponent\" не существует.\n        .Add (new UpdateSystem ())\n        .Init ();\n}\n\nvoid Update () {\n    _update.Run ();\n}\n```\n\n### Мне нужен больший контроль над размерами кешей, которые мир использует в момент создания. Как я могу сделать это?\n\nМир может быть создан с явным указанием `EcsWorldConfig`-конфигурации:\n```c#\nvar config = new EcsWorldConfig () {\n    // Размер по умолчанию для World.Entities.\n    WorldEntitiesCacheSize = 1024,\n    // Размер по умолчанию для World.Filters.\n    WorldFiltersCacheSize = 128,\n    // Размер по умолчанию для World.ComponentPools.\n    WorldComponentPoolsCacheSize = 512,\n    // Размер по умолчанию для Entity.Components (до удвоения).\n    EntityComponentsCacheSize = 8,\n    // Размер по умолчанию для Filter.Entities.\n    FilterEntitiesCacheSize = 256,\n};\nvar world = new EcsWorld(config);\n```\n\n### Мне нужно больше чем 6-\"Include\" и 2-\"Exclude\" ограничений для компонентов в фильтре. Как я могу сделать это?\n\n\u003e **ВАЖНО!** Это приведет к модификации исходного кода фреймворка и несовместимости с обновлениями.\n\u003e \nНеобходимо воспользоваться [кодогенерацией EcsFilter](https://leopotam.github.io/ecs/filter-gen.html) классов и заменить содержимое файла `EcsFilter.cs`.\n\n### Я хочу добавить реактивщины и обрабатывать события изменения фильтров. Как я могу это сделать?\n\n\u003e **ВАЖНО!** Так делать не рекомендуется из-за падения производительности.\n\nДля активации этого функционала следует добавить `LEOECS_FILTER_EVENTS` в список директив комплятора, а затем - добавить слушатель событий:\n```c#\nclass CustomListener: IEcsFilterListener {\n    public void OnEntityAdded (in EcsEntity entity) {\n        // Сущность добавлена в фильтр.\n    }\n    \n    public void OnEntityRemoved (in EcsEntity entity) {\n        // Сущность удалена из фильтра.\n    }\n}\n\nclass MySystem : IEcsInitSystem, IEcsDestroySystem {\n    readonly EcsFilter\u003cComponent1\u003e _filter = null;\n    readonly CustomListener _listener = new CustomListener ();\n    public void Init () {\n        // Подписка слушателя на события фильтра.\n        _filter.AddListener (_listener);\n    }\n    public void Destroy () {\n        // Отписка слушателя от событий фильтра.\n        _filter.RemoveListener (_listener);\n    }\n}\n``` ","funding_links":[],"categories":["Libraries","ECS Libraries","Open Source Repositories","ECS"],"sub_categories":["C#","ECS Framework"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLeopotam%2Fecs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLeopotam%2Fecs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLeopotam%2Fecs/lists"}