Convenience API for Unity ECS

Maxim Zaks
3 min readJul 22, 2019

--

This is the third article based on my exploration of Unity ECS and Project Tiny. In the first and second articles I discussed different aspects of component design. This article will be all about API sugar.

But before we begin, words of caution:

Syntactic sugar and convenience API can make your code run slower, so use with caution!!!

First I would like to start with some convenience API which is already backed in, but is not used in the sample code. For example have a look at the following snippet:

var selectionCursorEntity = Entity.Null;
Entities.WithAll<SelectionCursor>().ForEach((Entity entity) => {
selectionCursorEntity = entity;
});
if (!EntityManager.Exists(selectionCursorEntity))
return;

We are trying to get one entity with SelectionCursor component. However we are doing it by iterating over all entities, which have SelectionCursor and keeping the last one. IMHO this is not optimal on many levels and there is already an API in Unity ECS, which can provide us with the entity in more readable, safe and efficient way.

var selectionCursorEntity = GetSingletonEntity<SelectionCursor>();

GetSingletonEntity is a method we can find on EntityQuery and on ComponentSystem. It will return us the first entity, which has desired component type. If we set ENABLE_UNITY_COLLECTIONS_CHECKS macro, it will also throw an exception, if there are more than one entities, which have given component type. This is a very nice safety check, because some components (SelectionCursor in this case) should be considered unique (or singletons if you will). If we have multiple instances of such component in one world, this is a bug on our side and should raise an exception. I implemented a few simple ECS libraries myself and I tend to mark unique components as such by a special interface and also raise an exception directly, when a second instance is added. In Unity ECS we don’t have this strict distinction, however using the GetSingletonEntity gives us the next best thing.

An Entity in Unity ECS is a simple struct holding two int values and all the entity component interactions are done through EntityManager instance. This is a great design from performance perspective, however IMHO it is slightly less ergonomic from developer experience. Consider following expression:

if (!EntityManager.Exists(selectionCursorEntity))
return;

Wouldn't it read and write better as following:

if (selectionCursorEntity.IsNull())
return;

Lucky for us, C# has a language feature called extension methods. It enables us to provide methods to classes, which we do not own.

public static class EntityExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNull(this Entity entity)
{
return entity == Entity.Null;
}
}

Here we go, now we can write entity.IsNull(). And thanks to [MethodImpl(MethodImplOptions.AggressiveInlining)] attribute, this sugar should not cost us much from performance perspective.

What else can we do with Extension methods 🤔?

How about providing Entity struct with all the methods which we otherwise call over EntityManager.

https://gist.github.com/mzaks/cc46cc7cbd88a92526a476ce279b861d

We need the world to call those methods, but in many cases you will have only one world anyways, so not providing it, set the world to World.Active. And now we can wirte things like entity.GetComponentData<Transform>(), entity.Destroy(), etc…

However keep in mind, we introduced an if statement which can have a small impact on performance.

Last sugary goodnesses I would like to present has something to do with following snippet:

if (EntityManager.HasComponent<LayerSorting>(spriteEntity))
{
var sortingLayer = EntityManager.GetComponentData<LayerSorting>(
spriteEntity
);
sortingLayer.order = (short)(
isScaledUp ? dragAnimation.DraggedSortOrder :
dragAnimation.DefaultSortOrder
);
EntityManager.SetComponentData(spriteEntity, sortingLayer);
}

We have an entity with LayerSorting component and we would like to replace just one value in the component. In order to do this, we need to check if this component exists on the entity, then get the component, assign the one value and set the component on the entity.

What if we could write it all like this:

spriteEntity.ReplaceSortingLayer(
order: (short)(
isScaledUp ? dragAnimation.DraggedSortOrder :
dragAnimation.DefaultSortOrder
)
);

It is posible thanks to the power of extension methods:

https://gist.github.com/mzaks/d4e02445d11e273ede81e532546da70f

This sugary goodness is more complex to write and introduces computational overhead, but it is up to you to decide, what is good for you and your code. 😉

That’s it for today, thank you for reading!!! And don’t forget to clap 😀.

PS: In the next article, I will discuss the options for reactive systems in Unity ECS.

--

--

Maxim Zaks
Maxim Zaks

Written by Maxim Zaks

Tells computers how to waste electricity. Hopefully in efficient, or at least useful way.

Responses (2)