• entries
11
17
• views
27292

2022 views

[font=arial]

[/font]

[font=arial]

# Entity Objects

Artemis used Entity class as a sort of abstraction, it gave the impression than entities were objects rather than plain IDs. Entity objects were kinda heavy weight to be fair, they had a reference to a ComponentManager, to a World instance, an UUID instance, a bit set instance for keeping track of components and a long ID.

First two were for providing convenience methods say, entity.addComponent(cmp) instead of world.getComponentManager().addComponent(entity,cmp) for example, then the UUID was probably there for serialization purposes.

This makes creating Entity instances kinda cumbersome, whatever thats in charge of creating it needs a World instance, a ComponentManager instance and the Entity will create an UUID instance and a bit set instance by itself.

First step I took is narrowing its scope: Getting rid of the UUID (you can always add it as a Component if you want) and using a plain 'int' ID. So now we're left with the World and ComponentManager instances.

This situation makes Entity instances ideal for pooling. At least in my mind, dustArtemis should provide fast and hopefully garbage free ways to make new entities, associate entities with components and process them.

# Complementing Features

I implemented Entity instance pooling into the framework. I also added a nifty thing, a sort of ID allocator that would guarantee that every time you needed a new Entity it would have the lowest free available ID.

This is great since ever incrementing IDs are awful for the backing component arrays (they'd always get bigger and bigger for holding ever increasing entity IDs).

# Integer Entities

Now the next step in my trail of thought was: If the only things in Entity instance are World and ComponentManager instance, and they're only there for providing convenience methods, Entity now was just behaving just like a Java Integer instance, ie, a crappy boxed int.

What if I just remove such conveniences and just use plain 'int' IDs for representing entities?[/font]// This turns this code:Entity e = world.createEntity();e.addComponent( new Position() );// Into this:int eid = world.createEntity();world.componentManager().addComponent( eid, new Position() );
[font=arial]

# Pooled Components

There are some components that might be handy if they were pooled. This is the interface I came up with for these cases:[/font]// Registering a pooled component.world.registerPoolable( Position.class, Position::new, Position::resetPosition );// Adding a pooled component to an entity.int eid = world.createEntity();world.componentManager().addPooledComponent( Position.class );
[font=arial]

## Most defintively not in "fluent style" but it works well enough registerPoolable needs a way to create new components of that type, that's why the second parameter is a Supplier of that component, which can be a static factory method, a reference to Position's constructor like in the example, an object that implements the Supplier interface, and so on. Pretty fexible.Third parameter is optional, its a Consumer that can manipulate the component when the ComponentManager fetches an existing one from the pool, in the example its a reference to a static method in Position. You might want to say, reset the position component to 0 before its gets used by another entity, or you might deem it an unnecessary cost, in that case you can just avoid providing a resetter.This has an impact in the ComponentManager since now you cant just iterate over an entity's bits and remove them, since some of them might be pooled. So now entity "cleaning" (which happens when an entity is deleted) is done in a two step process: First pooled components are removed and returned to the pool, then regular components are removed.This became rather easy using the fixed bit sets introduced in the last entry, just copy the entity bits, & with pooled bits, iterate and return to the pool.# Imagine the Possibilities! Together the fixed bit sets, plain int entities and the way ComponentManager handles components and mappers allowed for a few tweaks around the framework plus a few shortcuts I added to do some operations more efficiently (for example, adding/removing components without hash lookups).That will be for another entry though, cya!

[/font]

It can be counter-intuitive at first, but I quickly learned how awesome ECS is once you have most of the framework put together and working. I'll be writing up my own article on my recent work with ECS soon.

I don't know how I would feel about using an ID in a language that supports objects but it's looking nice.

As I alluded to in the entry, it simplifies everything. Entity pools stop making sense. Code gets simplified all over the place. Now I no longer pay 16 bytes (or more!) per entity instance, but just the 4 bytes for storing an int. And so on.

Objects are nice... just not always. Specially without value semantics, like its the case with Java.

## Create an account

Register a new account