{"id":13663229,"url":"https://github.com/OlegDzhuraev/CeresECL","last_synced_at":"2025-04-25T13:32:25.388Z","repository":{"id":125503066,"uuid":"283160180","full_name":"OlegDzhuraev/CeresECL","owner":"OlegDzhuraev","description":"Experimental architectural approach for gamedev","archived":false,"fork":false,"pushed_at":"2021-07-02T17:01:06.000Z","size":137,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-10T19:34:39.532Z","etag":null,"topics":["csharp","ecs","entity-component","gamedev","unity"],"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/OlegDzhuraev.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-28T09:10:12.000Z","updated_at":"2024-02-28T13:25:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"3dc4774e-d7c3-4b04-b618-3139b206fb6a","html_url":"https://github.com/OlegDzhuraev/CeresECL","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlegDzhuraev%2FCeresECL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlegDzhuraev%2FCeresECL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlegDzhuraev%2FCeresECL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlegDzhuraev%2FCeresECL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OlegDzhuraev","download_url":"https://codeload.github.com/OlegDzhuraev/CeresECL/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250825069,"owners_count":21493392,"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":["csharp","ecs","entity-component","gamedev","unity"],"created_at":"2024-08-02T05:02:21.851Z","updated_at":"2025-04-25T13:32:20.351Z","avatar_url":"https://github.com/OlegDzhuraev.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"# CeresECL\nCeres ECL is **experimental** implementation of Entity Component Logic architectural pattern in Unity. \n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"http://dzhuraev.com/CeresECL/CeresECLUnity1.png\" width=\"364\" height=\"385\" alt=\"Ceres ECL\"\u003e\n\u003c/p\u003e\n\nCeres ECL is designed to be lightweight and used mostly from code, not from Unity Inspector. If you're looking for more Unity-connected thing, take look at [PlutoECL](https://github.com/InsaneOneHub/PlutoECL).\n\n### What is Entity Component Logic?\nIt is inspired by Entity Component System and Components over Inheritance approaches. \nDifference from ECS is that there no Systems, which handles a lot of objects, but there is Logics, which handle self objects like MonoBehaviours in Unity. \nBut with ECL you obliged to separate logics from data.\nI really don't know is there exist any pattern like this, so I described it by my own. :)\n\nProblem of Unity-way scripting is that there only MonoBehaviour, which is not saves you from bad coding practices. Ceres ECL will keep you in track of following the pattern principles.\n\n### Why I should use it instead of Entity Component System?\nNo reasons. ECS is cool. But if you're have problems with understanding ECS or it looks too complicated to you,\nCeres ECL is simplier and looks more like usual Unity-way scripting, so you can use it.\n\n## Overview\nThere is ready classes Entity, Component, Logic, which you should use to create your own. More info and examples will be added soon.\n\n### Entity\n**Entity** is **MonoBehaviour** script. It describes your object - contains all it **Components** and **Logics**. Looks like Unity component system, but all code is open-source.\n\n```csharp\n// Spawning new Entity object using PlayerEntityBuilder and using instance of playerPrefab as Entity GameObject.\nvar entity = Entity.Spawn\u003cPlayerEntityBuilder\u003e(playerPrefab);\n\n// Spawn empty game object as entity (no prefab needed).\nvar emptyEntity = Entity.Spawn\u003cPlayerEntityBuilder\u003e();\n```\n\n### Component\nComponent is simple class, which only contains some data of your **Entity**. For example, **MoveComponent**, which contains **Speed** and **Direction** of movement. \nShould be no any logics code in this class.\n\n```csharp\nusing CeresECL;\n\npublic class MoveComponent : Component\n{\n  public float Speed;\n  public Vector3 Direction;\n}\n```\n\n### Logic\n**Logic** describes specific behaviour of the **Entity**. Logics should know nothing about anothers, it should work only with **Components**, **Events** and **Tags**.\n\nFor example, **MoveLogic** will move it using **MoveComponent** data. \nAnd **InputLogic** will fill **MoveComponent Direction** field with player input.\n\n\n```csharp\nusing CeresECL;\n\npublic class MoveLogic : Logic, IInitLogic, IRunLogic\n{\n  MoveComponent moveComponent;\n\n  void IInitLogic.Init()\n  {\n    moveComponent = Entity.Components.Get\u003cMoveComponent\u003e();\n\n    moveComponent.Speed = 2f;\n  }\n\n  void IRunLogic.Run()\n  {\n    Entity.transform.position += moveComponent.Direction * (moveComponent.Speed * Time.deltaTime);\n  }\n}\n```\n\nThere is **IInitLogic** interface to implement initialization logic, similar to the **Start** Unity method.\n\nThere also **IRunLogic** interface to implement run logic, similar to the **Update** Unity method.\n\n### Builder\nYou need to create your entities, filling it with Logics which will handle this entity behaviour. **Builder** is Init Logic realization, designed to setup your entity Logics.\n```csharp\nusing CeresECL;\n\npublic class PlayerEntityBuilder : Builder\n{\n  protected override void Build()\n  {\n    Entity.Logics.Add\u003cInputLogic\u003e();\n    Entity.Logics.Add\u003cMoveLogic\u003e();\n  }\n}\n```\n\nBuilders is a only one place, where you allowed to create strong dependencies (Builders will know about all connected Logics). This is key differnce from ECS -- in ECS most of dependencies is placed in Launcher, which generate ECS World with all it's system. So there 1 ECS Launcher file vs N ECL Builder files. But in other there should be minimum dependencies amount.\n\n### Tags\nIf you need to create new component, which will be simple mark object state, use **Tags** instead. **Entity.Tags** contains all tags, added to the entity. \n\n**Tags** can be any **Enum**. You can use **TagsList.cs** from Example or create your own **enum Tag**.\nTo create new **Tag**, edit **enum Tag**:\n```csharp\npublic enum Tag\n{\n    CustomTag = 0,\n    // add your tags here\n}\n```\n\nAdding tag to the entity:\n```csharp\nEntity.Tags.Add(Tag.CustomTag);\n```\n\nNote that tags are stacked, it means that you can add several same tags to the entity. It can used for some mechanics like block of some entity action from different Logics.\n\nCheck of tag on the entity:\n```csharp\nEntity.Tags.Have(Tag.CustomTag);\n```\n\nRemoving tag (only one, if there stacked tags) from the entity:\n```csharp\nEntity.Tags.Remove(Tag.CustomTag);\n```\n\nNew tags version is a simple integer in code, so if you want see your Tags names from enum in Entity debug, you need specify your enum type in **CeresSettings** in ECL Launcher script:\n```csharp\nCeresSettings.Instance.TagsEnum = typeof(Tag);\n```\nYou can see it in **Example**.\n\nTags inspired by Pixeye Actors ECS tags. But possble that in my realisation this feature is not so cool. :D\n\n### Events\n**Events** - same to the components, but live only 1 frame. So if something happens in your game, you can send event from one of Logics and other will catch it. Since event same to the component, it can contain any data. To create **Event**, create new class, derived from **Event**:\n\n```csharp\nusing CeresECL;\n\nclass ColliderHitEvent : Event\n{\n    public Collider2D HitCollider;\n}\n```\n\nTo send **Event**, do it like this:\n```csharp\n var hitEvent = new ColliderHitEvent\n{\n    HitCollider = other\n};\n\nEntity.Events.Add(hitEvent);\n```\n\nYou can send events not only from Logics, but from any MonoBehaviours too, it can be useful for combining of default Unity-way coding and ECL.\nNote that **Logics** adding order can be important since **Event** live only one frame.\n\nYou can subscribe to event type in **Logic** like this:\n```csharp\nusing CeresECL;\n\npublic class Bullet : Logic, IInitLogic\n{\n  void IInitLogic.Init()\n  {\n    Entity.Events.Subscribe\u003cColliderHitEvent\u003e(OnHit);\n  }\n\n  void OnHit(ColliderHitEvent eventData)\n  {\n    // handle event data\n  }\n}\n```\n\nUnsubscribe is the same:\n```csharp\nEntity.Events.Unsubscribe\u003cColliderHitEvent\u003e(OnHit);\n```\n\nCurrent Events version is not finished and can be unstable, but all tests passed fine, so I added it to the repo.\n\n### Launcher\nTo make it all work, you need entry point, some classic **MonoBehaviour** script. To do this correct, create your new script, name it, for example, **MyLauncher**, and derive from Ceres **Launcher** class. Next, you need to override **StartAction** method and add there your init logic.\n\n```csharp\nusing Ceres.ECL;\n\npublic class MyLauncher : Launcher\n{\n    protected override void StartAction()\n    {\n        Entity.Spawn\u003cYourEntBuilder\u003e();\n    }\n}\n```\n\nBase **Launcher** class handles all entities update, so there only 1 MonoBehaviour Update for **all** Entities Logics. For some unknown reasons, in Unity it increases game FPS. So do **not** make **Update** method in your Launcher, it can override Ceres one. And, yes, you don't need it in any case.\n\n### Templates\nYou can create each of these classes using templates. Click **RMB** in **Project Window** and open submenu **Ceres ECL**. There will be all actual templates. \n\nIt will generate script in root namespace, which you can change in **Editor Settings -\u003e Editor -\u003e C# Project Generation**. Otherwise it will be generated in **CeresECL** namespace.\n\nFor template generator idea thanks to LeoECS, some used things came from its code.\n\n### Dependency Injection\nCeres ECL has DI implementation for Logics. So you can inject any data to all of yours Entity Logics:\n\n```csharp\nEntity.Logics.Inject(data);\n```\n\nYour Logic should have field with same to **data** type, for example, if **data** type is **Data**, your Logic should look like this:\n\n```csharp\nusing CeresECL;\n\npublic class TestLogic : Logic, IRunLogic\n{\n  Data injectedData;\n\n  void IRunLogic.Run()\n  {\n    // Do smth ?\n  }\n}\n```\n\nDependency Injection idea came from LeoECS, you can find a link to its repo at the end of readme.\n\n## Debug\nTo check state of your **Entity**, select its GameObject on scene and you will see all **Tags**, **Components** and **Logics**, added to the entity with their parameters:\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"http://dzhuraev.com/CeresECL/CeresECLUnity1.png\" width=\"364\" height=\"385\" alt=\"Ceres ECL\"\u003e\n\u003c/p\u003e\n\n## More FAQ\n### Can I edit variables or entities from Inspector\n**No**. All changes should be done from code - this is place for all your game logic. If you need add some data - load it from **Scritable Object** files and use Dependency Injection. If you prefer using Inspector for all your settings, take look at [PlutoECL](https://github.com/InsaneOneHub/PlutoECL), it is much more Inspector-friendly.\n\n### How I can use OnTriggerEnter, for example\nYou can create classic **MonoBehaviour**, and send Event from it to the Entity.Events. Check Example, there is **CollisionSender** class. In [PlutoECL](https://github.com/InsaneOneHub/PlutoECL) you can use all these methods directly in Logic code. And no, this is not Ad for PlutoECL :D\n\n### Is Ceres ECL production-ready\nNo, until there will be at least one release on GitHub. Currently it is fully experimental non-commercial project. But you can use it on your risk, all features already should work.\n\n## Examples\nCheck Example folder from repository, it contains simple Ceres ECL usage example. \n\nLinks to games examples on GitHub will be added when these examples will be created. :)\n\n## Thanks to\nLeopotam for LeoECS https://github.com/Leopotam/ecs\n\nPixeye for Actors https://github.com/PixeyeHQ/actors.unity\n\nInspired me to use ECS and think moer about different coding architecture patterns. :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FOlegDzhuraev%2FCeresECL","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FOlegDzhuraev%2FCeresECL","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FOlegDzhuraev%2FCeresECL/lists"}