API

Ark's public API.

World

The World is the central data storage for Entities, Components and Resources.

Ark.WorldMethod
World(
    comp_types::Type...;
    initial_capacity::Int=128,
    allow_mutable::Bool=false,
)

Creates a new, empty World for the given component types.

All component types that will be used with the world must be specified. This allows Ark to use Julia's compile-time method generation to achieve the best performance.

For each component type, an individual storage mode can be set. See also VectorStorage and StructArrayStorage.

Additional arguments can be used to allow mutable component types (forbidden by default and discouraged) and an initial capacity for entities in archetypes.

Arguments

  • comp_types: The component types used by the world.
  • initial_capacity: Initial capacity for entities in each archetype and in the entity index.
  • allow_mutable: Allows mutable components. Use with care, as all mutable objects are heap-allocated in Julia.

Examples

A World where all components use the default storage mode:

world = World(
    Position,
    Velocity,
)

A World with individually configured storage modes:

world = World(
    Position => StructArrayStorage,
    Velocity => StructArrayStorage,
    Health => VectorStorage,
)
source
Ark.reset!Function
reset!(world::World)

Removes all entities and resources from the world, and un-registers all observers. Does NOT free reserved memory or remove archetypes.

Can be used to run systematic simulations without the need to re-allocate memory for each run. Accelerates re-populating the world by a factor of 2-3.

source
Ark.is_lockedFunction
is_locked(world::World)::Bool

Returns whether the world is currently locked for modifications.

source
Ark.StructArrayStorageType
StructArrayStorage

Marks component types for using StructArray-like storage mode in the world constructor.

In StructArray storages, mutable components are not allowed.

See also VectorStorage.

Example

world = World(
    Position => StructArrayStorage,
    Velocity => StructArrayStorage,
)
source
Ark.VectorStorageType
VectorStorage

Marks component types for using Vector storage mode in the world constructor. As this is the default storage mode if the storage type is not specified.

See also StructArrayStorage.

Example

world = World(
    Position => VectorStorage,
    Velocity => VectorStorage,
)
source
Ark.RelationshipType
Relationship

Abstract marker type for relationship components.

Example

struct ChildOf <: Relationship end
source

Entities

Entities are the "game objects" or "model entities". An entity if just an ID with a generation, but Components can be attached to an entity.

Ark.new_entity!Function
new_entity!(world::World, values::Tuple; relations::Tuple=())::Entity

Creates a new Entity with the given component values. Types are inferred from the values.

Arguments

  • world::World: The World instance to use.
  • values::Tuple: Component values for the entity.
  • defaults::Tuple: A tuple of default values for initialization, like (Position(0, 0), Velocity(1, 1)).
  • relations::Tuple: Relationship component type => target entity pairs.

Examples

Create an entity with components:

entity = new_entity!(world, (Position(0, 0), Velocity(1, 1)))

Create an entity with components and relationships:

entity = new_entity!(world, (Position(0, 0), ChildOf()); relations=(ChildOf => parent,))
source
Ark.new_entities!Function
new_entities!(
    [f::Function],
    world::World,
    n::Int,
    components::Tuple;
    relations:Tuple=(),
)

Creates the given number of entities. Components can be given as types or as default values. In the latter case, types are inferred from the add values.

A callback/do-block can be run on the newly created entities e.g. for individual initialization. It takes a tuple of (entities, columns...) as argument, with a column for each added component. The callback is mandatory if components are given as types. Note that components are not initialized/undef unless set in the callback in this case.

Arguments

  • f::Function: Optional callback for initialization, can be passed as a do block.
  • world::World: The World instance to use.
  • n::Int: The number of entities to create.
  • components::Tuple: A tuple of component to add. Either default values like (Position(0, 0), Velocity(1, 1)), or types like (Position, Velocity).
  • relations::Tuple: Relationship component type => target entity pairs.
  • iterate::Bool: Whether to return a batch for individual entity initialization.

Examples

Create 100 entities from default values:

