src/world

Search:
Group by:
Source   Edit  

Types

DoubleAddDefect = object of Defect
Source   Edit  
World = object
Source   Edit  

Procs

proc `==`(a, b: ComponentId): bool {.borrow, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc add[T: tuple](world: var World; components: T;
                   mode: OperationMode = Deferred): EntityId {.discardable.}
Add an entity with components. Automatically adds the special Meta component, so queries can access metadata like the entity's Id. If mode is Deferred, the entity with a Meta component is created immediately, but the components will be added when consolidate() is called, Deferred is the default mode. If mode is after(query), the entity with a Meta component is created immediately, but the components will be added after query is iterated. If mode is Immediate, the entity and components will be added immediately. Note: Adding entities immediately during query iteration leads to undefined behaviour. Returns the new entity's Id.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"),), Immediate)

assert w.read(marcus, Meta).id == marcus
assert w.read(marcus, Character).name == "Marcus"
Source   Edit  
proc add[T: tuple](world: var World; id: EntityId; components: T;
                   mode: OperationMode = Deferred)
Add components to an entity. If mode is Deferred, the components will be added when consolidate() is called, Deferred is the default mode. If mode is after(query), the components will be added after query is iterated. If mode is Immediate, the components will be added immediately. Note: Adding components immediately during query iteration leads to undefined behaviour.

Example:

import examples
import show

var w = World()
let marcus = w.add (Character(name: "Marcus"),)
w.add(marcus, (Health(health: 100, maxHealth: 100), Weapon(name: "Sword", attack: 10)))
w.consolidate()

assert w.has(marcus, Health)
assert w.has(marcus, Weapon)
Source   Edit  
proc add[T](world: var World; id: EntityId; component: T;
            mode: OperationMode = Deferred)
Add a component to an entity. If mode is Deferred, the component will be added when consolidate() is called, Deferred is the default mode. If mode is after(query), the component will be added after query is iterated. If mode is Immediate, the component will be added immediately. Note: Adding components immediately during query iteration leads to undefined behaviour.

Example:

import examples
import show

var w = World()
let marcus = w.add (Character(name: "Marcus"),)
w.add(marcus, Health(health: 100, maxHealth: 100))
w.consolidate()

assert w.has(marcus, Health)
Source   Edit  
proc addWithSpecificId(world: var World; id: EntityId) {.
    ...raises: [Exception, KeyError], tags: [RootEffect], forbids: [].}
Add an entity with a given id immediately. The entity will have a single Meta component. This is useful mostly for deserialization. Note: Any id above 0 is valid, however a greater id will allocate more memory.

Example:

import examples

var w = World()
w.addWithSpecificId(EntityId(value: 10))
Source   Edit  
proc cleanupEmptyArchetypes(world: var World) {....raises: [KeyError], tags: [],
    forbids: [].}
Cleans up empty archetypes. This is useful mostly for deserialization routines. Removing archetypes forces caches from queries to be rebuilt. Source   Edit  
proc componentIdFrom[T](world: var World; desc: typedesc[T]): ComponentId
 Get the ComponentId for a given component type. This is mostly useful to identify the components of an archetype. Source   Edit  
proc consolidate(world: var World) {....raises: [Exception, KeyError],
                                     tags: [RootEffect], forbids: [].}
Consolidates all additions and removals in the world. Source   Edit  
proc emit[T](world: var World; event: T)
Enqueue an event of type T into the world's event queue for that type. Events are collected and drained by collect.

Example:

type DamageEvent = object
  amount: int

var w = World()
w.emit(DamageEvent(amount: 10))
Source   Edit  
proc has(world: var World; id: EntityId): bool {....raises: [], tags: [],
    forbids: [].}
Check if an entity exists.

Example:

import examples

var w = World()
let marcus = w.add (Character(name: "Marcus"),)
assert w.has(marcus) == true
assert w.has(EntityId(value: 10)) == false
Source   Edit  
proc has[T](world: var World; id: EntityId; compDesc: typedesc[T]): bool
Check if an entity has a given component.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"),), Immediate)
assert w.has(marcus, Character)
assert not w.has(marcus, Health)
Source   Edit  
proc hash(id: ArchetypeId): Hash {....raises: [], tags: [], forbids: [].}
Source   Edit  
proc read[T: tuple](world: var World; id: EntityId; tup: typedesc[T]): T
Direct read access to multiple components of an entity. The T tuple must contain no Write, Opt, or Not accessors.

Example:

import examples

var w = World()
let character = Character(name: "Marcus")
let sword = Weapon(name: "Sword")
let elements = Spellbook(spells: @["Fireball", "Ice Storm", "Lightning"])
let marcus = w.add((character, sword, elements), Immediate)

let (weapon, spellbook) = w.read(marcus, (Weapon, Spellbook))

assert weapon.name == "Sword"
assert spellbook.spells == @["Fireball", "Ice Storm", "Lightning"]
Source   Edit  
proc read[T](world: var World; id: EntityId; compDesc: typedesc[T]): T
Directly read a single component of an entity.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"),), Immediate)
let character = w.read(marcus, Character)
assert character.name == "Marcus"
Source   Edit  
proc remove(world: var World; id: EntityId; mode: OperationMode = Deferred)
Remove an entity from the world. If mode is Deferred, the entity will be removed when consolidate() is called, Deferred is the default mode. If mode is after(query), the entity will be removed after query is iterated. If mode is Immediate, the entity will be removed immediately. Note: Removing entities immediately during query iteration leads to undefined behaviour.

Example:

import examples

var w = World()
let marcus = w.add (Character(name: "Marcus"),)
w.remove(marcus)
w.consolidate()

var query: Query[(Character,)]
for character in w.query(query):
  raiseAssert "No character should exist."
Source   Edit  
proc remove[T: tuple](world: var World; id: EntityId; descriptions: typedesc[T];
                      mode: OperationMode = Deferred)
Remove multiple components from an entity. If mode is Deferred, the components will be removed when consolidate() is called, Deferred is the default mode. If mode is after(query), the components will be removed after query is iterated. If mode is Immediate, the components will be removed immediately. Note: Removing components immediately during query iteration leads to undefined behaviour.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"), Weapon(name: "Sword")), Immediate)
w.remove(marcus, (Weapon, Character))
w.consolidate()

assert not w.has(marcus, Character)
assert not w.has(marcus, Weapon)
Source   Edit  
proc remove[T](world: var World; id: EntityId; compDesc: typedesc[T];
               mode: OperationMode = Deferred)
Remove a component from an entity. If mode is Deferred, the component will be removed when consolidate() is called, Deferred is the default mode. If mode is after(query), the component will be removed after query is iterated. If mode is Immediate, the component will be removed immediately. Note: Removing a component immediately during query iteration leads to undefined behaviour.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"), Weapon(name: "Sword")), Immediate)
w.remove(marcus, Weapon)
w.consolidate()

assert w.has(marcus, Weapon) == false
Source   Edit  

Iterators

iterator archetypes(world: var World): Archetype {....raises: [KeyError], tags: [],
    forbids: [].}

Iterate through all the world's archetypes.

This is mostly useful just to implement custom queries. To use Archetypes, the archetype module must be imported.

Source   Edit  
iterator collect[T](world: var World; _: typedesc[T]): T
Yield all queued events of type T and drain the queue. A second call to collect for the same type in the same frame yields nothing.

Example:

type DamageEvent = object
  amount: int

var w = World()
w.emit(DamageEvent(amount: 10))
w.emit(DamageEvent(amount: 20))

for event in w.collect(DamageEvent):
  assert event.amount > 0
Source   Edit  
iterator components[T: tuple](world: var World; id: EntityId; tup: typedesc[T]): tup.accessTuple
Read, write, and optional access to components of an entity. An iterator is used to ensure fast and safe access to the components. Accessors:
  • Read access: just use the component's type
  • Write access: use Write[Component]
  • Optional access: use Opt[Component], availability can be checked with isSomething or isNothing
  • Not access: use Not[Component], to avoid access if the entity contains Component

Example:

import examples

var w = World()
let character = Character(name: "Marcus")
let weapon = Weapon(name: "Sword")
let spellbook = Spellbook(spells: @["Fireball", "Ice Storm", "Lightning"])
let marcus = w.add((character, weapon, spellbook), Immediate)

for (character, weapon, armor, spellbook) in w.components(marcus, (Character, Write[Weapon], Opt[Armor], Opt[Spellbook])):
  echo character.name
  weapon.attack = 10

  armor.isSomething:
    raiseAssert "Marcus should have no armor."
  armor.isNothing:
    echo "Marcus has no armor."

  spellbook.isSomething:
    echo "Marcus's spellbook contains: ", value.spells
  spellbook.isNothing:
    raiseAssert "Marcus should have a spellbook."

assert w.read(marcus, Weapon).attack == 10
Source   Edit  
iterator query[T: tuple](world: var World; query: var Query[T]): T.accessTuple

Query for components on entities. Components are matched based on the query's type parameter.

Accessors:

  • Read access: match entities that have the component for read only access. Just use the component's type.
  • Write access: match entities that have the comoponent for write access. Use Write[Component].
  • Optional access: match entities that may or may not have the component. Use Opt[Component], availability can be checked with isSomething or isNothing.
  • Not access: match entities that do not have the component. Use Not[Component].

The iterated tuple's type is the same as the query's type parameter, except for:

  • the Not accessors are excluded.
  • the Write accessors are replaced with the component's type.

Queries build a cache that is updated each time the query is used.

Example:

import examples

var w = World()
w.add((Character(name: "Marcus"), Health(health: 100, maxHealth: 100), Weapon(name: "Sword")), Immediate)
w.add((Character(name: "Elena"), Health(health: 80, maxHealth: 80), Amulet(name: "Arcane Stone")), Immediate)
w.add((Character(name: "Brom"), Health(health: 140, maxHealth: 140), Armor(name: "Fur Armor")), Immediate)

# Query for characters, health with write access, an optional weapon, and no armor.
var query: Query[(Character, Write[Health], Opt[Weapon], Not[Armor])]

for (character, health, weapon) in w.query(query):
  health.health += 10
  assert character.name != "Brom"

  weapon.isSomething:
    assert character.name == "Marcus"
    echo character.name, " has a weapon: ", value.name

  weapon.isNothing:
    assert character.name == "Elena"
    echo character.name, " has no weapon."
Source   Edit  
iterator queryForRemoval[T](world: var World; compDesc: typedesc[T]): (Meta, T).accessTuple
Query for components to be removed from entities and components on entities to be removed. The yielded components have write access.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"), Weapon(name: "Sword", attack: 10)), Immediate)
let elena = w.add((Character(name: "Elena"), Weapon(name: "Dagger", attack: 5)), Immediate)
let brom = w.add((Character(name: "Brom"), Weapon(name: "Axe", attack: 15)), Immediate)

w.remove(marcus, Weapon)
w.remove(elena, Weapon)
w.remove(brom)

var removedWeapons: seq[(Meta, Weapon)] = @[]
for (meta, weapon) in w.queryForRemoval(Weapon):
  removedWeapons.add (meta, weapon)
  assert weapon.name in ["Sword", "Dagger", "Axe"]

assert removedWeapons.len == 3
Source   Edit  
iterator write[T](world: var World; id: EntityId; compDesc: typedesc[T]): var T
Write access to a single component of an entity. An iterator is used to ensure fast and safe access to the component.

Example:

import examples

var w = World()
let marcus = w.add((Character(name: "Marcus"),), Immediate)

for character in w.write(marcus, Character):
  character.name = "Mark"

assert w.read(marcus, Character).name == "Mark"
Source   Edit  

Macros

macro typeHash[T](typ: typedesc[T]): int
Source   Edit