A better approach to game design that allows you to concentrate on the actual problems you are solving: the data and behavior that make up your game. By moving from object-oriented to data-oriented design it will be easier for you to reuse the code and easier for others to understand and work on it.
Installation · Documentation · License
Made with ♥ by Jeffrey Lanters
Install the latest stable release using the Unity Package Manager by adding the following line to your manifest.json
file located within your project's Packages directory, or by adding the Git URL to the Package Manager Window inside of Unity.
"nl.elraccoone.entity-component-system": "git+https://github.com/jeffreylanters/unity-entity-component-system"
The module is availble on the OpenUPM package registry, you can install the latest stable release using the OpenUPM Package manager's Command Line Tool using the following command.
openupm add nl.elraccoone.entity-component-system
It's recommended to get started by using the built-in File Generator. When it's your first time using the ECS, you might want to enable the Overwrite All Virtuals option to see all the available methods for each type of class.
It's recommended to build your entire project around these life cycle methods.
The Controller
is the heart of your Application, each Application should consist of just one, commonly named the MainController. The Controller
is the first entry point of the Entity Component System and is the place where all of your System
and Services
are registered. Your Controller
should be attached to a GameObject
in your scene and will automatically be marked to not be destroyed when switching scenes.
public class MainController: Controller { }
The Controller
consists of a virtual OnInitialize
method. This lifecycle method can be overwritten and will be invoked at the very start of your Application. During this cycle, properties with the Injected
and Asset
attributes are being assigned, and the OnInitialize
method of each registered System
and Service
will be invoked as well.
public class MainController: Controller {
public override void OnInitialize() { }
}
The Controller
consists of a virtual OnInitialized
method. This lifecycle method can be overwritten and will be invoked after the OnInitialize
method has been invoked. During this cycle, the OnInitialized
method of each registered System
and Service
will be invoked as well.
public class MainController: Controller {
public override void OnInitialized() { }
}
The Controller
consists of a virtual OnUpdate
method. This lifecycle method can be overwritten and will be invoked every frame. During this cycle, the OnUpdate
method of each registered System
will be invoked as well.
public class MainController: Controller {
public override void OnUpdate() { }
}
The Controller
consists of a virtual OnWillDestroy
method. This lifecycle method can be overwritten and will be invoked when the Application is about to quit. During this cycle, the OnWillDestroy
method of each registered System
and Service
will be invoked as well.
public class MainController: Controller {
public override void OnWillDestroy() { }
}
Use this method to Register
the Systems and Services that are required for your Application to function. The Register
method accepts a list of Type
arguments, each of these types should be a System
or Service
type.
Registering a System
or Service
can only be done once during the Controller
's OnInitialize
life cycle method.
public class MainController: Controller {
public override void OnInitialize() {
Register(
typeof(ExampleSystem),
typeof(ExampleService)
);
}
}
To enable or disable the life cycle of a System
or Service
, use the SetSystemEnabled
methods. This method accepts a Type
generic, and a bool
value to enable or disable the life cycle of the System
or Service
.
public class MainController: Controller {
void SomeMethod() {
SetSystemEnabled<ExampleSystem>(false);
}
}
To check whether the life cycle of a System
or Service
is enabled, use the IsSystemEnabled
methods. This method accepts a Type
generic, and returns a bool
value indicating whether the life cycle of the System
or Service
is enabled.
public class MainController: Controller {
void SomeMethod() {
if (IsSystemEnabled<ExampleSystem>()) { }
}
}
Something you might want to get a reference to a System
or Service
from within something outside of the Entity Component System. To do this, use the GetSystem
, GetService
, HasSystem
and HasService
methods respectively. These methods accept a Type
generic, or a Type
parameter and return the System
or Service
instance.
public class MainController: Controller {
void SomeMethod() {
if (HasSystem<ExampleSystem>()) {
var exampleSystem = GetSystem<ExampleSystem>();
var exampleSystem = GetSystem(typeof(ExampleSystem));
}
if (HasService<ExampleService>()) {
var exampleService = GetService<ExampleService>();
var exampleService = GetService(typeof(ExampleService));
}
}
}
Something you might want to get a reference to an Asset
from within something outside of the Entity Component System. To do this, use the GetAsset
and HasAsset
methods respectively. These methods accepts an optional Type
generic and a name
parameter and returns the Type
or Object
public class MainController: Controller {
void SomeMethod() {
if (HasAsset<ExampleAsset>()) {
var exampleAsset = GetAsset<ExampleAsset>("MyAssetName");
var exampleAssetObject = GetAsset("MyAssetName");
}
}
}
The Controller
allows the use of the Asset
attribute on properties to automatically assign the values of referenced Assets. Assets can be assigned on the Controller
instance in your Scene. When assigning using the empty contructor, the property's name will be used for searching the Asset, to find an Asset by its name, use the string overload. All types of UnityEngine's Object can be used in these fields. These properties are assigned during the OnInitialize cycle and are available for use at the OnInitialized cycle. When an asset is not found, an error is thrown.
public class MainController: Controller {
[Asset] public ExampleAsset exampleAsset;
[Asset("MyAssetName")] public ExampleAsset exampleAsset;
}
The Controller
allows the use of the Injected
attribute on properties to automatically assign the values of referenced Systems and Services, making all public methods and properties accessible. These properties are assigned during the OnInitialize cycle and are available for use at the OnInitialized cycle.
public class MainController: Controller {
[Injected] public ExampleSystem exampleSystem;
[Injected] public ExampleService exampleService;
}
Components
are responsible for storing the data of your entities
while Systems
are responsible for manipulating that data. Components
are added to your entities
(GameObjects
) in the Scene
, an Entity
is not limited to one Component
and can hold as many as needed.
public class MovementComponent : EntityComponent<MovementComponent, MovementSystem> { }
To provide Systems
entity data, we'll use properties to store this. All properties should be public and will be accessible to all Systems
and Controllers
since there is no need for privates.
public class MovementComponent : EntityComponent<MovementComponent, MovementSystem> {
public float speed;
public Vector3 targetPosition;
public int[] ids;
public NpcDialog dialog;
[HideInInspector] public bool isMoving;
}