A first example of Unity ECS in action
Table of Contents
In this article I will provide a first example on how to get up and running with ECS. If any of the terms make little sense to you jump back to my terms article. For this example you will do nothing super fancy, just a rotating cube. If you don’t want to do all the setup yourself, you can checkout a finished project from GitHub.
Thinking about the data
Thinking about how you can organize your data is crucial for
effectively using Unity ECS. The ECS approach works a lot different from
the “old” way using GameObject
s and MonoBehaviour
s. So first you need
to wrap your thinking around the fact, that behaviour and data are two separate
things in ECS. It is quite a departure from the trusty old object
oriented approach where you combine data and behaviour into a single object.
In ECS all data is in your components and all behaviour is in systems. With that in mind, let’s think about what data you need for your rotating cube.
- You need to know where it is in 3D space and how big it is and how its rotation should be.
- You need to know what mesh and material it should use.
- You need to know how fast it should rotate.
The good news is, that for the first and second points there are already built-in components from Unity that you can use:
- The
Translation
,Scale
andRotation
components are there for tracking any entity’s position, size and orientation in 3D space, so you can just use them. - There is a
RenderMesh
component you can use to set the mesh and material. Together with theTranslation
,Scale
andRotation
components you get rendering for free as there is already a built-in system which takes care of rendering all entities that have these components.
Now the only thing that is missing data-wise is the information on how fast the cube should rotate. For this you create a new component:
public struct RotationSpeed : IComponentData {
public float DegreesPerSecond;
}
Now you have all the data for building up your entity for a rotating cube.
Building a rotation system
You would like to rotate the cube at a certain speed. This is logic and in ECS systems perform the logic. To keep things simple, start with a ComponentSystem
that runs on the main thread:
public class RotationSystem : ComponentSystem
{
protected override void OnUpdate()
{
}
}
A ComponentSystem
has an OnUpdate
method that is called once per frame, which looks similar to the old MonoBehaviour
way of things. However, unlike a MonoBehaviour
the system is not bound to any special entity, it can process any entity. So how can you get access to your entities in a component system? If you have read the terms article you may already know the answer - using an EntityQuery
. You need an entity query that returns all entities having both a Rotation
and a RotationSpeed
component. The ComponentSystem
class provides a OnCreateManager
method that can be used to initialize your system.
private EntityQuery _cubes;
protected override void OnCreateManager()
{
_cubes = Entities
.WithAll<RotationSpeed, Rotation>()
.ToEntityQuery();
}
Here you create the EntityQuery
and store it into a field so you can use it in the OnUpdate
method:
protected override void OnUpdate()
{
Entities.With(_cubes)
.ForEach((ref RotationSpeed rotationSpeed, ref Rotation rotation) =>
{
rotation.Value = math.mul(rotation.Value,
quaternion.RotateY(
math.radians(
rotationSpeed.DegreesPerSecond * Time.deltaTime
)
)
);
});
}
Now that’s a lot of stuff going on for a simple rotation, so let’s go through it step by step. First there is the Entities.With(_cubes_).ForEach
part. This is a convenience built into ComponentSystem
which allows you to quickly iterate over all interesting components that are part of a EntityQuery
. As parameter you give it a lambda function that is executed for each entity of the EntityQuery
- in this case once for each cube in the _cubes
component group. The signature of this lambda function tells ForEach
in which components you are interested. You are interested in the Rotation
and RotationSpeed
components. Note that the parameters are having a ref
modifier. This is special magic built into this helper method. It allows you to change the component while iterating over it. For this example this is exactly what you need.
You may now scratch your head and wonder why there is so much code for a simple rotation around the Y axis - something, that is in old MonoBehaviour
terms as simple as:
transform.Rotate(Vector3.up, speed * Time.deltaTime);
The reason for this is, that with ECS Unity has introduced new primitives for representing vectors and quaternions. These are in the Unity.Mathematics
library and are very optimized versions of the good old Vector3
and Quaternion
classes. Unfortunately they currently lack many convenience features like overloaded operators. So first you have to manually create a quaternion
(notice the lower-case class name) representing a rotation around the Y-axis by as many degrees as you need to achieve the desired rotation speed given the elapsed time. The good news is that you can use Time.deltaTime
here as this code will run on the main thread. quaternion.RotateY
requires a value in radians so you need to call math.radians
(notice the lower case class and method names) to convert the degrees to radians.
Finally, you call math.mul
to multiply the quaternion representing the entity’s current rotation with the new one you created to get the final rotation. Then you assign the result back to the Rotation
component, so the rotation is actually updated.
Making it run
Now with the system and data in place, how do you get this to work in a scene? After all there are no MonoBehaviours
involved, so how is your system going to run? The answer to this is straightforward: Unity will run your system automatically. When you start a scene Unity will scan for all ComponentSystem
s and will automatically instantiate and run them. You can finely control how this works (and even instantiate and run systems yourself if you want to), but for now let’s run with the automatic instantiation. The next question is: How can you create a cube entity that your system will work with? There is more than one way of doing this but for the sake of keeping it simple you’ll use the most straightforward way - Unity’s entity auto-conversion. Using auto conversion you just build a simple game object with MonoBehaviour
s in your scene and let Unity convert it to entities and components automatically.
So for creating a cube, you can just use Game Object -> 3D Object -> Cube to create a simple cube. Then in the inspector, add a Convert To Entity component to the cube. This will automatically convert the game object to an entity at run time and remove the game object from the scene.

This takes care of converting the Transform
MonoBehaviour
component into Translate
, Rotation
and Scale
ECS components and also creating a shared RenderMesh
ECS component for the MeshFilter
and MeshRenderer
components (yes it’s unfortunate that both the old MonoBehaviour
based components and the ECS components are named components).
When you now start the scene, you should see a cube but it’s not rotating. Why is that? Because you didn’t specify the rotation speed yet. Your RotationSpeed
component is an ECS component and you cannot add it directly to a GameObject
. You can only add MonoBehaviours
to GameObjects
. So how can you add it to the cube you have in your scene?
For this, you need a little “bridge” MonoBehaviour
that wraps our RotationSpeed
component and exposes it as a MonoBehaviour
that you can add to your cube GameObject
in the scene. Unity calls such objects ComponentDataProxy
. So create a new class in your project like this:
public class RotationSpeedProxy : ComponentDataProxy<RotationSpeed>
{
}
All ComponentDataProxy
objects are derived from MonoBehaviour
so you can now add RotationSpeedProxy
to your cube entity and enter a rotation speed:

When you now start the scene, you can see the cube rotating. Congratulations, you made your first step into Unity ECS territory. Again, you can check out this project from GitHub and try it for yourself.