├── InsaneOne.CeresECL.asmdef ├── .gitignore ├── Example ├── Sources │ ├── Events │ │ ├── ColliderHitEvent.cs.meta │ │ └── ColliderHitEvent.cs │ ├── Builders │ │ ├── EnemyEntityBuilder.cs.meta │ │ ├── EnemyEntityBuilder.cs │ │ ├── BulletEntityBuilder.cs │ │ ├── PlayerEntityBuilder.cs │ │ ├── BulletEntityBuilder.cs.meta │ │ └── PlayerEntityBuilder.cs.meta │ ├── TagsList.cs │ ├── Components │ │ ├── BulletComponent.cs │ │ ├── MoveComponent.cs │ │ ├── MoveComponent.cs.meta │ │ └── BulletComponent.cs.meta │ ├── Builders.meta │ ├── Events.meta │ ├── Logics.meta │ ├── Storing.meta │ ├── Components.meta │ ├── UnityComponents.meta │ ├── TagsList.cs.meta │ ├── Logics │ │ ├── BulletLogic.cs.meta │ │ ├── InputLogic.cs.meta │ │ ├── MoveLogic.cs.meta │ │ ├── MoveLogic.cs │ │ ├── BulletLogic.cs │ │ └── InputLogic.cs │ ├── Storing │ │ ├── GameData.cs.meta │ │ └── GameData.cs │ └── UnityComponents │ │ ├── CollisionSender.cs.meta │ │ ├── ExampleLauncher.cs.meta │ │ ├── CollisionSender.cs │ │ └── ExampleLauncher.cs ├── Prefabs │ ├── Bullet.prefab.meta │ ├── Enemy.prefab.meta │ ├── Player.prefab.meta │ ├── Enemy.prefab │ ├── Bullet.prefab │ └── Player.prefab ├── Data.meta ├── Scenes.meta ├── Scenes │ ├── SampleScene.unity.meta │ └── SampleScene.unity ├── Prefabs.meta ├── Sources.meta ├── InsaneOne.CeresECL.Example.asmdef.meta ├── Data │ ├── GameData.asset.meta │ └── GameData.asset └── InsaneOne.CeresECL.Example.asmdef ├── Resources ├── Templates │ ├── Event.txt │ ├── Component.txt │ ├── Builder.txt │ ├── RunLogic.txt │ ├── InitLogic.txt │ ├── GameLauncher.txt │ ├── Event.txt.meta │ ├── Builder.txt.meta │ ├── Component.txt.meta │ ├── InitLogic.txt.meta │ ├── RunLogic.txt.meta │ └── GameLauncher.txt.meta ├── Templates.meta ├── CeresSettings.asset.meta └── CeresSettings.asset ├── LICENSE.md.meta ├── README.md.meta ├── package.json.meta ├── Example.meta ├── Resources.meta ├── Sources.meta ├── Sources ├── Editor.meta ├── Containers.meta ├── Extensions.meta ├── Extensions │ ├── Editor.meta │ ├── Extensions.cs.meta │ ├── Editor │ │ ├── EditorHelpers.cs.meta │ │ └── EditorHelpers.cs │ └── Extensions.cs ├── Editor │ ├── InsaneOne.CeresECL.Editor.asmdef.meta │ ├── EntityEditor.cs.meta │ ├── TemplatesGenerator.cs.meta │ ├── InsaneOne.CeresECL.Editor.asmdef │ ├── TemplatesGenerator.cs │ └── EntityEditor.cs ├── CeresIgnoreInjectAttribute.cs ├── Builder.cs.meta ├── Entity.cs.meta ├── Event.cs.meta ├── IntTag.cs.meta ├── Launcher.cs.meta ├── Logic.cs.meta ├── CeresSettings.cs.meta ├── Component.cs.meta ├── Launcher.cs ├── Containers │ ├── Events.cs.meta │ ├── Logics.cs.meta │ ├── Tags.cs.meta │ ├── Components.cs.meta │ ├── Container.cs.meta │ ├── Container.cs │ ├── Components.cs │ ├── Events.cs │ ├── Logics.cs │ └── Tags.cs ├── CeresIgnoreInjectAttribute.cs.meta ├── Event.cs ├── Component.cs ├── Builder.cs ├── CeresSettings.cs ├── Logic.cs ├── IntTag.cs └── Entity.cs ├── InsaneOne.CeresECL.asmdef.meta ├── package.json ├── LICENSE.md └── README.md /InsaneOne.CeresECL.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "InsaneOne.CeresECL" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.csproj 3 | *.sln 4 | Library/ 5 | obj/ 6 | Logs/ 7 | -------------------------------------------------------------------------------- /Example/Sources/Events/ColliderHitEvent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4633be333eef4a1e83e414899b9d9f9c 3 | timeCreated: 1596027551 -------------------------------------------------------------------------------- /Example/Sources/Builders/EnemyEntityBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26884141ba554410906c253ffa0c9100 3 | timeCreated: 1596435913 -------------------------------------------------------------------------------- /Example/Sources/TagsList.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | public enum Tag 4 | { 5 | CustomTagA = 0, 6 | CustomTag = 1, 7 | // add your tags here 8 | } 9 | } -------------------------------------------------------------------------------- /Resources/Templates/Event.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Event 6 | { 7 | // add your data here 8 | } 9 | } -------------------------------------------------------------------------------- /Resources/Templates/Component.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Component 6 | { 7 | // add your data here 8 | } 9 | } -------------------------------------------------------------------------------- /Example/Sources/Events/ColliderHitEvent.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | class ColliderHitEvent : Event 6 | { 7 | public Collider2D HitCollider; 8 | } 9 | } -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e19e74eb01309d5419f60e86fc5830b3 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0364b9a17eacd5d46921840d633fdc91 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45bdb62c8ad67ff4d9b4703f3b6a9761 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 464b602021d22a04ca1966a9dce27054 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Prefabs/Bullet.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 359d3f7baf8fa0741b007972bded5780 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example/Prefabs/Enemy.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a6dc0deb30f6c24bab60d9437f02a61 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example/Prefabs/Player.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 55f55aee0fbc8644ba551d4a93ce1833 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 77cee8b6dd83bf8488375d0c67d95dcd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38789b5c6ea2f7044ab6aee22cf1465a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c8ee30eddbefcd489ab0fd49c296a27 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e35f5513bcd93de4e8236c637574951c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Scenes/SampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cda990e2423bbf4892e6590ba056729 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Sources/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9792937346a78114a9f5e23e2974ba8a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3195931cc22cdf4082959a61de15ab9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 564707e2f7662524f9cd259dd3dfaaaa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Components/BulletComponent.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL.Example 2 | { 3 | public class BulletComponent : Component 4 | { 5 | public Entity Owner; 6 | public float Damage; 7 | public float Lifetime; 8 | } 9 | } -------------------------------------------------------------------------------- /InsaneOne.CeresECL.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20f61b99a18cf83488884339898131ac 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources/Templates.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb1de691676d66549a958479f4eec8d9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sources/Containers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45405b812f725f74b9ab99e55797ee52 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sources/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ea7edd88df64c1e43b70c7a243982e2e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Builders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0363661005feed4b8eaca6c1d56e587 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Events.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8468cf9cdf9e8674bb6895a8b50382a3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Logics.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 71903790ebc3e7349a1dc3e469a75907 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Storing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 786d77bd9a06fdd429e1b5fd5e19368b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Components.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 929d2eac66b0c2d4da5d1d4aef3d58e9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/Templates/Builder.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Builder 6 | { 7 | protected override void Build() 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Resources/Templates/RunLogic.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Logic, IRunLogic 6 | { 7 | void IRunLogic.Run() 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Sources/Extensions/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c875d50d4a14ef4c87ecaf8b216766b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/InsaneOne.CeresECL.Example.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06c36705f799c3c43aa23fa5bf3f1c6d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example/Sources/UnityComponents.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57fc0045c0d87bc459acf9db26a77137 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Data/GameData.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a88a39021675e341ad942e5f8949220 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Sources/Builders/EnemyEntityBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL.Example 2 | { 3 | public class EnemyEntityBuilder : Builder 4 | { 5 | protected override void Build() 6 | { 7 | Entity.Logics.Add(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Resources/CeresSettings.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 24651c666244d3b43804c9f18b9d3438 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sources/Editor/InsaneOne.CeresECL.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7cf50b3a199dad841a7466a734dd62f2 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources/Templates/InitLogic.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Logic, IInitLogic 6 | { 7 | void IInitLogic.Init() 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Sources/Components/MoveComponent.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class MoveComponent : Component 6 | { 7 | public float Speed; 8 | public Vector3 Direction; 9 | } 10 | } -------------------------------------------------------------------------------- /Resources/Templates/GameLauncher.txt: -------------------------------------------------------------------------------- 1 | using CeresECL; 2 | 3 | namespace #NAMESPACE# 4 | { 5 | class #SCRIPTNAME# : Launcher 6 | { 7 | protected override void StartAction() 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Sources/CeresIgnoreInjectAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CeresECL 4 | { 5 | /// Use this attribute to ignore injection for specific type field in your Logic. 6 | public sealed class CeresIgnoreInjectAttribute : Attribute { } 7 | } -------------------------------------------------------------------------------- /Resources/Templates/Event.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c84c97c500bc6794f823b9b31eb352c4 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Resources/Templates/Builder.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 479758e76fc117c44856dd892571be16 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Resources/Templates/Component.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1945be9fa3ba9054890d165d7bd52596 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Resources/Templates/InitLogic.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe9be83341cae524b8af848ec16239be 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Resources/Templates/RunLogic.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe0d2851d2012624dbb420ce514688fd 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Resources/Templates/GameLauncher.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d2193937c28a9240b3ebfa80ede8696 3 | labels: 4 | - CeresEcl 5 | - CeresTemplate 6 | TextScriptImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Example/Sources/Builders/BulletEntityBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL.Example 2 | { 3 | public class BulletEntityBuilder : Builder 4 | { 5 | protected override void Build() 6 | { 7 | Entity.Logics.Add(); 8 | Entity.Logics.Add(); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Sources/Builder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ffd90054fc16fb94992f1ceefb654d7c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Entity.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62ec553c730d5684d943e079f94f6934 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Event.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 388bce9cf6b40bb4689b75548908f2a3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/IntTag.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aadaf98869624b642904f032b991f85d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Launcher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd5d29060ac69b94aa2f0f7d9e8aa829 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Logic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 21799770650ecec49bf9f8a4db90eb67 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Builders/PlayerEntityBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL.Example 2 | { 3 | public class PlayerEntityBuilder : Builder 4 | { 5 | protected override void Build() 6 | { 7 | Entity.Logics.Add(); 8 | Entity.Logics.Add(); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Sources/CeresSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2ecfe3bbc28ef44eb2a732255368d9c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Component.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a3d2a4c8d8c37f41ab918c9816af5b4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Launcher.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL 4 | { 5 | public abstract class Launcher : MonoBehaviour 6 | { 7 | void Start() => StartAction(); 8 | 9 | protected abstract void StartAction(); 10 | 11 | void Update() => Entity.UpdateAll(); 12 | } 13 | } -------------------------------------------------------------------------------- /Example/Sources/TagsList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4563df8d4f03e814dbd8fcb39665cbc2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Containers/Events.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a22d9e877b4294a47ac544d7679c6f13 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Containers/Logics.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe77a27b3c161cf49853a438b6b38cf8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Containers/Tags.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5a8c55c146b7ee4a855c8aa938a22dc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Containers/Components.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a906ef3c38ec23a45b6a0ae992d5a4cf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Containers/Container.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 25af947015823ae41a48b37cd21ac267 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Editor/EntityEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 694e15f58bf914b42b04e1d302e668f7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Extensions/Extensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a747fc3d9ef255c4dab9b297c910145d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Logics/BulletLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a93d37b0c09abd240bf510843350897a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Logics/InputLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac8719cc35eb01344a9e028642346fd6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Logics/MoveLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a8bc488fb820414ea35c9f465f187e4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Storing/GameData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0ba61a3ce87b89740a27434ffe6737bd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/CeresIgnoreInjectAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1c9445c51391cd429cf639e30d1c337 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Editor/TemplatesGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 49b4f4dcc0b85524fa8e63310c0c7f73 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Event.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | /// Derive from this class for your custom Events. Event same to Component, but will live only one frame. 4 | public class Event 5 | { 6 | public static implicit operator bool(Event evnt) 7 | { 8 | return !ReferenceEquals(evnt, null); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Example/Sources/Components/MoveComponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae1628eb5cbd03a46a60b6c0bebc2a5b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Component.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | /// Base class to derive your components from. Component should contain only data, no any logics implementations. 4 | public class Component 5 | { 6 | /// Parent entity of this component. 7 | public Entity Entity; 8 | } 9 | } -------------------------------------------------------------------------------- /Sources/Extensions/Editor/EditorHelpers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 022f6798c9d8b934e94fec4f37c253a4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Builders/BulletEntityBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce0ad1d2d4197b840bfbbdc05615c3d1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Builders/PlayerEntityBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20ed22384f5db9649ab2fde4cc350eeb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/Components/BulletComponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f0e0c8967b20f34da88510676149767 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/UnityComponents/CollisionSender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0e42a93113c3ea44a5fb92705f11d8a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/Sources/UnityComponents/ExampleLauncher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff0080920c580854bbf1a70a09a4467d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Sources/Builder.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | /// Builder class is base class to build your entities with your logics. It implements Init Logic. 4 | public abstract class Builder : Logic, IInitLogic 5 | { 6 | void IInitLogic.Init() => Build(); 7 | 8 | protected abstract void Build(); 9 | } 10 | } -------------------------------------------------------------------------------- /Sources/Containers/Container.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | public abstract class Container 4 | { 5 | public Entity Entity { get; } 6 | 7 | protected Container(Entity entity) 8 | { 9 | Entity = entity; 10 | } 11 | 12 | public virtual void Init() { } 13 | public virtual void Run() { } 14 | } 15 | } -------------------------------------------------------------------------------- /Example/Sources/Storing/GameData.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | [CreateAssetMenu(fileName = "GameData", menuName = "Ceres ECL/Example/Game Data")] 6 | public class GameData : ScriptableObject 7 | { 8 | public GameObject PlayerPrefab; 9 | public GameObject BulletPrefab; 10 | public GameObject EnemyPrefab; 11 | } 12 | } -------------------------------------------------------------------------------- /Example/InsaneOne.CeresECL.Example.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "InsaneOne.CeresECL.Example", 3 | "references": [ 4 | "GUID:20f61b99a18cf83488884339898131ac" 5 | ], 6 | "includePlatforms": [], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [], 14 | "noEngineReferences": false 15 | } -------------------------------------------------------------------------------- /Resources/CeresSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: f2ecfe3bbc28ef44eb2a732255368d9c, type: 3} 13 | m_Name: CeresSettings 14 | m_EditorClassIdentifier: 15 | templates: [] 16 | -------------------------------------------------------------------------------- /Sources/Editor/InsaneOne.CeresECL.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "InsaneOne.CeresECL.Editor", 3 | "references": [ 4 | "GUID:20f61b99a18cf83488884339898131ac" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.insaneone.ceresecl", 3 | "author": "InsaneOne", 4 | "displayName": "Ceres ECL", 5 | "description": "Ceres ECL is Entity Component Logic implementation for Unity (C#) by InsaneOne. MIT License.", 6 | "unity": "2019.1", 7 | "version": "0.2.0", 8 | "keywords": [ 9 | "ceresecl", 10 | "ecl", 11 | "insaneone" 12 | ], 13 | "dependencies": {}, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/OlegDzhuraev/CeresECL.git" 17 | } 18 | } -------------------------------------------------------------------------------- /Example/Sources/Logics/MoveLogic.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class MoveLogic : Logic, IInitLogic, IRunLogic 6 | { 7 | MoveComponent moveComponent; 8 | 9 | void IInitLogic.Init() 10 | { 11 | moveComponent = Entity.Components.Get(); 12 | 13 | moveComponent.Speed = 2f; 14 | } 15 | 16 | void IRunLogic.Run() 17 | { 18 | Entity.transform.position += moveComponent.Direction * (moveComponent.Speed * Time.deltaTime); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Sources/UnityComponents/CollisionSender.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class CollisionSender : MonoBehaviour 6 | { 7 | Entity entity; 8 | 9 | void Start() => entity = gameObject.GetEntity(); 10 | 11 | void OnTriggerEnter2D(Collider2D other) 12 | { 13 | if (!entity) 14 | return; 15 | 16 | var hitEvent = new ColliderHitEvent 17 | { 18 | HitCollider = other 19 | }; 20 | 21 | entity.Events.Add(hitEvent); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Sources/CeresSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace CeresECL 5 | { 6 | [CreateAssetMenu(fileName = "CeresSettings", menuName = "Ceres ECL/Settings Asset")] 7 | public class CeresSettings : ScriptableObject 8 | { 9 | public const int MaxEntities = 1000; 10 | public const int MaxEntityLogics = 16; 11 | 12 | public static CeresSettings Instance 13 | { 14 | get 15 | { 16 | if (!instance) 17 | instance = Resources.Load("CeresSettings") as CeresSettings; 18 | 19 | return instance; 20 | } 21 | } 22 | 23 | static CeresSettings instance; 24 | 25 | public Type TagsEnum; 26 | } 27 | } -------------------------------------------------------------------------------- /Example/Data/GameData.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 0ba61a3ce87b89740a27434ffe6737bd, type: 3} 13 | m_Name: GameData 14 | m_EditorClassIdentifier: 15 | PlayerPrefab: {fileID: 1552443546450155103, guid: 55f55aee0fbc8644ba551d4a93ce1833, 16 | type: 3} 17 | BulletPrefab: {fileID: 9159526560964145970, guid: 359d3f7baf8fa0741b007972bded5780, 18 | type: 3} 19 | EnemyPrefab: {fileID: 3372446858887832482, guid: 7a6dc0deb30f6c24bab60d9437f02a61, 20 | type: 3} 21 | -------------------------------------------------------------------------------- /Sources/Logic.cs: -------------------------------------------------------------------------------- 1 | namespace CeresECL 2 | { 3 | /// Base class for any logics implementations. 4 | public abstract class Logic 5 | { 6 | /// Parent entity of this component. 7 | [CeresIgnoreInject] 8 | public Entity Entity; 9 | 10 | [CeresIgnoreInject] 11 | public bool IsInitialized; // C# 8.0 feature for interfaces, so it is there :/ 12 | } 13 | 14 | /// Interface for Initialization logic, which will be runned once when Logic work started. 15 | public interface IInitLogic 16 | { 17 | void Init(); 18 | } 19 | 20 | /// Interface for Run logic, which will be runned in Update cycle. 21 | public interface IRunLogic 22 | { 23 | void Run(); 24 | } 25 | } -------------------------------------------------------------------------------- /Example/Sources/Logics/BulletLogic.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class BulletLogic : Logic, IInitLogic, IRunLogic 6 | { 7 | BulletComponent bulletComponent; 8 | 9 | public void Init() 10 | { 11 | bulletComponent = Entity.Components.Get(); 12 | 13 | Entity.Events.Sub(CheckHit); 14 | } 15 | 16 | void IRunLogic.Run() 17 | { 18 | bulletComponent.Lifetime -= Time.deltaTime; 19 | 20 | if (bulletComponent.Lifetime <= 0) 21 | Entity.Destroy(); 22 | } 23 | 24 | void CheckHit(ColliderHitEvent hitEvent) 25 | { 26 | var otherEntity = hitEvent.HitCollider.GetComponent(); 27 | 28 | if (otherEntity != bulletComponent.Owner) 29 | { 30 | Debug.Log("Hit " + otherEntity); 31 | 32 | Entity.Destroy(); 33 | otherEntity.Destroy(); // todo CeresECL add health example 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sources/IntTag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CeresECL 4 | { 5 | public readonly struct IntTag 6 | { 7 | readonly int value; 8 | 9 | IntTag(int value) => this.value = value; 10 | 11 | public static implicit operator IntTag(Enum enumerator) => new IntTag((int)(object)enumerator); 12 | public static implicit operator IntTag(int value) => new IntTag(value); 13 | 14 | public static explicit operator int(IntTag intTag) => intTag.value; 15 | 16 | public static bool operator ==(IntTag tag, int integer) => tag.value == integer; 17 | public static bool operator !=(IntTag tag, int integer) => tag.value != integer; 18 | 19 | public override string ToString() => value.ToString(); 20 | 21 | public bool Equals(IntTag other) => value == other.value; 22 | public override bool Equals(object tag) => tag is IntTag other && Equals(other); 23 | public override int GetHashCode() => value; 24 | } 25 | } -------------------------------------------------------------------------------- /Sources/Extensions/Editor/EditorHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace CeresECL.Misc 6 | { 7 | public static class EditorHelpers 8 | { 9 | public static Texture2D GetColoredTexture(Color color) 10 | { 11 | var texture = new Texture2D(1, 1); 12 | texture.SetPixel(0, 0, color); 13 | texture.Apply(); 14 | 15 | return texture; 16 | } 17 | 18 | public static void LoadAssetsToList(List listToAddIn, string searchFilter) where T : UnityEngine.Object 19 | { 20 | listToAddIn.Clear(); 21 | 22 | var assets = AssetDatabase.FindAssets(searchFilter); 23 | 24 | for (int i = 0; i < assets.Length; i++) 25 | { 26 | var asset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(assets[i]), typeof(T)) as T; 27 | listToAddIn.Add(asset); 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 InsaneOne godlikeaurora@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Example/Sources/UnityComponents/ExampleLauncher.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class ExampleLauncher : Launcher 6 | { 7 | [SerializeField] GameData gameData; 8 | 9 | protected override void StartAction() 10 | { 11 | CeresSettings.Instance.TagsEnum = typeof(Tag); 12 | 13 | var mainCamera = Camera.main; 14 | 15 | // it is better to spawn system, which will handle all game start process. 16 | 17 | var playerEnt = Entity.Spawn(gameData.PlayerPrefab); 18 | 19 | playerEnt.Logics.Inject(gameData); 20 | playerEnt.Logics.Inject(mainCamera); 21 | 22 | for (int i = 0; i < 3; i++) 23 | { 24 | var enemyEnt = Entity.Spawn(gameData.EnemyPrefab); 25 | 26 | enemyEnt.Logics.Inject(gameData); 27 | enemyEnt.Logics.Inject(mainCamera); 28 | 29 | enemyEnt.transform.position = new Vector2(Random.Range(-3f, 3f), Random.Range(-3f, 3f)); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Sources/Extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL 4 | { 5 | public static class Extensions 6 | { 7 | /// Short version of gameObject.GetComponent Entity (); for MonoBehaviour connections to Ceres ECL. Can return null if object is not Entity. 8 | public static Entity GetEntity(this GameObject gameObject) => gameObject.GetComponent(); 9 | 10 | /// Returns Component of specified type. Not affects Unity default components because requires T derived from Component - only for game logics. 11 | public static T Get(this GameObject gameObject) where T : Component => gameObject.GetComponent(); 12 | 13 | /// Returns true if game object have Component of specified type. Not affects Unity default components because requires T derived from Component - only for game logics. 14 | public static bool Have(this GameObject gameObject) where T : Component => gameObject.Get() != null; 15 | 16 | /// Short version of gameObject.GetComponent Entity (); for MonoBehaviour connections to ECL. Can return null if object is not Entity. 17 | public static Entity GetEntity(this MonoBehaviour monoBeh) => monoBeh.GetComponent(); 18 | 19 | /// Returns Component of specified type. Not affects Unity default components because requires T derived from Component - only for game logics. 20 | public static T Get(this MonoBehaviour monoBeh) where T : Component => monoBeh.GetComponent(); 21 | 22 | /// Returns true if game object have Component of specified type. Not affects Unity default components because requires T derived from Component - only for game logics. 23 | public static bool Have(this MonoBehaviour monoBeh) where T : Component => monoBeh.Get() != null; 24 | } 25 | } -------------------------------------------------------------------------------- /Example/Sources/Logics/InputLogic.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace CeresECL.Example 4 | { 5 | public class InputLogic : Logic, IInitLogic, IRunLogic 6 | { 7 | GameData gameData; 8 | Camera mainCamera; 9 | MoveComponent moveComponent; 10 | 11 | void IInitLogic.Init() 12 | { 13 | moveComponent = Entity.Components.Get(); 14 | } 15 | 16 | void IRunLogic.Run() 17 | { 18 | HandleMove(); 19 | 20 | if (Input.GetMouseButtonDown(0)) 21 | DoShoot(); 22 | } 23 | 24 | void HandleMove() 25 | { 26 | var x = Input.GetAxis("Horizontal"); 27 | var y = Input.GetAxis("Vertical"); 28 | 29 | moveComponent.Direction = new Vector3(x, y, 0); 30 | } 31 | 32 | // todo move to separated shooting logic, keep only input events in this class 33 | void DoShoot() 34 | { 35 | var selfPosition = Entity.transform.position; 36 | 37 | var mouseWorldPosition = mainCamera.ScreenToWorldPoint(Input.mousePosition); 38 | mouseWorldPosition.z = selfPosition.z; 39 | 40 | var shootDirection = (mouseWorldPosition - selfPosition).normalized; 41 | 42 | var bullet = Entity.Spawn(gameData.BulletPrefab); 43 | bullet.transform.position = selfPosition; 44 | 45 | var bulletMoveComponent = bullet.Components.Get(); 46 | 47 | bulletMoveComponent.Direction = shootDirection; 48 | bulletMoveComponent.Speed = 6; 49 | 50 | var bulletComponent = bullet.Components.Get(); 51 | bulletComponent.Owner = Entity; 52 | bulletComponent.Damage = 15; 53 | bulletComponent.Lifetime = 5; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Sources/Containers/Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CeresECL 5 | { 6 | public sealed class Components : Container 7 | { 8 | readonly List components = new List(); 9 | 10 | public Components(Entity entity) : base(entity) { } 11 | 12 | /// Get (with add if dont exist) any of game Components. 13 | public T Get() where T : Component, new() 14 | { 15 | foreach (var component in components) 16 | if (component is T resultComponent) 17 | return resultComponent; 18 | 19 | var newComponent = new T 20 | { 21 | Entity = Entity 22 | }; 23 | 24 | components.Add(newComponent); 25 | 26 | return newComponent; 27 | } 28 | 29 | /// Get (with add if dont exist) any of game Components. 30 | public Component Get(Type componentType) 31 | { 32 | if (!typeof(Component).IsAssignableFrom(componentType)) 33 | return null; 34 | 35 | foreach (var comp in components) 36 | if (comp.GetType() == componentType) 37 | return comp; 38 | 39 | var newComponent = Activator.CreateInstance(componentType) as Component; 40 | newComponent.Entity = Entity; 41 | components.Add(newComponent); 42 | 43 | return newComponent; 44 | } 45 | 46 | public bool Have() where T : Component 47 | { 48 | foreach (var component in components) 49 | if (component is T) 50 | return true; 51 | 52 | return false; 53 | } 54 | 55 | public void Delete() where T : Component 56 | { 57 | foreach (var component in components) 58 | if (component is T) 59 | components.Remove(component); 60 | } 61 | 62 | /// Used only for editor scripting. 63 | public List GetListEditor() 64 | { 65 | var list = new List(); 66 | 67 | for (var i = 0; i < components.Count; i++) 68 | list.Add(components[i]); 69 | 70 | return list; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Sources/Containers/Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CeresECL 5 | { 6 | public sealed class Events : Container 7 | { 8 | readonly Dictionary> subscribers = new Dictionary>(); 9 | readonly Dictionary, int> addedDelegates = new Dictionary, int>(); 10 | 11 | /// Method allows send Event to the entity. 12 | public void Add(T newEvent) where T : Event 13 | { 14 | var type = newEvent.GetType(); 15 | 16 | if (subscribers.ContainsKey(type)) 17 | subscribers[type].Invoke(newEvent); 18 | } 19 | 20 | /// Simplier version of Add. If you do not need to pass any data to this event. 21 | public void Add() where T : Event, new() => Add(new T()); 22 | 23 | public void Sub(Action action) where T : Event => 24 | Sub(typeof(T), e => action?.Invoke((T) e), action.GetHashCode()); 25 | 26 | public void Sub(Action action) where T : Event => 27 | Sub(typeof(T), e => action?.Invoke(), action.GetHashCode()); 28 | 29 | void Sub(Type type, Action eventDelegate, int rawActionHash) 30 | { 31 | if (!subscribers.ContainsKey(type)) 32 | subscribers.Add(type, eventDelegate); 33 | else 34 | subscribers[type] += eventDelegate; 35 | 36 | addedDelegates.Add(eventDelegate, 37 | rawActionHash); // subs to same method have same hash codes, so this is easy way to check connection between method and action 38 | } 39 | 40 | public void Unsub(Action action) where T : Event => Unsub(action.GetHashCode()); 41 | public void Unsub(Action action) where T : Event => Unsub(action.GetHashCode()); 42 | 43 | void Unsub(int actionHash) where T : Event 44 | { 45 | var type = typeof(T); 46 | 47 | foreach (var keyValuePair in addedDelegates) 48 | if (keyValuePair.Value == actionHash) 49 | { 50 | subscribers[type] -= keyValuePair.Key; 51 | 52 | if (subscribers[type] == null) 53 | subscribers.Remove(type); 54 | 55 | addedDelegates.Remove(keyValuePair.Key); 56 | 57 | break; 58 | } 59 | } 60 | 61 | public Events(Entity entity) : base(entity) { } 62 | } 63 | } -------------------------------------------------------------------------------- /Sources/Containers/Logics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using UnityEngine; 5 | 6 | namespace CeresECL 7 | { 8 | public sealed class Logics : Container 9 | { 10 | readonly Logic[] logics = new Logic[CeresSettings.MaxEntityLogics]; 11 | int logicsCount; 12 | 13 | readonly List injects = new List(); 14 | 15 | public Logics(Entity entity) : base(entity) { } 16 | 17 | public override void Run() 18 | { 19 | for (int i = 0; i < logicsCount; i++) 20 | { 21 | var logic = logics[i]; 22 | 23 | if (!logic.IsInitialized && logic is IInitLogic initLogic) 24 | { 25 | initLogic.Init(); 26 | logic.IsInitialized = true; // C# 8.0 feature, so this is here :/ 27 | } 28 | 29 | if (logic is IRunLogic runLogic) 30 | runLogic.Run(); 31 | } 32 | } 33 | 34 | public void Add() where T : Logic, new() 35 | { 36 | if (logicsCount == CeresSettings.MaxEntityLogics) 37 | { 38 | Debug.LogWarning("You're trying to add more logics than it is allowed. Change CeresSettings parameters to allow it."); 39 | return; 40 | } 41 | 42 | if (Have()) 43 | return; 44 | 45 | var newLogic = new T 46 | { 47 | Entity = Entity 48 | }; 49 | 50 | for (var i = 0; i < injects.Count; i++) 51 | Inject(newLogic, injects[i]); 52 | 53 | logics[logicsCount] = newLogic; 54 | logicsCount++; 55 | } 56 | 57 | public bool Have() where T : Logic 58 | { 59 | for (var i = 0; i < logicsCount; i++) 60 | if (logics[i] is T) 61 | return true; 62 | 63 | return false; 64 | } 65 | 66 | void Inject(Logic inLogic, object data) 67 | { 68 | var dataType = data.GetType(); 69 | 70 | var bindingAttribute = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; 71 | var ignoreAttribute = typeof(CeresIgnoreInjectAttribute); 72 | 73 | var logicType = inLogic.GetType(); 74 | 75 | foreach (var field in logicType.GetFields(bindingAttribute)) 76 | { 77 | if (field.IsStatic || Attribute.IsDefined(field, ignoreAttribute)) 78 | continue; 79 | 80 | if (field.FieldType.IsAssignableFrom(dataType)) 81 | { 82 | field.SetValue(inLogic, data); 83 | break; 84 | } 85 | } 86 | } 87 | 88 | /// Method allows you inject any data to all Entity logics. 89 | public void Inject(object data) 90 | { 91 | if (!injects.Contains(data)) 92 | injects.Add(data); 93 | 94 | for (var i = 0; i < logicsCount; i++) 95 | Inject(logics[i], data); 96 | } 97 | 98 | /// Used only for editor scripting. 99 | public List GetListEditor() 100 | { 101 | var list = new List(); 102 | 103 | for (var i = 0; i < logicsCount; i++) 104 | list.Add(logics[i]); 105 | 106 | return list; 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /Example/Prefabs/Enemy.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &3372446858887832482 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 3372446858887832486} 12 | - component: {fileID: 3372446858887832487} 13 | - component: {fileID: 3372446858887832480} 14 | - component: {fileID: 3372446858887832481} 15 | m_Layer: 0 16 | m_Name: Enemy 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &3372446858887832486 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 3372446858887832482} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 3, y: 0, z: 0} 31 | m_LocalScale: {x: 2, y: 2, z: 2} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!212 &3372446858887832487 37 | SpriteRenderer: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 3372446858887832482} 43 | m_Enabled: 1 44 | m_CastShadows: 0 45 | m_ReceiveShadows: 0 46 | m_DynamicOccludee: 1 47 | m_MotionVectors: 1 48 | m_LightProbeUsage: 1 49 | m_ReflectionProbeUsage: 1 50 | m_RayTracingMode: 0 51 | m_RenderingLayerMask: 1 52 | m_RendererPriority: 0 53 | m_Materials: 54 | - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} 55 | m_StaticBatchInfo: 56 | firstSubMesh: 0 57 | subMeshCount: 0 58 | m_StaticBatchRoot: {fileID: 0} 59 | m_ProbeAnchor: {fileID: 0} 60 | m_LightProbeVolumeOverride: {fileID: 0} 61 | m_ScaleInLightmap: 1 62 | m_ReceiveGI: 1 63 | m_PreserveUVs: 0 64 | m_IgnoreNormalsForChartDetection: 0 65 | m_ImportantGI: 0 66 | m_StitchLightmapSeams: 1 67 | m_SelectedEditorRenderState: 0 68 | m_MinimumChartSize: 4 69 | m_AutoUVMaxDistance: 0.5 70 | m_AutoUVMaxAngle: 89 71 | m_LightmapParameters: {fileID: 0} 72 | m_SortingLayerID: 0 73 | m_SortingLayer: 0 74 | m_SortingOrder: 0 75 | m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} 76 | m_Color: {r: 1, g: 0.6745283, b: 0.6745283, a: 1} 77 | m_FlipX: 0 78 | m_FlipY: 0 79 | m_DrawMode: 0 80 | m_Size: {x: 0.2, y: 0.2} 81 | m_AdaptiveModeThreshold: 0.5 82 | m_SpriteTileMode: 0 83 | m_WasSpriteAssigned: 1 84 | m_MaskInteraction: 0 85 | m_SpriteSortPoint: 0 86 | --- !u!58 &3372446858887832480 87 | CircleCollider2D: 88 | m_ObjectHideFlags: 0 89 | m_CorrespondingSourceObject: {fileID: 0} 90 | m_PrefabInstance: {fileID: 0} 91 | m_PrefabAsset: {fileID: 0} 92 | m_GameObject: {fileID: 3372446858887832482} 93 | m_Enabled: 1 94 | m_Density: 1 95 | m_Material: {fileID: 0} 96 | m_IsTrigger: 1 97 | m_UsedByEffector: 0 98 | m_UsedByComposite: 0 99 | m_Offset: {x: 0, y: 0} 100 | serializedVersion: 2 101 | m_Radius: 0.1 102 | --- !u!50 &3372446858887832481 103 | Rigidbody2D: 104 | serializedVersion: 4 105 | m_ObjectHideFlags: 0 106 | m_CorrespondingSourceObject: {fileID: 0} 107 | m_PrefabInstance: {fileID: 0} 108 | m_PrefabAsset: {fileID: 0} 109 | m_GameObject: {fileID: 3372446858887832482} 110 | m_BodyType: 1 111 | m_Simulated: 1 112 | m_UseFullKinematicContacts: 0 113 | m_UseAutoMass: 0 114 | m_Mass: 1 115 | m_LinearDrag: 0 116 | m_AngularDrag: 0.05 117 | m_GravityScale: 1 118 | m_Material: {fileID: 0} 119 | m_Interpolate: 0 120 | m_SleepingMode: 1 121 | m_CollisionDetection: 0 122 | m_Constraints: 0 123 | -------------------------------------------------------------------------------- /Sources/Containers/Tags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CeresECL 5 | { 6 | public sealed class Tags : Container 7 | { 8 | /// Subscribers of event when tag was added. Event doesnt raised when second same tag added. 9 | readonly Dictionary> addSubscribers = new Dictionary>(); 10 | 11 | /// Subscribers of event when tag was removed. Event is being raised when last tag of some type was removed. 12 | readonly Dictionary> removeSubscribers = new Dictionary>(); 13 | 14 | readonly Dictionary addedTags = new Dictionary(); 15 | 16 | public Tags(Entity entity) : base(entity) { } 17 | 18 | public void Add(params IntTag[] tags) 19 | { 20 | foreach (var tag in tags) 21 | if (HaveAny(tag)) 22 | addedTags[tag]++; 23 | else 24 | FirstAddTag(tag); 25 | } 26 | 27 | public void AddOnce(params IntTag[] tags) 28 | { 29 | foreach (var tag in tags) 30 | if (!HaveAny(tag)) 31 | FirstAddTag(tag); 32 | } 33 | 34 | void FirstAddTag(IntTag tag) 35 | { 36 | addedTags.Add(tag, 1); 37 | InvokeActions(tag, addSubscribers); 38 | } 39 | 40 | public void Remove(params IntTag[] tags) 41 | { 42 | foreach (var tag in tags) 43 | { 44 | if (!HaveAny(tag)) 45 | return; 46 | 47 | addedTags[tag]--; 48 | 49 | if (addedTags[tag] > 0) 50 | continue; 51 | 52 | addedTags.Remove(tag); 53 | InvokeActions(tag, removeSubscribers); 54 | } 55 | } 56 | 57 | void InvokeActions(IntTag tag, Dictionary> dict) 58 | { 59 | if (dict.ContainsKey(tag)) 60 | foreach (var action in dict[tag]) 61 | action?.Invoke(); 62 | } 63 | 64 | public int Count(IntTag tag) 65 | { 66 | addedTags.TryGetValue(tag, out var count); 67 | 68 | return count; 69 | } 70 | 71 | public bool Have(IntTag tag) => addedTags.ContainsKey(tag); 72 | 73 | public bool HaveAny(params IntTag[] tags) 74 | { 75 | foreach (var tag in tags) 76 | if (Have(tag)) 77 | return true; 78 | 79 | return false; 80 | } 81 | 82 | public bool HaveAll(params IntTag[] tags) 83 | { 84 | foreach (var tag in tags) 85 | if (!Have(tag)) 86 | return false; 87 | 88 | return true; 89 | } 90 | 91 | public void SubscribeToAdd(IntTag tag, Action action) => AddToDict(addSubscribers, tag, action); 92 | public void UnsubscribeFromAdd(IntTag tag, Action action) => DelFromDict(addSubscribers, tag, action); 93 | 94 | public void SubscribeToRemove(IntTag tag, Action action) => AddToDict(removeSubscribers, tag, action); 95 | public void UnsubscribeFromRemove(IntTag tag, Action action) => DelFromDict(removeSubscribers, tag, action); 96 | 97 | static void AddToDict(Dictionary> dict, IntTag tag, Action action) 98 | { 99 | if (!dict.ContainsKey(tag)) 100 | dict[tag] = new List(); 101 | 102 | dict[tag].Add(action); 103 | } 104 | 105 | static void DelFromDict(Dictionary> dict, IntTag tag, Action action) 106 | { 107 | if (dict.ContainsKey(tag)) 108 | dict[tag].Remove(action); 109 | } 110 | 111 | /// Only for editor debug. 112 | public Dictionary GetTagsCopy() => new Dictionary(addedTags); 113 | } 114 | } -------------------------------------------------------------------------------- /Sources/Editor/TemplatesGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using UnityEditor; 6 | using UnityEditor.ProjectWindowCallback; 7 | using UnityEngine; 8 | 9 | namespace CeresECL 10 | { 11 | public static class TemplatesGenerator 12 | { 13 | [MenuItem ("Assets/Create/Ceres ECL/Component template", false, -199)] 14 | static void CreateComponentTemplate() => CreateAnyFromTemplate("Component"); 15 | 16 | [MenuItem ("Assets/Create/Ceres ECL/Init Logic template", false, -199)] 17 | static void CreateInitLogicTemplate() => CreateAnyFromTemplate("InitLogic"); 18 | 19 | [MenuItem ("Assets/Create/Ceres ECL/Run Logic template", false, -199)] 20 | static void CreateRunLogicTemplate() => CreateAnyFromTemplate("RunLogic"); 21 | 22 | [MenuItem ("Assets/Create/Ceres ECL/Builder template", false, -199)] 23 | static void CreateBuilderTemplate() => CreateAnyFromTemplate("Builder"); 24 | 25 | [MenuItem ("Assets/Create/Ceres ECL/Event template", false, -199)] 26 | static void CreateEventTemplate() => CreateAnyFromTemplate("Event"); 27 | 28 | [MenuItem ("Assets/Create/Ceres ECL/Launcher template", false, -199)] 29 | static void CreateLauncherTemplate() => CreateAnyFromTemplate("GameLauncher"); 30 | 31 | static void CreateAnyFromTemplate(string templateName) 32 | { 33 | var fileName = $"{GetSelectionPath()}/Ceres{templateName}.cs"; 34 | CreateAndRenameAsset(fileName, GetIcon(), name => CreateTemplateInternal(GetTemplateContent(templateName), name)); 35 | } 36 | 37 | static string CreateFromTemplate(string template, string fileName) 38 | { 39 | if (string.IsNullOrEmpty(fileName)) 40 | return "Invalid filename"; 41 | 42 | var namespaceName = EditorSettings.projectGenerationRootNamespace.Trim(); 43 | 44 | if (string.IsNullOrEmpty(EditorSettings.projectGenerationRootNamespace)) 45 | namespaceName = "CeresECL"; 46 | 47 | template = template.Replace("#NAMESPACE#", namespaceName); 48 | template = template.Replace("#SCRIPTNAME#", SanitizeClassName(Path.GetFileNameWithoutExtension(fileName))); 49 | 50 | try 51 | { 52 | File.WriteAllText(AssetDatabase.GenerateUniqueAssetPath(fileName), template); 53 | } 54 | catch (Exception ex) 55 | { 56 | return ex.Message; 57 | } 58 | 59 | AssetDatabase.Refresh (); 60 | 61 | return null; 62 | } 63 | 64 | static string SanitizeClassName(string className) 65 | { 66 | var sb = new StringBuilder(); 67 | var needUp = true; 68 | 69 | foreach (var c in className) 70 | { 71 | if (char.IsLetterOrDigit(c)) 72 | { 73 | sb.Append (needUp ? char.ToUpperInvariant(c) : c); 74 | needUp = false; 75 | } 76 | else 77 | { 78 | needUp = true; 79 | } 80 | } 81 | 82 | return sb.ToString(); 83 | } 84 | 85 | static string GetSelectionPath() 86 | { 87 | var path = AssetDatabase.GetAssetPath(Selection.activeObject); 88 | 89 | if (!string.IsNullOrEmpty(path) && AssetDatabase.Contains(Selection.activeObject)) 90 | { 91 | if (!AssetDatabase.IsValidFolder(path)) 92 | path = Path.GetDirectoryName(path); 93 | } 94 | else 95 | { 96 | path = "Assets"; 97 | } 98 | 99 | return path; 100 | } 101 | 102 | static string CreateTemplateInternal(string template, string fileName) 103 | { 104 | var result = CreateFromTemplate(template, fileName); 105 | if (result != null) 106 | EditorUtility.DisplayDialog("Ceres ECL", result, "Close"); 107 | 108 | return result; 109 | } 110 | 111 | static Texture2D GetIcon() => EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D; 112 | 113 | static void CreateAndRenameAsset(string fileName, Texture2D icon, Action onSuccess) 114 | { 115 | var action = ScriptableObject.CreateInstance(); 116 | action.Callback = onSuccess; 117 | ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, action, fileName, icon, null); 118 | } 119 | 120 | static string GetTemplateContent(string templateName) 121 | { 122 | var templates = new List(); 123 | Misc.EditorHelpers.LoadAssetsToList(templates, "l: CeresTemplate"); 124 | 125 | var template = templates.Find(t => t.name.Contains(templateName)); 126 | 127 | return template ? template.text : "No template found"; 128 | } 129 | 130 | sealed class CustomEndNameAction : EndNameEditAction 131 | { 132 | [NonSerialized] public Action Callback; 133 | 134 | public override void Action(int instanceId, string pathName, string resourceFile) 135 | { 136 | Callback?.Invoke(pathName); 137 | } 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /Sources/Entity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace CeresECL 5 | { 6 | /// Container for all components and logics of your object. Also it is MonoBehaviour, so you can use it as the connection to the Unity API. 7 | [DisallowMultipleComponent] 8 | public sealed class Entity : MonoBehaviour 9 | { 10 | static readonly List entities = new List(CeresSettings.MaxEntities); 11 | 12 | public Tags Tags { get; private set; } 13 | public Components Components { get; private set; } 14 | public Events Events => events; 15 | public Logics Logics => logics; 16 | 17 | Logics logics; 18 | Events events; 19 | 20 | void Awake() 21 | { 22 | Tags = new Tags(this); 23 | Components = new Components(this); 24 | 25 | events = new Events(this); 26 | logics = new Logics(this); 27 | 28 | entities.Add(this); 29 | } 30 | 31 | void Run() => logics.Run(); 32 | 33 | public void Destroy() 34 | { 35 | entities.Remove(this); 36 | 37 | Destroy(gameObject); 38 | } 39 | 40 | public static void UpdateAll() 41 | { 42 | for (var i = 0; i < entities.Count; i++) 43 | entities[i].Run(); 44 | } 45 | 46 | /// Returns all Entities with specific component. Something like FindObjectsOfType, but faster and works with Ceres ECL. 47 | public static List FindAllWith() where T : Component 48 | { 49 | var resultList = new List(); 50 | 51 | for (var i = 0; i < entities.Count; i++) 52 | if (entities[i].Components.Have()) 53 | resultList.Add(entities[i]); 54 | 55 | return resultList; 56 | } 57 | 58 | /// Returns Entity with specified Component. Like FindObjectOfType, but faster. 59 | public static Entity FindWith() where T : Component 60 | { 61 | for (var i = 0; i < entities.Count; i++) 62 | if (entities[i].Components.Have()) 63 | return entities[i]; 64 | 65 | return null; 66 | } 67 | 68 | /// Returns Entity with specified Tag. Like Unity Find method. 69 | public static Entity FindWith(IntTag tag) 70 | { 71 | for (var i = 0; i < entities.Count; i++) 72 | if (entities[i].Tags.Have(tag)) 73 | return entities[i]; 74 | 75 | return null; 76 | } 77 | 78 | /// Returns all Entities with specified Tag. Like Unity Find method. 79 | public static List FindAllWith(IntTag tag) 80 | { 81 | var resultList = new List(); 82 | 83 | for (var i = 0; i < entities.Count; i++) 84 | if (entities[i].Tags.Have(tag)) 85 | resultList.Add(entities[i]); 86 | 87 | return resultList; 88 | } 89 | 90 | /// Finds specified Component on level. If there several Components of this type on level, you receive only one of them - which was created first. 91 | public static T FindComponent() where T : Component, new() 92 | { 93 | for (var i = 0; i < entities.Count; i++) 94 | if (entities[i].Components.Have()) 95 | return entities[i].Components.Get(); 96 | 97 | return null; 98 | } 99 | 100 | /// Finds all of specified Component on level. 101 | public static List FindAllComponents() where T : Component, new() 102 | { 103 | var list = new List(); 104 | 105 | for (var i = 0; i < entities.Count; i++) 106 | if (entities[i].Components.Have()) 107 | list.Add(entities[i].Components.Get()); 108 | 109 | return list; 110 | } 111 | 112 | public static Entity Spawn(GameObject withPrefab) where T : Builder, new() 113 | { 114 | var entObject = Instantiate(withPrefab); 115 | 116 | return BuildEntity(entObject); 117 | } 118 | 119 | public static Entity Spawn() where T : Builder, new() 120 | { 121 | var entObject = new GameObject("Entity"); 122 | 123 | return BuildEntity(entObject); 124 | } 125 | 126 | /// Spawn empty Entity. Not recommended - use Spawn with Builder argument. 127 | public static Entity Spawn() 128 | { 129 | var entObject = new GameObject("Entity"); 130 | 131 | return BuildEntity(entObject); 132 | } 133 | 134 | static Entity BuildEntity(GameObject entObject) where T : Builder, new() 135 | { 136 | var entity = BuildEntity(entObject); 137 | 138 | entity.logics.Add(); 139 | 140 | return entity; 141 | } 142 | 143 | static Entity BuildEntity(GameObject entObject) 144 | { 145 | var entity = entObject.GetComponent(); 146 | 147 | if (!entity) 148 | entity = entObject.AddComponent(); 149 | 150 | return entity; 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /Example/Prefabs/Bullet.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &9159526560964145970 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 9159526560964145972} 12 | - component: {fileID: 9159526560964145971} 13 | - component: {fileID: 9159526560964145973} 14 | - component: {fileID: 5265268592354946481} 15 | - component: {fileID: 2771371679451237986} 16 | m_Layer: 0 17 | m_Name: Bullet 18 | m_TagString: Untagged 19 | m_Icon: {fileID: 0} 20 | m_NavMeshLayer: 0 21 | m_StaticEditorFlags: 0 22 | m_IsActive: 1 23 | --- !u!4 &9159526560964145972 24 | Transform: 25 | m_ObjectHideFlags: 0 26 | m_CorrespondingSourceObject: {fileID: 0} 27 | m_PrefabInstance: {fileID: 0} 28 | m_PrefabAsset: {fileID: 0} 29 | m_GameObject: {fileID: 9159526560964145970} 30 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 31 | m_LocalPosition: {x: 0, y: 0, z: 0} 32 | m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} 33 | m_Children: [] 34 | m_Father: {fileID: 0} 35 | m_RootOrder: 0 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | --- !u!212 &9159526560964145971 38 | SpriteRenderer: 39 | m_ObjectHideFlags: 0 40 | m_CorrespondingSourceObject: {fileID: 0} 41 | m_PrefabInstance: {fileID: 0} 42 | m_PrefabAsset: {fileID: 0} 43 | m_GameObject: {fileID: 9159526560964145970} 44 | m_Enabled: 1 45 | m_CastShadows: 0 46 | m_ReceiveShadows: 0 47 | m_DynamicOccludee: 1 48 | m_MotionVectors: 1 49 | m_LightProbeUsage: 1 50 | m_ReflectionProbeUsage: 1 51 | m_RayTracingMode: 0 52 | m_RenderingLayerMask: 1 53 | m_RendererPriority: 0 54 | m_Materials: 55 | - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} 56 | m_StaticBatchInfo: 57 | firstSubMesh: 0 58 | subMeshCount: 0 59 | m_StaticBatchRoot: {fileID: 0} 60 | m_ProbeAnchor: {fileID: 0} 61 | m_LightProbeVolumeOverride: {fileID: 0} 62 | m_ScaleInLightmap: 1 63 | m_ReceiveGI: 1 64 | m_PreserveUVs: 0 65 | m_IgnoreNormalsForChartDetection: 0 66 | m_ImportantGI: 0 67 | m_StitchLightmapSeams: 1 68 | m_SelectedEditorRenderState: 0 69 | m_MinimumChartSize: 4 70 | m_AutoUVMaxDistance: 0.5 71 | m_AutoUVMaxAngle: 89 72 | m_LightmapParameters: {fileID: 0} 73 | m_SortingLayerID: 0 74 | m_SortingLayer: 0 75 | m_SortingOrder: 0 76 | m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} 77 | m_Color: {r: 1, g: 0.8653269, b: 0.4198113, a: 1} 78 | m_FlipX: 0 79 | m_FlipY: 0 80 | m_DrawMode: 0 81 | m_Size: {x: 0.2, y: 0.2} 82 | m_AdaptiveModeThreshold: 0.5 83 | m_SpriteTileMode: 0 84 | m_WasSpriteAssigned: 1 85 | m_MaskInteraction: 0 86 | m_SpriteSortPoint: 0 87 | --- !u!96 &9159526560964145973 88 | TrailRenderer: 89 | serializedVersion: 2 90 | m_ObjectHideFlags: 0 91 | m_CorrespondingSourceObject: {fileID: 0} 92 | m_PrefabInstance: {fileID: 0} 93 | m_PrefabAsset: {fileID: 0} 94 | m_GameObject: {fileID: 9159526560964145970} 95 | m_Enabled: 1 96 | m_CastShadows: 1 97 | m_ReceiveShadows: 1 98 | m_DynamicOccludee: 1 99 | m_MotionVectors: 0 100 | m_LightProbeUsage: 0 101 | m_ReflectionProbeUsage: 0 102 | m_RayTracingMode: 0 103 | m_RenderingLayerMask: 1 104 | m_RendererPriority: 0 105 | m_Materials: 106 | - {fileID: 10306, guid: 0000000000000000f000000000000000, type: 0} 107 | m_StaticBatchInfo: 108 | firstSubMesh: 0 109 | subMeshCount: 0 110 | m_StaticBatchRoot: {fileID: 0} 111 | m_ProbeAnchor: {fileID: 0} 112 | m_LightProbeVolumeOverride: {fileID: 0} 113 | m_ScaleInLightmap: 1 114 | m_ReceiveGI: 1 115 | m_PreserveUVs: 0 116 | m_IgnoreNormalsForChartDetection: 0 117 | m_ImportantGI: 0 118 | m_StitchLightmapSeams: 1 119 | m_SelectedEditorRenderState: 3 120 | m_MinimumChartSize: 4 121 | m_AutoUVMaxDistance: 0.5 122 | m_AutoUVMaxAngle: 89 123 | m_LightmapParameters: {fileID: 0} 124 | m_SortingLayerID: 0 125 | m_SortingLayer: 0 126 | m_SortingOrder: 0 127 | m_Time: 0.5 128 | m_Parameters: 129 | serializedVersion: 3 130 | widthMultiplier: 0.05 131 | widthCurve: 132 | serializedVersion: 2 133 | m_Curve: 134 | - serializedVersion: 3 135 | time: 0 136 | value: 1 137 | inSlope: 0 138 | outSlope: 0 139 | tangentMode: 0 140 | weightedMode: 0 141 | inWeight: 0.33333334 142 | outWeight: 0.33333334 143 | - serializedVersion: 3 144 | time: 1 145 | value: 0 146 | inSlope: 0 147 | outSlope: 0 148 | tangentMode: 0 149 | weightedMode: 0 150 | inWeight: 0 151 | outWeight: 0 152 | m_PreInfinity: 2 153 | m_PostInfinity: 2 154 | m_RotationOrder: 4 155 | colorGradient: 156 | serializedVersion: 2 157 | key0: {r: 1, g: 0.8657416, b: 0.627451, a: 0} 158 | key1: {r: 1, g: 0.8657416, b: 0.627451, a: 0.9647059} 159 | key2: {r: 0, g: 0, b: 0, a: 0} 160 | key3: {r: 0, g: 0, b: 0, a: 0} 161 | key4: {r: 0, g: 0, b: 0, a: 0} 162 | key5: {r: 0, g: 0, b: 0, a: 0} 163 | key6: {r: 0, g: 0, b: 0, a: 0} 164 | key7: {r: 0, g: 0, b: 0, a: 0} 165 | ctime0: 0 166 | ctime1: 65535 167 | ctime2: 0 168 | ctime3: 0 169 | ctime4: 0 170 | ctime5: 0 171 | ctime6: 0 172 | ctime7: 0 173 | atime0: 0 174 | atime1: 2313 175 | atime2: 65535 176 | atime3: 0 177 | atime4: 0 178 | atime5: 0 179 | atime6: 0 180 | atime7: 0 181 | m_Mode: 0 182 | m_NumColorKeys: 2 183 | m_NumAlphaKeys: 3 184 | numCornerVertices: 0 185 | numCapVertices: 0 186 | alignment: 0 187 | textureMode: 0 188 | shadowBias: 0.5 189 | generateLightingData: 0 190 | m_MinVertexDistance: 0.1 191 | m_Autodestruct: 0 192 | m_Emitting: 1 193 | --- !u!114 &5265268592354946481 194 | MonoBehaviour: 195 | m_ObjectHideFlags: 0 196 | m_CorrespondingSourceObject: {fileID: 0} 197 | m_PrefabInstance: {fileID: 0} 198 | m_PrefabAsset: {fileID: 0} 199 | m_GameObject: {fileID: 9159526560964145970} 200 | m_Enabled: 1 201 | m_EditorHideFlags: 0 202 | m_Script: {fileID: 11500000, guid: d0e42a93113c3ea44a5fb92705f11d8a, type: 3} 203 | m_Name: 204 | m_EditorClassIdentifier: 205 | --- !u!58 &2771371679451237986 206 | CircleCollider2D: 207 | m_ObjectHideFlags: 0 208 | m_CorrespondingSourceObject: {fileID: 0} 209 | m_PrefabInstance: {fileID: 0} 210 | m_PrefabAsset: {fileID: 0} 211 | m_GameObject: {fileID: 9159526560964145970} 212 | m_Enabled: 1 213 | m_Density: 1 214 | m_Material: {fileID: 0} 215 | m_IsTrigger: 1 216 | m_UsedByEffector: 0 217 | m_UsedByComposite: 0 218 | m_Offset: {x: 0, y: 0} 219 | serializedVersion: 2 220 | m_Radius: 0.1 221 | -------------------------------------------------------------------------------- /Example/Prefabs/Player.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1552443546450155103 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 1552443546450155097} 12 | - component: {fileID: 1552443546450155102} 13 | - component: {fileID: 1552443546450155096} 14 | - component: {fileID: 8612143065944902370} 15 | - component: {fileID: -5865924358743505632} 16 | m_Layer: 0 17 | m_Name: Player 18 | m_TagString: Untagged 19 | m_Icon: {fileID: 0} 20 | m_NavMeshLayer: 0 21 | m_StaticEditorFlags: 0 22 | m_IsActive: 1 23 | --- !u!4 &1552443546450155097 24 | Transform: 25 | m_ObjectHideFlags: 0 26 | m_CorrespondingSourceObject: {fileID: 0} 27 | m_PrefabInstance: {fileID: 0} 28 | m_PrefabAsset: {fileID: 0} 29 | m_GameObject: {fileID: 1552443546450155103} 30 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 31 | m_LocalPosition: {x: 0, y: 0, z: 0} 32 | m_LocalScale: {x: 2, y: 2, z: 2} 33 | m_Children: [] 34 | m_Father: {fileID: 0} 35 | m_RootOrder: 0 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | --- !u!212 &1552443546450155102 38 | SpriteRenderer: 39 | m_ObjectHideFlags: 0 40 | m_CorrespondingSourceObject: {fileID: 0} 41 | m_PrefabInstance: {fileID: 0} 42 | m_PrefabAsset: {fileID: 0} 43 | m_GameObject: {fileID: 1552443546450155103} 44 | m_Enabled: 1 45 | m_CastShadows: 0 46 | m_ReceiveShadows: 0 47 | m_DynamicOccludee: 1 48 | m_MotionVectors: 1 49 | m_LightProbeUsage: 1 50 | m_ReflectionProbeUsage: 1 51 | m_RayTracingMode: 0 52 | m_RenderingLayerMask: 1 53 | m_RendererPriority: 0 54 | m_Materials: 55 | - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} 56 | m_StaticBatchInfo: 57 | firstSubMesh: 0 58 | subMeshCount: 0 59 | m_StaticBatchRoot: {fileID: 0} 60 | m_ProbeAnchor: {fileID: 0} 61 | m_LightProbeVolumeOverride: {fileID: 0} 62 | m_ScaleInLightmap: 1 63 | m_ReceiveGI: 1 64 | m_PreserveUVs: 0 65 | m_IgnoreNormalsForChartDetection: 0 66 | m_ImportantGI: 0 67 | m_StitchLightmapSeams: 1 68 | m_SelectedEditorRenderState: 0 69 | m_MinimumChartSize: 4 70 | m_AutoUVMaxDistance: 0.5 71 | m_AutoUVMaxAngle: 89 72 | m_LightmapParameters: {fileID: 0} 73 | m_SortingLayerID: 0 74 | m_SortingLayer: 0 75 | m_SortingOrder: 0 76 | m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} 77 | m_Color: {r: 1, g: 1, b: 1, a: 1} 78 | m_FlipX: 0 79 | m_FlipY: 0 80 | m_DrawMode: 0 81 | m_Size: {x: 0.2, y: 0.2} 82 | m_AdaptiveModeThreshold: 0.5 83 | m_SpriteTileMode: 0 84 | m_WasSpriteAssigned: 1 85 | m_MaskInteraction: 0 86 | m_SpriteSortPoint: 0 87 | --- !u!96 &1552443546450155096 88 | TrailRenderer: 89 | serializedVersion: 2 90 | m_ObjectHideFlags: 0 91 | m_CorrespondingSourceObject: {fileID: 0} 92 | m_PrefabInstance: {fileID: 0} 93 | m_PrefabAsset: {fileID: 0} 94 | m_GameObject: {fileID: 1552443546450155103} 95 | m_Enabled: 1 96 | m_CastShadows: 1 97 | m_ReceiveShadows: 1 98 | m_DynamicOccludee: 1 99 | m_MotionVectors: 0 100 | m_LightProbeUsage: 0 101 | m_ReflectionProbeUsage: 0 102 | m_RayTracingMode: 0 103 | m_RenderingLayerMask: 1 104 | m_RendererPriority: 0 105 | m_Materials: 106 | - {fileID: 10306, guid: 0000000000000000f000000000000000, type: 0} 107 | m_StaticBatchInfo: 108 | firstSubMesh: 0 109 | subMeshCount: 0 110 | m_StaticBatchRoot: {fileID: 0} 111 | m_ProbeAnchor: {fileID: 0} 112 | m_LightProbeVolumeOverride: {fileID: 0} 113 | m_ScaleInLightmap: 1 114 | m_ReceiveGI: 1 115 | m_PreserveUVs: 0 116 | m_IgnoreNormalsForChartDetection: 0 117 | m_ImportantGI: 0 118 | m_StitchLightmapSeams: 1 119 | m_SelectedEditorRenderState: 3 120 | m_MinimumChartSize: 4 121 | m_AutoUVMaxDistance: 0.5 122 | m_AutoUVMaxAngle: 89 123 | m_LightmapParameters: {fileID: 0} 124 | m_SortingLayerID: 0 125 | m_SortingLayer: 0 126 | m_SortingOrder: 0 127 | m_Time: 5 128 | m_Parameters: 129 | serializedVersion: 3 130 | widthMultiplier: 0.1 131 | widthCurve: 132 | serializedVersion: 2 133 | m_Curve: 134 | - serializedVersion: 3 135 | time: 0 136 | value: 1 137 | inSlope: 0 138 | outSlope: 0 139 | tangentMode: 0 140 | weightedMode: 0 141 | inWeight: 0.33333334 142 | outWeight: 0.33333334 143 | - serializedVersion: 3 144 | time: 1 145 | value: 0 146 | inSlope: 0 147 | outSlope: 0 148 | tangentMode: 0 149 | weightedMode: 0 150 | inWeight: 0 151 | outWeight: 0 152 | m_PreInfinity: 2 153 | m_PostInfinity: 2 154 | m_RotationOrder: 4 155 | colorGradient: 156 | serializedVersion: 2 157 | key0: {r: 0.6273585, g: 1, b: 0.697127, a: 0} 158 | key1: {r: 0.6273585, g: 1, b: 0.697127, a: 0.9647059} 159 | key2: {r: 0, g: 0, b: 0, a: 0} 160 | key3: {r: 0, g: 0, b: 0, a: 0} 161 | key4: {r: 0, g: 0, b: 0, a: 0} 162 | key5: {r: 0, g: 0, b: 0, a: 0} 163 | key6: {r: 0, g: 0, b: 0, a: 0} 164 | key7: {r: 0, g: 0, b: 0, a: 0} 165 | ctime0: 0 166 | ctime1: 65535 167 | ctime2: 0 168 | ctime3: 0 169 | ctime4: 0 170 | ctime5: 0 171 | ctime6: 0 172 | ctime7: 0 173 | atime0: 0 174 | atime1: 2313 175 | atime2: 65535 176 | atime3: 0 177 | atime4: 0 178 | atime5: 0 179 | atime6: 0 180 | atime7: 0 181 | m_Mode: 0 182 | m_NumColorKeys: 2 183 | m_NumAlphaKeys: 3 184 | numCornerVertices: 0 185 | numCapVertices: 0 186 | alignment: 0 187 | textureMode: 0 188 | shadowBias: 0.5 189 | generateLightingData: 0 190 | m_MinVertexDistance: 0.1 191 | m_Autodestruct: 0 192 | m_Emitting: 1 193 | --- !u!58 &8612143065944902370 194 | CircleCollider2D: 195 | m_ObjectHideFlags: 0 196 | m_CorrespondingSourceObject: {fileID: 0} 197 | m_PrefabInstance: {fileID: 0} 198 | m_PrefabAsset: {fileID: 0} 199 | m_GameObject: {fileID: 1552443546450155103} 200 | m_Enabled: 1 201 | m_Density: 1 202 | m_Material: {fileID: 0} 203 | m_IsTrigger: 0 204 | m_UsedByEffector: 0 205 | m_UsedByComposite: 0 206 | m_Offset: {x: 0, y: 0} 207 | serializedVersion: 2 208 | m_Radius: 0.1 209 | --- !u!50 &-5865924358743505632 210 | Rigidbody2D: 211 | serializedVersion: 4 212 | m_ObjectHideFlags: 0 213 | m_CorrespondingSourceObject: {fileID: 0} 214 | m_PrefabInstance: {fileID: 0} 215 | m_PrefabAsset: {fileID: 0} 216 | m_GameObject: {fileID: 1552443546450155103} 217 | m_BodyType: 1 218 | m_Simulated: 1 219 | m_UseFullKinematicContacts: 0 220 | m_UseAutoMass: 0 221 | m_Mass: 1 222 | m_LinearDrag: 0 223 | m_AngularDrag: 0.05 224 | m_GravityScale: 1 225 | m_Material: {fileID: 0} 226 | m_Interpolate: 0 227 | m_SleepingMode: 1 228 | m_CollisionDetection: 0 229 | m_Constraints: 0 230 | -------------------------------------------------------------------------------- /Sources/Editor/EntityEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using CeresECL.Misc; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace CeresECL 8 | { 9 | [CustomEditor(typeof(Entity))] 10 | public class EntityEditor : Editor 11 | { 12 | GUIStyle panelStyle, headerPanelStyle; 13 | 14 | int selectedLogic; 15 | 16 | void OnEnable() 17 | { 18 | panelStyle = new GUIStyle(); 19 | panelStyle.padding = new RectOffset(5, 5, 5, 5); 20 | var panelColor = EditorGUIUtility.isProSkin ? new Color(0.25f, 0.25f, 0.25f) : new Color(0.9f, 0.9f, 0.9f); 21 | panelStyle.normal.background = EditorHelpers.GetColoredTexture(panelColor); 22 | 23 | headerPanelStyle = new GUIStyle(panelStyle); 24 | var headerPanelColor = EditorGUIUtility.isProSkin ? new Color(0.3f, 0.275f, 0.4f) :new Color(0.8f, 0.8f, 0.9f); 25 | headerPanelStyle.normal.background = EditorHelpers.GetColoredTexture(headerPanelColor); 26 | } 27 | 28 | public override void OnInspectorGUI() 29 | { 30 | if (!Application.isPlaying) 31 | { 32 | GUILayout.BeginVertical(panelStyle); 33 | GUILayout.Label("Adding Entity component in inspector currently isn't supported. Do it from code.", EditorStyles.boldLabel); 34 | GUILayout.EndVertical(); 35 | return; 36 | } 37 | 38 | var entity = target as Entity; 39 | 40 | DrawTags(entity); 41 | EditorGUILayout.Space(); 42 | DrawComponents(entity); 43 | EditorGUILayout.Space(); 44 | DrawLogics(entity); 45 | } 46 | 47 | void DrawHeader(string title) 48 | { 49 | GUILayout.BeginVertical(headerPanelStyle); 50 | GUILayout.Label(title, EditorStyles.boldLabel); 51 | GUILayout.EndVertical(); 52 | } 53 | 54 | void DrawTags(Entity entity) 55 | { 56 | DrawHeader("Tags"); 57 | 58 | GUILayout.BeginVertical(panelStyle); 59 | 60 | if (!Application.isPlaying) 61 | { 62 | GUILayout.Label("Tags is not editable in editor now.", EditorStyles.boldLabel); 63 | GUILayout.EndVertical(); 64 | return; 65 | } 66 | 67 | var tagsList = entity.Tags.GetTagsCopy(); 68 | 69 | foreach (var keyValuePair in tagsList) 70 | { 71 | var tagName = keyValuePair.Key.ToString(); 72 | 73 | if (CeresSettings.Instance.TagsEnum != null) 74 | tagName = Enum.Parse(CeresSettings.Instance.TagsEnum, tagName).ToString(); 75 | 76 | GUILayout.Label(tagName + ", Count: " + keyValuePair.Value, EditorStyles.boldLabel); 77 | } 78 | 79 | if (tagsList.Count == 0) 80 | GUILayout.Label("No tags on object", EditorStyles.boldLabel); 81 | 82 | GUILayout.EndVertical(); 83 | } 84 | 85 | void DrawComponents(Entity entity) 86 | { 87 | var componentsList = entity.Components.GetListEditor(); 88 | 89 | DrawHeader("Components"); 90 | 91 | for (var i = 0; i < componentsList.Count; i++) 92 | { 93 | GUILayout.BeginVertical(panelStyle); 94 | var component = componentsList[i]; 95 | var type = component.GetType(); 96 | 97 | GUILayout.Label(type.Name, EditorStyles.boldLabel); 98 | 99 | foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)) 100 | DrawField(field, component); 101 | 102 | GUILayout.EndVertical(); 103 | } 104 | 105 | if (componentsList.Count == 0) 106 | { 107 | GUILayout.BeginVertical(panelStyle); 108 | GUILayout.Label("No components on object", EditorStyles.boldLabel); 109 | GUILayout.EndVertical(); 110 | } 111 | } 112 | 113 | void DrawLogics(Entity entity) 114 | { 115 | var logicsList = entity.Logics.GetListEditor(); 116 | 117 | DrawHeader("Logics"); 118 | 119 | for (var i = 0; i < logicsList.Count; i++) 120 | { 121 | GUILayout.BeginVertical(panelStyle); 122 | GUILayout.Label(logicsList[i].GetType().Name, EditorStyles.boldLabel); 123 | GUILayout.EndVertical(); 124 | } 125 | 126 | if (logicsList.Count == 0) 127 | { 128 | GUILayout.BeginVertical(panelStyle); 129 | GUILayout.Label("No logics on object", EditorStyles.boldLabel); 130 | GUILayout.EndVertical(); 131 | } 132 | 133 | /* For future improvements of editor 134 | var listOfLogics = ( 135 | from domainAssembly in AppDomain.CurrentDomain.GetAssemblies() 136 | from assemblyType in domainAssembly.GetTypes() 137 | where assemblyType.IsSubclassOf(typeof(Logic)) 138 | && ! assemblyType.IsAbstract 139 | select assemblyType).ToArray(); 140 | 141 | GUILayout.BeginHorizontal(); 142 | 143 | var listOfStrings = Misc.EditorHelpers.TypesNamesToStrings(listOfLogics); 144 | selectedLogic = EditorGUILayout.Popup("Add Logic", selectedLogic, listOfStrings); 145 | if (GUILayout.Button("Add")) 146 | { 147 | entity.AddLogic(); // debug 148 | EditorUtility.SetDirty(target); 149 | } 150 | 151 | GUILayout.EndHorizontal(); 152 | */ 153 | } 154 | 155 | void DrawField(FieldInfo field, object obj) 156 | { 157 | var fieldValue = field.GetValue(obj); 158 | var fieldType = field.FieldType; 159 | 160 | if (fieldType == typeof (UnityEngine.Object) || fieldType.IsSubclassOf (typeof (UnityEngine.Object))) 161 | { 162 | GUILayout.BeginHorizontal (); 163 | GUILayout.Label (field.Name); 164 | var guiEnabled = GUI.enabled; 165 | GUI.enabled = false; 166 | EditorGUILayout.ObjectField (fieldValue as UnityEngine.Object, fieldType, false); 167 | GUI.enabled = guiEnabled; 168 | GUILayout.EndHorizontal (); 169 | return; 170 | } 171 | 172 | var strVal = fieldValue != null ? string.Format (System.Globalization.CultureInfo.InvariantCulture, "{0}", fieldValue) : "null"; 173 | 174 | GUILayout.BeginHorizontal(); 175 | GUILayout.Label(field.Name); 176 | GUILayout.Label(strVal); 177 | GUILayout.EndHorizontal(); 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /Example/Scenes/SampleScene.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 3 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 0 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 500 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 2 83 | m_PVRDenoiserTypeDirect: 0 84 | m_PVRDenoiserTypeIndirect: 0 85 | m_PVRDenoiserTypeAO: 0 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 0 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_UseShadowmask: 1 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | debug: 122 | m_Flags: 0 123 | m_NavMeshData: {fileID: 0} 124 | --- !u!1 &519420028 125 | GameObject: 126 | m_ObjectHideFlags: 0 127 | m_CorrespondingSourceObject: {fileID: 0} 128 | m_PrefabInstance: {fileID: 0} 129 | m_PrefabAsset: {fileID: 0} 130 | serializedVersion: 6 131 | m_Component: 132 | - component: {fileID: 519420032} 133 | - component: {fileID: 519420031} 134 | - component: {fileID: 519420029} 135 | m_Layer: 0 136 | m_Name: Main Camera 137 | m_TagString: MainCamera 138 | m_Icon: {fileID: 0} 139 | m_NavMeshLayer: 0 140 | m_StaticEditorFlags: 0 141 | m_IsActive: 1 142 | --- !u!81 &519420029 143 | AudioListener: 144 | m_ObjectHideFlags: 0 145 | m_CorrespondingSourceObject: {fileID: 0} 146 | m_PrefabInstance: {fileID: 0} 147 | m_PrefabAsset: {fileID: 0} 148 | m_GameObject: {fileID: 519420028} 149 | m_Enabled: 1 150 | --- !u!20 &519420031 151 | Camera: 152 | m_ObjectHideFlags: 0 153 | m_CorrespondingSourceObject: {fileID: 0} 154 | m_PrefabInstance: {fileID: 0} 155 | m_PrefabAsset: {fileID: 0} 156 | m_GameObject: {fileID: 519420028} 157 | m_Enabled: 1 158 | serializedVersion: 2 159 | m_ClearFlags: 2 160 | m_BackGroundColor: {r: 0.37397647, g: 0.41509432, b: 0.39938635, a: 0} 161 | m_projectionMatrixMode: 1 162 | m_GateFitMode: 2 163 | m_FOVAxisMode: 0 164 | m_SensorSize: {x: 36, y: 24} 165 | m_LensShift: {x: 0, y: 0} 166 | m_FocalLength: 50 167 | m_NormalizedViewPortRect: 168 | serializedVersion: 2 169 | x: 0 170 | y: 0 171 | width: 1 172 | height: 1 173 | near clip plane: 0.3 174 | far clip plane: 1000 175 | field of view: 60 176 | orthographic: 1 177 | orthographic size: 2 178 | m_Depth: -1 179 | m_CullingMask: 180 | serializedVersion: 2 181 | m_Bits: 4294967295 182 | m_RenderingPath: -1 183 | m_TargetTexture: {fileID: 0} 184 | m_TargetDisplay: 0 185 | m_TargetEye: 0 186 | m_HDR: 1 187 | m_AllowMSAA: 0 188 | m_AllowDynamicResolution: 0 189 | m_ForceIntoRT: 0 190 | m_OcclusionCulling: 0 191 | m_StereoConvergence: 10 192 | m_StereoSeparation: 0.022 193 | --- !u!4 &519420032 194 | Transform: 195 | m_ObjectHideFlags: 0 196 | m_CorrespondingSourceObject: {fileID: 0} 197 | m_PrefabInstance: {fileID: 0} 198 | m_PrefabAsset: {fileID: 0} 199 | m_GameObject: {fileID: 519420028} 200 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 201 | m_LocalPosition: {x: 0, y: 0, z: -10} 202 | m_LocalScale: {x: 1, y: 1, z: 1} 203 | m_Children: [] 204 | m_Father: {fileID: 0} 205 | m_RootOrder: 0 206 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 207 | --- !u!1 &744404224 208 | GameObject: 209 | m_ObjectHideFlags: 0 210 | m_CorrespondingSourceObject: {fileID: 0} 211 | m_PrefabInstance: {fileID: 0} 212 | m_PrefabAsset: {fileID: 0} 213 | serializedVersion: 6 214 | m_Component: 215 | - component: {fileID: 744404226} 216 | - component: {fileID: 744404225} 217 | m_Layer: 0 218 | m_Name: Launcher 219 | m_TagString: Untagged 220 | m_Icon: {fileID: 0} 221 | m_NavMeshLayer: 0 222 | m_StaticEditorFlags: 0 223 | m_IsActive: 1 224 | --- !u!114 &744404225 225 | MonoBehaviour: 226 | m_ObjectHideFlags: 0 227 | m_CorrespondingSourceObject: {fileID: 0} 228 | m_PrefabInstance: {fileID: 0} 229 | m_PrefabAsset: {fileID: 0} 230 | m_GameObject: {fileID: 744404224} 231 | m_Enabled: 1 232 | m_EditorHideFlags: 0 233 | m_Script: {fileID: 11500000, guid: ff0080920c580854bbf1a70a09a4467d, type: 3} 234 | m_Name: 235 | m_EditorClassIdentifier: 236 | gameData: {fileID: 11400000, guid: 3a88a39021675e341ad942e5f8949220, type: 2} 237 | --- !u!4 &744404226 238 | Transform: 239 | m_ObjectHideFlags: 0 240 | m_CorrespondingSourceObject: {fileID: 0} 241 | m_PrefabInstance: {fileID: 0} 242 | m_PrefabAsset: {fileID: 0} 243 | m_GameObject: {fileID: 744404224} 244 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 245 | m_LocalPosition: {x: 0, y: 0, z: 0} 246 | m_LocalScale: {x: 1, y: 1, z: 1} 247 | m_Children: [] 248 | m_Father: {fileID: 0} 249 | m_RootOrder: 1 250 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 251 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CeresECL 2 | Ceres ECL is **experimental** implementation of Entity Component Logic architectural pattern in Unity. 3 | 4 |

5 | Ceres ECL 6 |

7 | 8 | Ceres 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). 9 | 10 | ### What is Entity Component Logic? 11 | It is inspired by Entity Component System and Components over Inheritance approaches. 12 | Difference 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. 13 | But with ECL you obliged to separate logics from data. 14 | I really don't know is there exist any pattern like this, so I described it by my own. :) 15 | 16 | Problem 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. 17 | 18 | ### Why I should use it instead of Entity Component System? 19 | No reasons. ECS is cool. But if you're have problems with understanding ECS or it looks too complicated to you, 20 | Ceres ECL is simplier and looks more like usual Unity-way scripting, so you can use it. 21 | 22 | ## Overview 23 | There is ready classes Entity, Component, Logic, which you should use to create your own. More info and examples will be added soon. 24 | 25 | ### Entity 26 | **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. 27 | 28 | ```csharp 29 | // Spawning new Entity object using PlayerEntityBuilder and using instance of playerPrefab as Entity GameObject. 30 | var entity = Entity.Spawn(playerPrefab); 31 | 32 | // Spawn empty game object as entity (no prefab needed). 33 | var emptyEntity = Entity.Spawn(); 34 | ``` 35 | 36 | ### Component 37 | Component is simple class, which only contains some data of your **Entity**. For example, **MoveComponent**, which contains **Speed** and **Direction** of movement. 38 | Should be no any logics code in this class. 39 | 40 | ```csharp 41 | using CeresECL; 42 | 43 | public class MoveComponent : Component 44 | { 45 | public float Speed; 46 | public Vector3 Direction; 47 | } 48 | ``` 49 | 50 | ### Logic 51 | **Logic** describes specific behaviour of the **Entity**. Logics should know nothing about anothers, it should work only with **Components**, **Events** and **Tags**. 52 | 53 | For example, **MoveLogic** will move it using **MoveComponent** data. 54 | And **InputLogic** will fill **MoveComponent Direction** field with player input. 55 | 56 | 57 | ```csharp 58 | using CeresECL; 59 | 60 | public class MoveLogic : Logic, IInitLogic, IRunLogic 61 | { 62 | MoveComponent moveComponent; 63 | 64 | void IInitLogic.Init() 65 | { 66 | moveComponent = Entity.Components.Get(); 67 | 68 | moveComponent.Speed = 2f; 69 | } 70 | 71 | void IRunLogic.Run() 72 | { 73 | Entity.transform.position += moveComponent.Direction * (moveComponent.Speed * Time.deltaTime); 74 | } 75 | } 76 | ``` 77 | 78 | There is **IInitLogic** interface to implement initialization logic, similar to the **Start** Unity method. 79 | 80 | There also **IRunLogic** interface to implement run logic, similar to the **Update** Unity method. 81 | 82 | ### Builder 83 | You 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. 84 | ```csharp 85 | using CeresECL; 86 | 87 | public class PlayerEntityBuilder : Builder 88 | { 89 | protected override void Build() 90 | { 91 | Entity.Logics.Add(); 92 | Entity.Logics.Add(); 93 | } 94 | } 95 | ``` 96 | 97 | Builders 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. 98 | 99 | ### Tags 100 | If 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. 101 | 102 | **Tags** can be any **Enum**. You can use **TagsList.cs** from Example or create your own **enum Tag**. 103 | To create new **Tag**, edit **enum Tag**: 104 | ```csharp 105 | public enum Tag 106 | { 107 | CustomTag = 0, 108 | // add your tags here 109 | } 110 | ``` 111 | 112 | Adding tag to the entity: 113 | ```csharp 114 | Entity.Tags.Add(Tag.CustomTag); 115 | ``` 116 | 117 | Note 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. 118 | 119 | Check of tag on the entity: 120 | ```csharp 121 | Entity.Tags.Have(Tag.CustomTag); 122 | ``` 123 | 124 | Removing tag (only one, if there stacked tags) from the entity: 125 | ```csharp 126 | Entity.Tags.Remove(Tag.CustomTag); 127 | ``` 128 | 129 | New 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: 130 | ```csharp 131 | CeresSettings.Instance.TagsEnum = typeof(Tag); 132 | ``` 133 | You can see it in **Example**. 134 | 135 | Tags inspired by Pixeye Actors ECS tags. But possble that in my realisation this feature is not so cool. :D 136 | 137 | ### Events 138 | **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**: 139 | 140 | ```csharp 141 | using CeresECL; 142 | 143 | class ColliderHitEvent : Event 144 | { 145 | public Collider2D HitCollider; 146 | } 147 | ``` 148 | 149 | To send **Event**, do it like this: 150 | ```csharp 151 | var hitEvent = new ColliderHitEvent 152 | { 153 | HitCollider = other 154 | }; 155 | 156 | Entity.Events.Add(hitEvent); 157 | ``` 158 | 159 | You 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. 160 | Note that **Logics** adding order can be important since **Event** live only one frame. 161 | 162 | You can subscribe to event type in **Logic** like this: 163 | ```csharp 164 | using CeresECL; 165 | 166 | public class Bullet : Logic, IInitLogic 167 | { 168 | void IInitLogic.Init() 169 | { 170 | Entity.Events.Subscribe(OnHit); 171 | } 172 | 173 | void OnHit(ColliderHitEvent eventData) 174 | { 175 | // handle event data 176 | } 177 | } 178 | ``` 179 | 180 | Unsubscribe is the same: 181 | ```csharp 182 | Entity.Events.Unsubscribe(OnHit); 183 | ``` 184 | 185 | Current Events version is not finished and can be unstable, but all tests passed fine, so I added it to the repo. 186 | 187 | ### Launcher 188 | To 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. 189 | 190 | ```csharp 191 | using Ceres.ECL; 192 | 193 | public class MyLauncher : Launcher 194 | { 195 | protected override void StartAction() 196 | { 197 | Entity.Spawn(); 198 | } 199 | } 200 | ``` 201 | 202 | Base **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. 203 | 204 | ### Templates 205 | You can create each of these classes using templates. Click **RMB** in **Project Window** and open submenu **Ceres ECL**. There will be all actual templates. 206 | 207 | It will generate script in root namespace, which you can change in **Editor Settings -> Editor -> C# Project Generation**. Otherwise it will be generated in **CeresECL** namespace. 208 | 209 | For template generator idea thanks to LeoECS, some used things came from its code. 210 | 211 | ### Dependency Injection 212 | Ceres ECL has DI implementation for Logics. So you can inject any data to all of yours Entity Logics: 213 | 214 | ```csharp 215 | Entity.Logics.Inject(data); 216 | ``` 217 | 218 | Your Logic should have field with same to **data** type, for example, if **data** type is **Data**, your Logic should look like this: 219 | 220 | ```csharp 221 | using CeresECL; 222 | 223 | public class TestLogic : Logic, IRunLogic 224 | { 225 | Data injectedData; 226 | 227 | void IRunLogic.Run() 228 | { 229 | // Do smth ? 230 | } 231 | } 232 | ``` 233 | 234 | Dependency Injection idea came from LeoECS, you can find a link to its repo at the end of readme. 235 | 236 | ## Debug 237 | To 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: 238 |

239 | Ceres ECL 240 |

241 | 242 | ## More FAQ 243 | ### Can I edit variables or entities from Inspector 244 | **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. 245 | 246 | ### How I can use OnTriggerEnter, for example 247 | You 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 248 | 249 | ### Is Ceres ECL production-ready 250 | No, 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. 251 | 252 | ## Examples 253 | Check Example folder from repository, it contains simple Ceres ECL usage example. 254 | 255 | Links to games examples on GitHub will be added when these examples will be created. :) 256 | 257 | ## Thanks to 258 | Leopotam for LeoECS https://github.com/Leopotam/ecs 259 | 260 | Pixeye for Actors https://github.com/PixeyeHQ/actors.unity 261 | 262 | Inspired me to use ECS and think moer about different coding architecture patterns. :) 263 | --------------------------------------------------------------------------------