-
Notifications
You must be signed in to change notification settings - Fork 6
ECS
-
As a
Entityyou need to add aEntityBehaviourComponent on GameObject
-
You can use right click in Project Window Select Create -> Custom Script -> ComponentBehaviour Installer Create a
Componentscript -
You can use right click in Project Window Select Create -> Custom Script -> SystemBehaviour Installer Create a
Systemscript -
For Example :
[Entity]
Scene : Level(GameObject) : [Transform|SceneContext|SceneInstaller(MonoInstaller)] Entity(GameObject) : [Transform|EntityBehaviour|HealthComponent(ComponentBehaviour)] System(GameObject) : [Transform|HealthSystem(SystemBehaviour)][Component]
using UniEasy.ECS; public class HealthComponent : ComponentBehaviour { public float CurrentHealth; public float StartingHealth; }[System]
using UniEasy.ECS; using System; using UniRx; public class HealthSystem : SystemBehaviour { public IGroup Healths; public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory) { base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory); Healths = this.Create (typeof(HealthComponent)); } public override void OnEnable () { base.OnEnable (); Healths.OnAdd().Subscribe (entity => { var healthComponent = entity.GetComponent<healthcomponent> (); healthComponent.CurrentHealth = healthComponent.StartingHealth; }).AddTo (this.Disposer); } }

-
Add
ECSInstallerComponent toProjectContextprefab(Resources/ProjectContext.prefab) -
Drag
ECSInstallerComponent toProjectContextInstallers ReorderableList
ProjectContext will call ECSInstaller InstallBindings() function when before scenes loaded
ECSInstaller will create and binding all ECS framework needed core classes
-
Add
ProjectInstallerComponent toProjectContextprefab(Resources/ProjectContext.prefab) -
Drag
ProjectInstallerComponent toProjectContextInstallers ReorderableList
ProjectContext will call ProjectInstaller InstallBindings() function when before scenes loaded
ProjectInstaller will instantiate, binding and inject all gameObjects from Resources/Kernel folder

