Vexel's ECS library for Nim👑, heavily inspired by Beef🥩's yeacs, a lot of his ideas were used, and some of his macros were directly copied.
vecs's API aims to be mostly the same, with minor differences.
The main design differences between vecs and yeacs are in the implementation:
vecsavoids manually copying memory, erasure is implemented by using abstract types, then casting to concrete types when needed. This simplifies book-keeping a bit, and goes easier on references, not needing to track move semantics.vecsapproaches ECS with a collection for each component in the archetype, whileyeacsinstead uses a single collection of tuples of components for each archetype.
The API reference is available here.
# Create a world
var world = World()# Add an entity
let entityId = world.addEntity (
Character(name: "Marcus", class: "Warrior"),
Health(health: 120, maxHealth: 120)
)# Get a component from an entity
for health in world.component(entityId, Health):
health.health += 75# Get multiple components from an entity
for (character, health) in world.component(entityId, (Character, Health)):
character.name = "Happy " & character.name
health.health += 75# Query for components
var characterWithSwordsQuery = Query[(Character, Sword)]()
for (character, sword) in world.query(characterWithSwordsQuery):
echo character.name, " has a sword, ", sword.name, "!"# Removing an entity
world.removeEntity entityId# Adding a component
world.addComponent(entityId, Shield(name: "Steel Shield", defense: 15))# Removing a component
world.removeComponent(entityId, Shield)# Using an Id component fills it with the Id of the entity
# This is useful for embedding references to other entities into components
let entityId = world.addEntity (Id(), Character(name: "Leon", class: "Paladin"))
for idComponent in world.component(entityId, Id):
assert entityId == idComponent# Query components for writting
var characterWithSwordsQuery = Query[(Character, Write[Health])]()
for (character, health) in world.query(characterWithSwordsQuery):
health.health += 10# Query for optional components
var characterWithSwordsQuery = Query[(Character, Opt[Weapon])]()
for (character, weapon) in world.query(characterWithSwordsQuery):
weapon.isSmoething:
echo character.name, " has a weapon, ", weapon.name
weapon.isNothing:
echo character.name, " has no weapon"# Exclude components from a query
var disarmedCharacters = Query[(Character, Not[Weapon])]()
for (character,) in world.query(disarmedCharacters):
echo character.name, " has no weapon"-
Add entities
-
Archetypes
-
Queries
-
Remove entities
-
Support dynamic archetypes
-
Add component
-
Remove component
-
Special Id component
-
Restrict generic T on queries and components procs to be tuples
-
'Not' Queries
-
'Opt' Queries
-
'Write' Queries
-
Stable ids for components
-
Polish console output
-
Convenience procs and checks
- Allow read access to components without an iterator
-
componentfails to compile silently when used with a Tuple -
componentssys-fatals when searching for a non existing Id
-
Text serialization
-
Binary serialization
-
Convenience procs
-
componentandcomponentsaccept a list of entity ids - Add and Remove multiple components
-
-
Concurrency support
-
Zero-allocation?
-
Spatial and custom queries
-
Integrate with inim?
- Pull req: show current code
- Pull req: use nim --eval