Systems
Ark provides no systems as they are widely known in ECS implementations. This is a deliberate decisions, based on these reasons:
- Systems can be hard to integrate into frameworks, like a game engine's update loop. Ark wants to stay flexible and is completely engine-agnostic.
- Systems are usually tied to queries in a 1:1 relation, while it is easily possible to combine multiple queries.
- Systems and a scheduler are easy to implement, so this is left to the user.
Below, we provide an example for how to implement systems and a scheduler.
Systems example
Components
We start by defining our component types:
using Ark
struct Position
x::Float64
y::Float64
end
struct Velocity
dx::Float64
dy::Float64
endAbstract system type
We write and abstract system type. This is optional, but useful for clarity and to avoid boilerplate.
abstract type System end
function initialize!(::System, ::World) end
function update!(::System, ::World) end
function finalize!(::System, ::World) endScheduler
Next, we build a (type-stable) scheduler:
struct Scheduler{ST<:Tuple}
world::World
systems::ST
end
function run!(s::Scheduler, steps::Int)
# initialize all systems
for sys in s.systems
initialize!(sys, s.world)
end
# update loop
for _ in 1:steps
# update all systems
for sys in s.systems
update!(sys, s.world)
end
end
# finalize all systems
for sys in s.systems
finalize!(sys, s.world)
end
endInitializer system
Now we can write some systems. First one that creates some entities.
struct InitializerSystem <: System
count::Int
end
function initialize!(s::InitializerSystem, w::World)
for (entities, positions, velocities) in @new_entities!(w, s.count, (Position, Velocity))
@inbounds for i in eachindex(entities)
positions[i] = Position(rand() * 100, rand() * 100)
velocities[i] = Velocity(randn(), randn())
end
end
endAs we have the abstract type, we only need to implement the functions that are required for the system.
Movement system
And here the classical movement system:
struct MovementSystem <: System
end
function update!(s::InitializerSystem, w::World)
for (entities, positions, velocities) in @Query(world, (Position, Velocity))
@inbounds for i in eachindex(entities)
pos = positions[i]
vel = velocities[i]
positions[i] = Position(pos.x + vel.dx, pos.y + vel.dy)
end
end
endPutting it together
Finally, we can plug everything together:
world = World(Position, Velocity)
scheduler = Scheduler(
world,
(
InitializerSystem(100),
MovementSystem(),
),
)
run!(scheduler, 1000)