std/ecs/entity
std/ecs/src/entity.trb
The handle components are attached to, and the allocator that hands handles out.
type Entity
type Entity with Equals, Hash, Show
What components are attached to: an index into the columns and the generation of the handle.
Examples
const handle = Entity 3
assert(handle == Entity(3, 0))
assert(handle.generation == 0)
field index
index: Int
The slot the entity occupies. Handed out again after a despawn, with a higher generation.
field generation
generation: Int = 0
Counts up every time index is handed out again, so a stale handle is detectable.
type Entities
type Entities with Equals, Show
The allocator of Entity handles, and the only place where a generation changes.
An index that was freed comes back before a new one is made - the one freed last first - and with its generation one higher, so the handle that was kept across the despawn no longer matches. The same sequence of operations gives the same handles, which is what a lockstep simulation needs (ECS.md, "Determinism").
Entities does not know a column. Taking an entity's components out when it is despawned is the world's job, in
the program that owns the columns.
Examples
var entities = Entities()
const first = entities.spawn()
const second = entities.spawn()
assert entities.despawn(first)
assert(!entities.isAlive(first))
const reused = entities.spawn()
assert(reused == Entity(0, 1))
assert(entities.length() == 2)
assert entities.isAlive(second)
Pitfalls
- A handle that was despawned stays a valid value:
isAliveis how a caller asks, and a column answersNonefor it only because the program took its components out.
field generations
protected var generations: List<Int> = []
The generation the next handle of each index gets: raised by the despawn of the one before.
field living
protected var living: List<Bool> = []
Whether each index is handed out right now.
field freed
protected var freed: List<Int> = []
The indices that were despawned, the one freed last at the end.
field live
protected var live: Int = 0
How many entities are alive.
fn spawn
var fn spawn(): Entity
Hands out an entity: the index freed last with its generation raised, or else the next new index.
fn despawn
var fn despawn(entity: Entity): Bool
Retires an entity and answers true. A handle that is stale, never handed out or already despawned changes
nothing and answers false.
fn isAlive
fn isAlive(entity: Entity): Bool
Whether entity is the handle currently handed out for its index.
fn length
fn length(): Int
How many entities are alive.