# ECSComb
`ECSComb` is an Entity-Component-System framework for Elixir built on BEAM and ETS.
It focuses on a small runtime surface:
- `ECSComb.World` owns entity lifecycle and component storage.
- `ECSComb.Query` provides runtime `all` / `any` / `none` queries.
- `ECSComb.System` defines the scheduler contract.
- `ECSComb.Scheduler` groups non-conflicting systems into parallel layers.
- `ECSComb.TickLoop` drives the world at a fixed tick rate.
## Design Highlights
- ETS-backed storage with public named tables and direct read access
- Entity IDs use `{index, generation}` to reject stale references
- Components are plain structs with no macros or registration
- System ordering is inferred from declared read/write sets
- Runtime add/remove of systems is supported between ticks
## Quick Example
```elixir
defmodule Demo.Position do
defstruct [:x, :y]
end
defmodule Demo.Velocity do
defstruct [:dx, :dy]
end
defmodule Demo.MoveSystem do
@behaviour ECSComb.System
alias ECSComb.Query
alias ECSComb.World
alias Demo.Position
alias Demo.Velocity
@impl true
def access do
%{reads: [Position, Velocity], writes: [Position]}
end
@impl true
def run(world) do
Query.select(world, all: [Position, Velocity])
|> Enum.each(fn entity_id ->
{:ok, %Position{x: x, y: y}} = World.get(world, entity_id, Position)
{:ok, %Velocity{dx: dx, dy: dy}} = World.get(world, entity_id, Velocity)
:ok = World.put(world, entity_id, %Position{x: x + dx, y: y + dy})
end)
:ok
end
end
{:ok, world} = ECSComb.World.start_link()
{:ok, entity_id} = ECSComb.World.spawn_entity(world)
:ok = ECSComb.World.put(world, entity_id, %Demo.Position{x: 0, y: 0})
:ok = ECSComb.World.put(world, entity_id, %Demo.Velocity{dx: 1, dy: 1})
scheduler =
ECSComb.Scheduler.new()
|> ECSComb.Scheduler.add_system(Demo.MoveSystem)
|> ECSComb.Scheduler.build_graph()
{:ok, tick_loop} =
ECSComb.TickLoop.start_link(
world: world,
scheduler: scheduler,
tick_rate: 20
)
Process.sleep(120)
{:ok, %Demo.Position{x: x, y: y}} = ECSComb.World.get(world, entity_id, Demo.Position)
IO.inspect({x, y}, label: "updated position")
:ok = ECSComb.TickLoop.stop(tick_loop)
```
## Test Coverage
The project includes tests for:
- Entity lifecycle and component CRUD
- Transactions, name indexes, and concurrent reads/writes
- Query filtering and indexed lookup correctness
- Behaviour validation for systems
- Scheduler conflict detection, graph layering, and parallel execution
- Tick timing, cron callbacks, and end-to-end runtime integration
## Status
Implemented and covered by `mix test`.