new_entities!(world, 100, (Position(0, 0), Velocity(1, 1)))

Create 100 entities from component types and initialize them:

new_entities!(world, 100, (Position, Velocity)) do (entities, positions, velocities)
    for i in eachindex(entities)
        positions[i] = Position(rand(), rand())
        velocities[i] = Velocity(1, 1)
    end
end
source
Ark.remove_entities!Function
remove_entities!([f::Function], world::World, filter::Filter)

Removes all entities that match the given Filter from the World.

The optional callback/do block is called on them before the removal. The callback's argument is an Entities list.

Example

Removing entities:

filter = Filter(world, (Position, Velocity))
remove_entities!(world, filter)

Removing entities using a callback:

filter = Filter(world, (Position, Velocity))
remove_entities!(world, filter) do entities
    # do something with the entities.
end
source
Ark.copy_entity!Function
copy_entity!(
    world::World,
    entity::Entity;
    add::Tuple=(),
    remove::Tuple=(),
    relations::Tuple=(),
    mode=:copy,
)

Copies an Entity, optionally adding and/or removing components.

Mutable and non-isbits components are shallow copied by default. This can be changed with the mode argument.

Arguments

  • world: The World instance to query.
  • entity::Entity: The entity to copy.
  • add::Tuple: Components to add, like with=(Health(0),).
  • remove::Tuple: Component types to remove, like (Position,Velocity).
  • relations::Tuple: Relationship component type => target entity pairs.
  • mode::Tuple: Copy mode for mutable and non-isbits components. Modes are :ref, :copy, :deepcopy.

Examples

Simple copy of an entity:

entity1 = copy_entity!(world, entity)

Copy an entity, adding and removing some components in the same operation:

entity2 = copy_entity!(world, entity;
    add=(Health(100),),
    remove=(Position, Velocity),
)
source

Components

Components contain the data associated with Entities.

Ark.get_componentsFunction
get_components(world::World, entity::Entity, comp_types::Tuple)

Get the given components for an Entity. Components are returned as a tuple.

Example

pos, vel = get_components(world, entity, (Position, Velocity))
source
Ark.has_componentsFunction
has_components(world::World, entity::Entity, comp_types::Tuple)::Bool

Returns whether an Entity has all given components.

Example

has = has_components(world, entity, (Position, Velocity))
source
Ark.set_components!Function
set_components!(world::World, entity::Entity, values::Tuple)

Sets the given component values for an Entity. Types are inferred from the values. The entity must already have all these components.

Example

set_components!(world, entity, (Position(0, 0), Velocity(1, 1)))
source
Ark.add_components!Function
add_components!(world::World, entity::Entity, values::Tuple; relations::Tuple)

Adds the given component values to an Entity. Types are inferred from the values.

Example

add_components!(world, entity, (Health(100),))
source
add_components!(
    [f::Function]
    world::World,
    filter::Filter,
    add::Tuple=(),
    relations::Tuple=(),
)

Adds components to all entities matching the given Filter.

Components can be added as types or as values. In the latter case, types are inferred from the add values.

A callback/do-block can be run on the affected entities e.g. for individual initialization. It takes a tuple of (entities, columns...) as argument, with a column for each added component. The callback is mandatory if components are added as types. Note that components are not initialized/undef unless set in the callback in this case.

Arguments

  • f::Function: Optional callback for initialization, can be passed as a do block.
  • world::World: The World instance to use.
  • filter::Filter: The Filter to select entities.
  • add::Tuple: A tuple of component to add. Either default values like (Position(0, 0), Velocity(1, 1)), or types like (Position, Velocity).
  • relations::Tuple: Relationship component type => target entity pairs.

Examples

Adding values, not using the callback:

filter = Filter(world, (Velocity,))
add_components!(world, filter, (Health(100),))

Adding as types, using the callback for initialization:

filter = Filter(world, (Velocity,))
add_components!(world, filter, (Health,)) do (entities, healths)
    for i in eachindex(entities, healths)
        healths[i] = Health(i * 2)
    end
