The ‘E’ in ECS

In ECS, entities are just an identifier which components will be attached to, usually just an integer.

Rather than just a typedef for Int, I decided to make Entity a struct to provide a bit more type safety. I’m trusting in the swift compiler to make this reasonably efficient.

struct Entity : Hashable {
	let id: Int
}

EntityBuilder

Unique ids need to be assigned to each new entity. In addition, when entities are created, we’re going to need to usually add components to them. So there’s an EntityBuilder class that will create and assign ids to new entities.

Also, when entities are destroyed, we’ll want to reclaim those ids and notify anyone interested that the entities are gone.

We’ll come back to EntityBuilder to help us add components to an entity

class EntityBuilder {
	/***
	 * Builds an entity with the next available id
	 */
	func build() -> Entity {
		if let freeId = _freeIds.last {
			_freeIds.removeLast()
			return Entity(id: freeId)
		}
		defer { _nextId += 1 }
		return Entity(id: _nextId)
	}

	/***
	 * Destroys an entity, returning it's id to the pool and notifies any registered entity container that it's been destroyed.
	 */
	func destroy(entity: Entity) {
		for list in _lists {
			list.remove(entity: entity)
		}
		_freeIds.append(entity.id)
	}
	/***
	 * Destroys all entities
	 */
	func destroyAll() {
		_nextId = 0
		_freeIds = []
		for list in _lists {
			list.removeAll()
		}
	}

	/***
	 * Registers a container with the builder that will be notified when an entity is destroyed.
	 * This allows the container to clean up any resources associated with the entity
	 */
	func register(componentList: EntityContainer) {
		_lists.append(componentList)
	}
	/***
	 * Registers multiple containers with the builder.
	 */
	func register(lists: [EntityContainer]) {
		_lists += lists
	}
  private var _nextId = 0
	private var _freeIds = [Int]()
	private var _lists = [EntityContainer]()
	

}

The protocol for EntityContainer is fairly straight forward

/***
 * Protocol for anything that needs to be notified when an entity is destroyed
 */
protocol EntityContainer {
	func remove(entity: Entity)
	func removeAll()
	func register(with builder: EntityBuilder) -> Self
}

So we end up with an entity builder that can create entities and destroy them, then notify anything interested when entities are destroyed (purely for cleaning up any resources).

Next up

Components and component containers

All posts about the development of SwiftECS can be found here

:computer:

Updated: