API
Ark's public API.
World
The World is the central data storage for Entities, Components and Resources.
Ark.World — Method
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,
)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.
Ark.is_locked — Function
is_locked(world::World)::BoolReturns whether the world is currently locked for modifications.
Ark.StructArrayStorage — Type
StructArrayStorageMarks 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,
)Ark.VectorStorage — Type
VectorStorageMarks 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,
)Ark.Relationship — Type
RelationshipAbstract marker type for relationship components.
Example
struct ChildOf <: Relationship endEntities
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.Entity — Type
EntityEntity identifier.
Entities can be constructed using a World via new_entity! and new_entities!.
Entities can be safely stored in components and resources.
Ark.zero_entity — Constant
const zero_entity::EntityThe reserved zero Entity value. Can be used to represent "no entity"/"nil".
Ark.new_entity! — Function
new_entity!(world::World, values::Tuple; relations::Tuple=())::EntityCreates a new Entity with the given component values. Types are inferred from the values.
Arguments
world::World: TheWorldinstance 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,))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 adoblock.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
endArk.remove_entity! — Function
remove_entity!(world::World, entity::Entity)Removes an Entity from the World.
Example
remove_entity!(world, entity)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.
endArk.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: TheWorldinstance to query.entity::Entity: The entity to copy.add::Tuple: Components to add, likewith=(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),
)Ark.is_alive — Function
is_alive(world::World, entity::Entity)::BoolReturns whether an Entity is alive.
Ark.is_zero — Function
is_zero(entity::Entity)::BoolReturns whether an Entity is the reserved zero_entity.
Components
Components contain the data associated with Entities.
Ark.get_components — Function
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))Ark.has_components — Function
has_components(world::World, entity::Entity, comp_types::Tuple)::BoolReturns whether an Entity has all given components.
Example
has = has_components(world, entity, (Position, Velocity))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)))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),))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 adoblock.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
endArk.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))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 adoblock.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...
endArk.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),
)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 adoblock.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
endArk.get_relations — Function
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,))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,))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...
endQueries and Filters
Queries are used to filter and process Entities with a certain set of Components.
Ark.Query — Method
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: TheWorldinstance 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 andwithcomponents, can't be combined withwithout.relations::Tuple: Relationship component type => target entity pairs. These relation components must be in the query's components orwith.
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
endArk.close! — Method
close!(q::Query)Closes the query and unlocks the world.
Must be called if a query is not fully iterated.
Ark.Filter — Type
Ark.Filter — Method
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: TheWorldinstance 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 andwithcomponents, can't be combined withwithout.relations::Tuple: Relationship component type => target entity pairs. These relation components must be in the filter's components orwith.
Ark.unregister! — Function
unregister!(world::World, filter::Filter)Un-registers a Filter.
Ark.count_entities — Function
count_entities(f::Filter)Returns the number of matching entities in the filter.
count_entities(q::Query)Returns the number of matching entities in the query.
Does not iterate or close! the query.
Base.length — Function
length(f::Filter)Returns the number of matching tables with at least one entity in the filter.
length(q::Query)Returns the number of matching tables with at least one entity in the query.
Does not iterate or close! the query.
Ark.Entities — Type
EntitiesArchetype column for entities. Can be iterated and indexed like a Vector, but is read-only.
Used in query iteration and batch operations callbacks.
Ark.@unpack — Macro
@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
endArk.unpack — Function
unpack(a::StructArrayView)Unpacks the components (i.e. field vectors) of a StructArrayStorage column returned from a Query. See also @unpack.
unpack(a::FieldViewable)Unpacks the components (i.e. field vectors) of a VectorStorage column returned from a Query. See also @unpack.
Resources
Resources are singleton-like data structures that appear only once in a World and are not associated to an Entity.
Ark.get_resource — Function
get_resource(world::World, res_type::Type{T})::TGet the resource of type T from the world.
Ark.has_resource — Function
has_resource(world::World, res_type::Type{T})::BoolCheck if a resource of type T is in the world.
Ark.add_resource! — Function
add_resource!(world::World, res::T)::TAdd the given resource to the world. Returns the newly added resource.
Ark.set_resource! — Function
set_resource!(world::World, res::T)::TOverwrites an existing resource in the world. Returns the newly overwritten resource.
Ark.remove_resource! — Function
remove_resource!(world::World, res_type::Type{T})::TRemove the resource of type T from the world. Returns the removed resource.
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.EventType — Type
EventTypeType 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.
Ark.EventRegistry — Type
EventRegistryServes for creating custom event types.
Ark.EventRegistry — Method
EventRegistry()Creates a new EventRegistry.
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)Ark.Observer — Type
ObserverObserver for reacting on built-in and custom events.
See observe! for details. See EventType for built-in, and EventRegistry for custom event types.
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 adoblock.world::World: The World to observe.event::EventType: The EventType to observe.components::Tuple=(): The component types to observe. Must be empty forOnCreateEntityandOnRemoveEntity.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 bewith.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)
endobserve!(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.
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))Index
Ark.zero_entityArk.EntitiesArk.EntityArk.EventRegistryArk.EventRegistryArk.EventTypeArk.FilterArk.FilterArk.ObserverArk.QueryArk.QueryArk.QueryArk.RelationshipArk.StructArrayStorageArk.VectorStorageArk.WorldArk.WorldArk.add_components!Ark.add_resource!Ark.close!Ark.copy_entity!Ark.count_entitiesArk.emit_event!Ark.exchange_components!Ark.get_componentsArk.get_relationsArk.get_resourceArk.has_componentsArk.has_resourceArk.is_aliveArk.is_lockedArk.is_zeroArk.new_entities!Ark.new_entity!Ark.new_event_type!Ark.observe!Ark.remove_components!Ark.remove_entities!Ark.remove_entity!Ark.remove_resource!Ark.reset!Ark.set_components!Ark.set_relations!Ark.set_resource!Ark.unpackArk.unregister!Base.lengthArk.@unpack