end
source
Ark.remove_components!Function
remove_components!(world::World, entity::Entity, comp_types::Tuple)

Removes the given components from an Entity.

Example

remove_components!(world, entity, (Position, Velocity))
source
remove_components!(
    [f::Function]
    world::World,
    filter::Filter,
    remove::Tuple=(),
)

Removes components from all entities matching the given Filter.

A callback/do-block can be run on the affected entities. It takes an entities column as argument.

Arguments

  • f::Function: Optional callback for initialization, can be passed as a do block.
  • world::World: The World instance to use.
  • filter::Filter: The Filter to select entities.
  • remove::Tuple: A tuple of component types to remove, like (Position, Velocity)

Examples

Removing components, not using the callback:

filter = Filter(world, (Velocity,))
remove_components!(world, filter, (Velocity,))

Removing components, using the optional callback:

filter = Filter(world, (Velocity,))
remove_components!(world, filter, (Velocity,)) do entities
    # do something with the entities...
end
source
Ark.exchange_components!Function
exchange_components!(
    world::World,
    entity::Entity;
    add::Tuple=(),
    remove::Tuple=(),
    relations::Tuple=(),
)

Adds and removes components on an Entity. Types are inferred from the add values.

Example

exchange_components!(world, entity;
    add=(Health(100),),
    remove=(Position, Velocity),
)
source
exchange_components!(
    [f::Function]
    world::World,
    filter::Filter;
    add::Tuple=(),
    remove::Tuple=(),
    relations::Tuple=(),
)

Adds and removes components on all entities matching the given Filter.

Components can be added as types or as values. In the latter case, types are inferred from the add values.

A callback/do-block can be run on the affected entities e.g. for individual initialization. It takes a tuple of (entities, columns...) as argument, with a column for each added component. The callback is mandatory if components are added as types. Note that components are not initialized/undef unless set in the callback in this case.

Arguments

  • f::Function: Optional callback for initialization, can be passed as a do block.
  • world::World: The World instance to use.
  • filter::Filter: The Filter to select entities.
  • add::Tuple: A tuple of component to add. Either default values like (Position(0, 0), Velocity(1, 1)), or types like (Position, Velocity).
  • remove::Tuple: A tuple of component types to remove, like (Position, Velocity)
  • relations::Tuple: Relationship component type => target entity pairs.

Examples

Adding values, not using the callback:

filter = Filter(world, (Velocity,))
exchange_components!(world, filter;
    add=(Health(100),),
    remove=(Velocity,),
)

Adding as types, using the callback for initialization:

filter = Filter(world, (Velocity,))
exchange_components!(world, filter;
    add=(Health,),
    remove=(Velocity,),
) do (entities, healths)
    for i in eachindex(entities, healths)
        healths[i] = Health(i * 2)
    end
end
source
Ark.get_relationsFunction
get_relations(world::World, entity::Entity, comp_types::Tuple)

Get the relation targets for components of an Entity. Targets are returned as a tuple.

Example

parent, = get_relations(world, entity, (ChildOf,))
source
Ark.set_relations!Function
set_relations!(world::World, entity::Entity, relations::Tuple)

Sets relation targets for the given components of an Entity. The entity must already have all these relationship components.

Example

set_relations!(world, entity, (ChildOf => parent,))
source
set_relations!([f::Function], world::World, filter::Filter::Entity, relations::Tuple)

Sets relation targets for the given components of all entities matching the given Filter. Optionally runs a callback/do-block on the affected entities.

Example

Setting relation targets:

filter = Filter(world, (ChildOf,); relations=(ChildOf => parent,))
set_relations!(world, filter, (ChildOf => parent2,))

Setting relation targets and running a callback:

filter = Filter(world, (ChildOf,); relations=(ChildOf => parent,))
set_relations!(world, filter, (ChildOf => parent2,)) do entities
    # do something with the entities...
end
source

Queries and Filters

