Skip to content

Entities

fennecs in a box

cuddly, lively, come in litters of 1,073,741,824 Neofox: snuggle

Neofox: thumbsup The Heart of Your Game State

Entities are your actors, your game objects, your... well, things! They're lightweight handles that you attach components to, creating rich, composable game state.

What is an Entity?

An Entity is a lightweight, immutable handle – technically a readonly record struct. It's just an identity paired with a reference to its World.

cs
var player = world.Spawn();           // Create an entity
player.Add(new Health { Value = 100 }); // Give it components
player.Add<Player>();                   // Tag it as the player

You can store entities anywhere: in variables, collections, or even as components on other entities!

Quick Reference

OperationMethodDescription
CreateWorld.Spawn()Spawn a new entity
DestroyEntity.Despawn()Remove entity from world
Add dataEntity.Add<C>()Attach a component
Remove dataEntity.Remove<C>()Detach a component
Check dataEntity.Has<C>()Check if component exists
Read/WriteEntity.Ref<C>()Get reference to component
Get or CreateEntity.Ensure<C>()Ensure component exists
Check aliveEntity.AliveIs entity still valid?

Lifecycle Neofox: snug

Entities have a simple, predictable lifecycle:

  1. Spawn - Created via World.Spawn() or EntitySpawner
  2. Live - Exists in the world, can have components attached
  3. Despawn - Removed from world, recycled for reuse
cs
var fox = world.Spawn();
Console.WriteLine(fox.Alive); // true

fox.Despawn();
Console.WriteLine(fox.Alive); // false

Each Entity knows if it is alive inside a World. An Entity can only live in one World at a time – and it needs a World to be alive. (don't we all!)

Neofox: science Memory Efficient

Despawned entities are recycled, so spawning and despawning is extremely cheap – even in large waves – without runaway memory consumption.

Composition Neofox: heart

Entities can have any number of Components attached to them. This is how fennecs provides composable, structured data semantics.

cs
// Build up an entity with multiple components
var enemy = world.Spawn()
    .Add(new Position { X = 10, Y = 20 })
    .Add(new Velocity { X = -1, Y = 0 })
    .Add(new Health { Value = 50 })
    .Add<Enemy>();  // Tag component

Component Types

TypeExampleUse Case
PlainAdd(new Position())Regular data
TagAdd<Enemy>()Zero-size markers
RelationAdd<Likes>(otherEntity)Entity-to-entity relationships
Object LinkAdd(Link.With(gameObject))Links to managed objects

Entities can also serve as the secondary key in a Relation between two entities.

Archetypes

Entities with identical combinations of component Type Expressions share the same Archetype. This is how fennecs achieves blazing-fast iteration – entities with the same "shape" are stored together in contiguous memory.

Neofox: think A Dead Entity Has No Components

When an entity is despawned, all its components are removed. The entity handle becomes a stale reference to a recycled identity.

Internals

Neofox: magnify Tidbits for the Curious

The defining property of an entity is its Identity – a 64-bit value combining an index and a generation counter. Paired with a specific World, this gives us a unique handle to operate on.

A dead Entity doesn't exist in any World – it's just stale data with a leftover Identity whose successor was already returned to the internal IdentityPool.

Living Entities occupy a slot in the world's storage structure:

  • A Meta entry in the world's Meta-Set (tracking archetype membership)
  • A row in their current Archetype's storage (Storage<Identity>)

The generation counter ensures that even recycled entity slots produce unique identities, preventing accidental access to "wrong" entities.

fennecs is released under the MIT License. Neofox is released under the CC BY-NC-SA 4.0 License.