-
Create a gameObject named
Levelin the root directory of the scene -
Set other gameObjects transform parent were Level gameObject
-
Add
SceneContextComponent to Level gameObject -
Add
SceneInstallerComponent to Level gameObject -
Drag
SceneInstallerComponent toSceneContextInstallers ReorderableList
SceneContext will called SceneInstaller's InstallBindings() function when Awake, so SceneInstaller will inject all SystemBehaviour
For Performance we don't want to SceneInstaller GetComponents<SystemBehaviour> When Awake(), So we need to pre GetComponents<SystemBehaviour> and save them in array or list, we did it, too
You can see a Auto Update toggle and Force Update button on SceneInstaller Inspector panel
If set Auto Update toggle is true SceneInstaller will auto GetComponents<SystemBehaviour> and save them in Systems List when you save scene
Click Force Update button SceneInstaller will GetComponents<SystemBehaviour> and save them in Systems List immediately
If you also want this system can be binding and as a single system, you can add it to Binding Systems List by your hand
Use GroupFactory.Create (Type[] types) you can get the group(entities) that contain all of these types
You also can use this.Create (Type[] types) get the group when you are in the SystemBehaviour class
Now we add WithPreficate to the group, so we can do more cool things like this :
public class ActiveComponent
{
public BoolReactiveProperty IsActive;
}
public class ActiveSystem : SystemBehaviour
{
public IGroup Actives;
public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
{
base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);
Actives = GroupFactory.AddTypes (new Type[] {
typeof(EntityBehaviour),
typeof(ActiveComponent),
}).WithPredicate ((entity) =>
{
var activeComponent = e.GetComponent<ActiveComponent> ();
activeComponent.gameObject.ObserveEveryValueChanged (go => go.activeSelf).Subscribe (b => {
activeComponent.IsActive.Value = b;
}).AddTo (activeComponent.Disposer);
return activeComponent.IsActive;
}).Create ();
}
public override void OnEnable ()
{
base.OnEnable ();
Actives.OnAdd ().Subscribe (entity => {
Debug.Log ("every time the gameObject is set for active will be called");
}).AddTo (this.Disposer);
Actives.OnRemove ().Subscribe (entity => {
Debug.Log ("every time the gameObject is set for disactive will be called");
}).AddTo (this.Disposer);
}
}
For Performance for a high frequency used group you can choose to create a class that inherit from Group for him, then bind and inject it into every system that needs to be used, for example :
public class DeadEntities : Group
{
public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager)
{
Components = new Type[] { typeof(HealthComponent) };
Func<IEntity, ReactiveProperty<bool>> checkIsDead = (e) =>
{
var health = e.GetComponent<HealthComponent> ();
health.CurrentHealth.Value = health.StartingHealth;
var isDead = health.CurrentHealth.DistinctUntilChanged ().Select (value => value <= 0).ToReactiveProperty();
return isDead;
};
Predicates.Add(checkIsDead);
base.Initialize (eventSystem, poolManager);
}
}
public class GroupsInstaller : MonoInstaller
{
public override void InstallBindings()
{
Container.Bind<DeadEntities>().To<DeadEntities>().AsSingle();
}
}
Then add the GroupsInstaller component to the SceneContext List
If you want to dynamic create an entity GameObject, you need to use PrefabFactory.Instantiate() method
public class ExampleSystem : SystemBehaviour {
public GameObject Prefab;
public Transform Parent;
public bool WorldPositionStays = true;
public override void Initialize (IEventSystem eventSystem, IPoolManager poolManager, GroupFactory groupFactory, PrefabFactory prefabFactory)
{
base.Initialize (eventSystem, poolManager, groupFactory, prefabFactory);
if (Prefab != null)
{
var go = PrefabFactory.Instantiate (Prefab, Parent, WorldPositionStays);
var entity = (go.GetComponent<EntityBehaviour>() ?? go.AddComponent<EntityBehaviour>()).Entity;
}
}
}
For Performance we don't want to EntityBehaviour GetComponents<Component> When Awake(), So we need to pre GetComponents<Component> and save them in array or list, we did it, too
You can see a Auto Update toggle and Force Update button on EntityBehaviour Inspector panel
If set Auto Update toggle is true EntityBehaviour will auto GetComponents<Component> and save them in Components List when gameObject's components count changed
Click Force Update button EntityBehaviour will GetComponents<Component> and save them in Components List immediately
Runtime component does not contain references to Objects or Transforms, so it can makes components more single and more clear
You can found it on EntityBehaviour and it is a ReorderableList named Runtime Components [0]
You can use ReorderableList's + Button to select and add a runtime component to EntityBheaviour
// Use UniEasy.ContextMenuAttribute can easy to pack runtime components into groups
// You can see them at drop down context menu when you click `Runtime Components [0]` ReorderableList's `+` Button
[UniEasy.ContextMenu ("Test/HealthComponent")]
public class HealthComponent : RuntimeComponent
{
public float CurrentHealth;
public float StartingHealth;
}
The object you want to add scriptable components must be prefab or asset!
Because ScriptableComponent inherit from ScriptableObject and we used AssetDatabase.AddObjectToAsset() function to save the ScriptableObject
Note that your data will be modified and saved, whether you are playing or editing mode. Of course, we will disable edit of data at run time. But you still can modify it use scripts at run time
// Use UniEasy.ContextMenuAttribute can easy to pack scriptable components into groups
// You can see them at drop down context menu when you click `Scriptable Components [0]` ReorderableList's `+` Button
[UniEasy.ContextMenu ("Test/HealthComponent")]
public class HealthComponent : ScriptableComponent
{
public float CurrentHealth;
public float StartingHealth;
}
If you want to create a group system, you must inherit from the Feature instead of using it directly !
You can use Runtime Systems [0] ReorderableList's + Button to select and add a runtime system to the group system inherited from the Feature
Divide the systems with similar functions into a group, this can better help you manage complex systems, like I made the Console Systems !

public class ConsoleSystems : Feature {}
[UniEasy.ContextMenu ("Console/DebugSystem")]
public class DebugSystem : RuntimeSystem
{
...
}
[UniEasy.ContextMenu ("Console/ConsoleSystem")]
public class ConsoleSystem : RuntimeSystem
{
...
}
Create a gameObject and add ConsoleSystems component and click ConsoleSystems's Runtime Systems [0] ReorderableList's + Button in Inspector panel
Then select and add DebugSystem and ConsoleSystem in drop down context menu, Save the scene or make the gameObject a prefab and drag the prefab to the Resources/Kernel/... folder (The Console Systems in this folder will be automatically injected and bindings as a single)
Base on WriterExtensions
#if Serialize entity all can be serialize components
string data = entity.Serialize ();
#elif Only Serialize include in the includeTypes components
Type[] includeTypes = Type[] { typeof(SerializeComponent) }
string data = entity.Serialize (includeTypes);
#elif Serialize but ignore include in the ignoreTypes components
Type[] ignoreTypes = Type[] { typeof(NonSerializeComponent) }
string data = entity.Serialize (null, ignoreTypes);
#endif
entity.Deserialize (data);