Queries are used to filter and process Entities with a certain set of Components.

Ark.QueryMethod
Query(
    world::World,
    comp_types::Tuple;
    with::Tuple=(),
    without::Tuple=(),
    optional::Tuple=(),
    exclusive::Bool=false,
    relations::Tuple=(),
)

Creates a query.

A query is an iterator for processing all entities that match the query's criteria. The query itself iterates matching archetypes, while an inner loop or broadcast operations must be used to manipulate individual entities (see example below).

A query locks the World until it is fully iterated or closed manually. This prevents structural changes like creating and removing entities or adding and removing components during the iteration.

See the user manual chapter on Queries for more details and examples.

Arguments

  • world: The World instance to query.
  • comp_types::Tuple: Components the query filters for and provides access to.
  • with::Tuple: Additional components the entities must have.
  • without::Tuple: Components the entities must not have.
  • optional::Tuple: Additional components that are optional in the query.
  • exclusive::Bool: Makes the query exclusive in base and with components, can't be combined with without.
  • relations::Tuple: Relationship component type => target entity pairs. These relation components must be in the query's components or with.

Example

for (entities, positions, velocities) in Query(world, (Position, Velocity))
    for i in eachindex(entities)
        pos = positions[i]
        vel = velocities[i]
        positions[i] = Position(pos.x + vel.dx, pos.y + vel.dy)
    end
end
source
Ark.close!Method
close!(q::Query)

Closes the query and unlocks the world.

Must be called if a query is not fully iterated.

source
Ark.FilterMethod
Filter(
    world::World,
    comp_types::Tuple;
    with::Tuple=(),
    without::Tuple=(),
    optional::Tuple=(),
    exclusive::Bool=false,
    relations::Tuple=(),
    register::Bool=false,
)

Creates a filter. Filters are similar to queries, but can't be iterated directly. They are a re-usable way to define query filtering criteria, and can be registered for faster, cached queries. Further, filters are used in batch operations.

See the user manual chapter on Queries for more details and examples.

Arguments

  • world: The World instance to filter.
  • comp_types::Tuple: Components the filter filters for.
  • with::Tuple: Additional components the entities must have.
  • without::Tuple: Components the entities must not have.
  • optional::Tuple: Additional components that are optional in the filter.
  • exclusive::Bool: Makes the filter exclusive in base and with components, can't be combined with without.
  • relations::Tuple: Relationship component type => target entity pairs. These relation components must be in the filter's components or with.
source
Ark.count_entitiesFunction
count_entities(f::Filter)

Returns the number of matching entities in the filter.

Note

The time complexity is linear with the number of archetypes in the filter's pre-selection. It is equivalent to iterating the filter's archetypes and summing up their lengths.

source
count_entities(q::Query)

Returns the number of matching entities in the query.

Does not iterate or close! the query.

Note

The time complexity is linear with the number of archetypes in the query's pre-selection. It is equivalent to iterating the query's archetypes and summing up their lengths.

source
Base.lengthFunction
length(f::Filter)

Returns the number of matching tables with at least one entity in the filter.

Note

The time complexity is linear with the number of tables in the filter's pre-selection.

source
length(q::Query)

Returns the number of matching tables with at least one entity in the query.

Does not iterate or close! the query.

Note

The time complexity is linear with the number of tables in the query's pre-selection.

source
Ark.@unpackMacro
@unpack ...

Unpacks the tuple returned from a Query during iteration into field vectors. Field vectors are particularly useful for StructArrayStorages, but can also be used with VectorStorages, although those are currently not equally efficient in broadcasted operations.

Columns for components without fields, like primitives or label components, fall through @unpack unaltered.

See also unpack(::StructArrayView) and unpack(::FieldViewable).

Example

for columns in Query(world, (Position, Velocity))
    @unpack entities, (x, y), (dx, dy) = columns
    @inbounds x .+= dx
    @inbounds y .+= dy
end
source
Ark.unpackFunction
unpack(a::StructArrayView)

