{"id":22549054,"url":"https://github.com/dcfapixels/dragonecs-graphs","last_synced_at":"2026-02-21T04:01:43.383Z","repository":{"id":266445735,"uuid":"654852423","full_name":"DCFApixels/DragonECS-Graphs","owner":"DCFApixels","description":"Relations between entities for DragonECS","archived":false,"fork":false,"pushed_at":"2025-03-31T04:20:24.000Z","size":153,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-31T05:20:29.712Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DCFApixels.png","metadata":{"files":{"readme":"README-RU.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-17T06:14:43.000Z","updated_at":"2025-03-31T04:18:50.000Z","dependencies_parsed_at":"2024-12-04T10:24:41.553Z","dependency_job_id":"20bd40c1-edd6-46df-aeb9-b03cd63bd0da","html_url":"https://github.com/DCFApixels/DragonECS-Graphs","commit_stats":null,"previous_names":["dcfapixels/dragonecs-graphs"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DCFApixels%2FDragonECS-Graphs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DCFApixels%2FDragonECS-Graphs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DCFApixels%2FDragonECS-Graphs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DCFApixels%2FDragonECS-Graphs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DCFApixels","download_url":"https://codeload.github.com/DCFApixels/DragonECS-Graphs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248079289,"owners_count":21044274,"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-12-07T16:07:46.737Z","updated_at":"2026-02-21T04:01:38.338Z","avatar_url":"https://github.com/DCFApixels.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg width=\"400\" src=\"https://github.com/user-attachments/assets/4c1aaeea-7283-4980-b447-a3bc7e54aeb7\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg alt=\"Version\" src=\"https://img.shields.io/github/package-json/v/DCFApixels/DragonECS-Graphs?color=%23ff4e85\u0026style=for-the-badge\"\u003e\n\u003cimg alt=\"License\" src=\"https://img.shields.io/github/license/DCFApixels/DragonECS-Graphs?color=ff4e85\u0026style=for-the-badge\"\u003e\n\u003ca href=\"https://discord.gg/kqmJjExuCf\"\u003e\u003cimg alt=\"Discord\" src=\"https://img.shields.io/badge/Discord-JOIN-00b269?logo=discord\u0026logoColor=%23ffffff\u0026style=for-the-badge\"\u003e\u003c/a\u003e\n\u003ca href=\"http://qm.qq.com/cgi-bin/qm/qr?_wv=1027\u0026k=IbDcH43vhfArb30luGMP1TMXB3GCHzxm\u0026authKey=s%2FJfqvv46PswFq68irnGhkLrMR6y9tf%2FUn2mogYizSOGiS%2BmB%2B8Ar9I%2Fnr%2Bs4oS%2B\u0026noverify=0\u0026group_code=949562781\"\u003e\u003cimg alt=\"QQ\" src=\"https://img.shields.io/badge/QQ-JOIN-00b269?logo=tencentqq\u0026logoColor=%23ffffff\u0026style=for-the-badge\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Графы сущностей для [DragonECS](https://github.com/DCFApixels/DragonECS)\n \n\u003ctable\u003e\n  \u003ctr\u003e\u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"3\"\u003eReadme Languages:\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd nowrap width=\"100\"\u003e\n      \u003ca href=\"https://github.com/DCFApixels/DragonECS-Graphs/blob/main/README-RU.md\"\u003e\n        \u003cimg src=\"https://github.com/user-attachments/assets/3c699094-f8e6-471d-a7c1-6d2e9530e721\"\u003e\u003c/br\u003e\n        \u003cspan\u003eРусский\u003c/span\u003e\n      \u003c/a\u003e  \n    \u003c/td\u003e\n    \u003ctd nowrap width=\"100\"\u003e\n      \u003ca href=\"https://github.com/DCFApixels/DragonECS-Graphs\"\u003e\n        \u003cimg src=\"https://github.com/user-attachments/assets/30528cb5-f38e-49f0-b23e-d001844ae930\"\u003e\u003c/br\u003e\n        \u003cspan\u003eEnglish(WIP)\u003c/span\u003e\n      \u003c/a\u003e  \n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c/br\u003e\n\nРеализация отношений сущностей в виде графа. Связывающие ребра графа представлены в виде сущностей, что позволяет создавать отношения вида многие ко многим, а с помощью компонентной композиции можно настраивать вид этих отношений.\n\n\u003e [!WARNING]\n\u003e Проект в стадии разработки. API может меняться.\n\n# Оглавление\n- [Установка](#установка)\n- [Инициализация](#инициализация)\n\n\u003c/br\u003e\n\n# Установка\nСемантика версионирования - [Открыть](https://gist.github.com/DCFApixels/e53281d4628b19fe5278f3e77a7da9e8#file-dcfapixels_versioning_ru-md)\n## Окружение\nОбязательные требования:\n+ Зависимость: [DragonECS](https://github.com/DCFApixels/DragonECS)\n+ Минимальная версия C# 7.3;\n\nОпционально:\n+ Игровые движки с C#: Unity, Godot, MonoGame и т.д.\n\nПротестировано:\n+ **Unity:** Минимальная версия 2020.1.0;\n\n## Установка для Unity\n* ### Unity-модуль\nПоддерживается установка в виде Unity-модуля в  при помощи добавления git-URL [в PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) или ручного добавления в `Packages/manifest.json`: \n```\nhttps://github.com/DCFApixels/DragonECS-Graphs.git\n```\n* ### В виде исходников\nПакет так же может быть добавлен в проект в виде исходников.\n\n\u003c/br\u003e\n\n# Граф\nКлючевой класс в котором хранится информация об отношениях. Графу требуется 2 мира: обычный мир и мир для сущностей-связей. Пример создания `EntityGraph`:\n```c#\n// Обычный мир.\n_world = new EcsDefaultWorld();\n// EcsGraphWorld специальный тип мира для сущностей-связей,\n// но может использоваться любой другой тип мира.\n_graphWorld = new EcsGraphWorld();\n// Создание EntityGraph связывающий эти два мира.\nEntityGraph graph = _world.CreateGraph(_graphWorld);\n\n_pipeline = EcsPipeline.New()\n    // ...\n    // Далее миры и граф можно внедрить в системы.\n    .Inject(_world, _graphWorld, graph)\n    // ...\n    .Build()\n```\nДля обычных сущностей и для сущностей-связей может использовать один общий мир:\n```c#\n_world = new EcsDefaultWorld();\n// Создание EntityGraph завязанный на одном мире.\nEntityGraph graph = _world.CreateGraph();\n```\n\n# Сущность-связь\n\nКак и обычная сущность, но регистрируется и создается в `EntityGraph`. Предназначена для данных об отношении двух сущностей.\n\n\u003e Отношения имеют направление, поэтому чтобы разделять сущности, далее будет использованы понятия: начальная сущность(`Start Entity`) от нее исходит сущность-связъ(`Relation Entity`) к конечной сущности(`End Entity`). Начальная и конечная сущность это сущности-узлы(`Node Entity`).\n\u003e \n\u003e (Start Entity) ── (Relation Entity) ─》(End Entity)\n\nПример работы с связями:\n```c#\n// Получаем или создаем новую сущность-связь от узлов `startE` к `endE`.\n// Сущность создается в мире _graph.GraphWorld и регистрируется в графе.\nvar relE = _graph.GetOrNewRelation(startE, endE);\n\n// Кроме создания и удаления, в остальном сущности-связи - это обычные сущности.\nref var someCmp = ref _somePool.Add(relE);\n\n// Вернет true если была создана через EntityGraph.GetOrNewRelation(startE, endE)\n// и false если через EcsWorld.NewEntity().\nbool isRelation = _graph.IsRelation(relE);\n\n// Получить начальную и конечную сущность.\n(startE, endE) = _graph.GetRelationStartEnd(relE);\n\n// Взять сущность-связь для отношения в обратном направлении, от `endE` к `startE`.\n_graph.GetOrNewInverseRelation(relE);\n\n// Удаляем сущность-связь.\n_graph.DelRelation(relE);\n```\n\n# Запрос Join\n\nСопоставляет сущности-связи с привязанными сущностями. Возвращает структуру `SubGraphMap` которая позволяет итерироваться по сопоставленным сущностями-связям.\n\n```c#\n// Запросом Where получем сущности-связи, потом запросом Join сопоставляем их с конечными сущностями.\n// Аргумент JoinMode.End указывает что сопоставлять нужно с конечными сущностями.\nSubGraphMap map = _graph.GraphWorld.Where(out EventAspect relA).Join(JoinMode.End);\n// map.Nodes это список конечных сущностей.\nforeach (var endE in map.Nodes.Where(out Aspect a))\n{\n    // ...\n    // Итерация по сопоставленным сущностям-связям.\n    foreach (var relE in map.GetRelations(endE))\n    {\n        // ...\n    }\n}\n```\n\n# Пример кода\n\nНиже приведен пример как бы могли быть реализованы системы нанесения урона взрывом и система применения урона к здоровью. Этот пример поверхностный реализации, но достаточно нагляден и демонстрирует основные функции расширения.\n\u003cdetails\u003e\n\u003csummary\u003eИспользованные в примере компоненты\u003c/summary\u003e\n\n```c#\npublic struct Explosion : IEcsComponent\n{\n    public float damage;\n    public float radius;\n}\npublic struct Health : IEcsComponent\n{\n    public float points;\n}\npublic struct Transform : IEcsComponent\n{\n    public Vector3 position;\n}\n\n// Компоненты для связей.\npublic struct DamageEvent : IEcsComponent\n{\n    public float points;\n}\npublic struct KillEvent : IEcsTagComponent { }\n```\n\n\u003c/details\u003e\n\n```c#\npublic class SomeExplosionHitSystem : IEcsRun, IEcsInject\u003cEntityGraph\u003e, IEcsInject\u003cSpatialService\u003e\n{\n    class EventAspect : EcsAspect\n    {\n        public EcsPool\u003cDamageEvent\u003e damageEvents = Inc;\n    }\n    class Aspect : EcsAspect\n    {\n        public EcsPool\u003cTransform\u003e transforms = Inc;\n        public EcsPool\u003cExplosion\u003e explosions = Inc;\n    }\n    EntityGraph _graph;\n    SpatialService _spatial;\n\n    public void Run()\n    {\n        var relA = _graph.GraphWorld.GetAspect\u003cEventAspect\u003e();\n        foreach (var e in _graph.World.Where(out Aspect a))\n        {\n            ref var transform = ref a.transforms.Get(e);\n            ref var explosion = ref a.explosions.Get(e);\n            // Получаем все сущности рядом со взрывом.\n            // Реализация опущена, можно реализовать на основе Quad Tree, Spatial hashing или при помощи методов физики движка.\n            EcsSpan targetEs = _spatial.GetEntitiesInRadius(transform.position, explosion.radius);\n\n            foreach (var targetE in targetEs)\n            {\n                // Получаем сущность-связь от `e` к `targetE`.\n                var relE = _graph.GetOrNewRelation(e, targetE);\n                // Создаем событие нанесения урона.\n                ref var damageEvent = ref relA.damageEvents.TryAddOrGet(relE);\n                damageEvent.points = explosion.damage;\n            }\n        }\n    }\n    public void Inject(EntityGraph obj) =\u003e _graph = obj;\n    public void Inject(SpatialService obj) =\u003e _spatial = obj;\n}\n```\n```c#\npublic class SomeApplyDamageSystem : IEcsRun, IEcsInject\u003cEntityGraph\u003e\n{\n    class EventAspect : EcsAspect\n    {\n        public EcsPool\u003cDamageEvent\u003e damageEvents = Inc;\n        public EcsTagPool\u003cKillEvent\u003e killEvents = Opt;\n    }\n    class Aspect : EcsAspect\n    {\n        public EcsPool\u003cHealth\u003e healths = Inc;\n    }\n    EntityGraph _graph;\n    \n    public void Run()\n    {\n        // Запрос сущностей с DamageEvent и запрос Join для них.\n        SubGraphMap map = _graph.GraphWorld.Where(out EventAspect relA).Join(JoinMode.End);\n        // Фильтруем конечные сущности наа наличие Health и итерируемся по ним.\n        foreach (var endE in map.Nodes.Where(out Aspect a))\n        {\n            ref var health = ref a.healths.Get(endE);\n            bool isAlive = health.points \u003e 0;\n            foreach (var relE in map.GetRelations(endE))\n            {\n                ref var damage = ref relA.damageEvents.Get(relE);\n                health.points -= damage.points;\n                if (isAlive \u0026\u0026 health.points \u003c= 0)\n                {\n                    // Добавляем в сущность связь тег сигнализирующий что\n                    // источник урона так же убил сущность.\n                    relA.killEvents.TryAdd(relE);\n                }\n            }\n        }\n    }\n    public void Inject(EntityGraph obj) =\u003e _graph = obj;\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcfapixels%2Fdragonecs-graphs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdcfapixels%2Fdragonecs-graphs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcfapixels%2Fdragonecs-graphs/lists"}