Unpacks the components (i.e. field vectors) of a StructArrayStorage column returned from a Query. See also @unpack.

source
unpack(a::FieldViewable)

Unpacks the components (i.e. field vectors) of a VectorStorage column returned from a Query. See also @unpack.

Note

Setting values on unpacked non-isbits fields of immutable components has a certain overhead, as the underlying struct needs to be reconstructed and written to memory. See

source

Resources

Resources are singleton-like data structures that appear only once in a World and are not associated to an Entity.

Ark.get_resourceFunction
get_resource(world::World, res_type::Type{T})::T

Get the resource of type T from the world.

source
Ark.has_resourceFunction
has_resource(world::World, res_type::Type{T})::Bool

Check if a resource of type T is in the world.

source
Ark.add_resource!Function
add_resource!(world::World, res::T)::T

Add the given resource to the world. Returns the newly added resource.

source
Ark.set_resource!Function
set_resource!(world::World, res::T)::T

Overwrites an existing resource in the world. Returns the newly overwritten resource.

source
Ark.remove_resource!Function
remove_resource!(world::World, res_type::Type{T})::T

Remove the resource of type T from the world. Returns the removed resource.

source

Event system

The event system allows user code to react on structural changes like entity creation and removal and component addition and removal. Further, custom events can be defined and emitted.

Ark.EventTypeType
EventType

Type for built-in and custom events. See EventRegistry for creating custom event types.

Built-in event types

  • OnCreateEntity: Event emitted after a new entity is created.
  • OnRemoveEntity: Event emitted before an entity is removed from the World.
  • OnAddComponents: Event emitted after components are added to an entity.
  • OnRemoveComponents: Event emitted before components are removed from an entity.
  • OnAddRelations: Event emitted after relation targets are added to an entity. Includes creating entities, adding components as well as setting relation targets.
  • OnRemoveRelations: Event emitted before relation targets are removed from an entity. Includes removing entities, removing components as well as setting relation targets.
source
Ark.new_event_type!Function
new_event_type!(reg::EventRegistry, symbol::Symbol)

Creates a new custom EventType. Custom event types are best stored in global constants.

The symbol is only used for printing.

Example

registry = EventRegistry()
const OnGameOver = new_event_type!(registry, :OnGameOver)
source
Ark.observe!Function
observe!(
    fn::Function,
    world::World,
    event::EventType,
    components::Tuple=();
    with::Tuple=(),
    without::Tuple=(),
    exclusive::Bool=false,
    register::Bool=true,
)

Creates an Observer and (optionally, default) registers it.

See EventType for built-in, and EventRegistry for custom event types.

Arguments

  • fn::Function: A callback function to execute when a matching event is received. Can be used via a do block.
  • world::World: The World to observe.
  • event::EventType: The EventType to observe.
  • components::Tuple=(): The component types to observe. Must be empty for OnCreateEntity and OnRemoveEntity.
  • with::Tuple=(): Components the entity must have.
  • without::Tuple=(): Components the entity must not have.
  • exclusive::Bool=false: Makes the observer exclusive for entities that have exactly the components given be with.
  • register::Bool=true: Whether the observer is registered immediately. Alternatively, register later with observe!

Example

observe!(world, OnAddComponents, (Position, Velocity); with=(Altitude,)) do entity
    println(entity)
end
source
observe!(world::World, observer::Observer; unregister::Bool=false)

Registers or un-registers the given Observer. Note that observers created with observe! are automatically registered by default.

source
Ark.emit_event!Function
emit_event!(world::World, event::EventType, entity::Entity, components::Tuple=())

Emits a custom event for the given EventType, Entity and optional components. The entity must have the given components. The entity can be the reserved zero_entity.

  • world::World: The World to emit the event.
  • event::EventType: The EventType to emit.
  • entity::Entity: The Entity to emit the event for.
  • components::Tuple=(): The component types to emit the event for. Optional.

Example

emit_event!(world, OnCollisionDetected, entity, (Position, Velocity))
source

Index