Skip to content

mlange-42/arche

Repository files navigation

Arche (logo) Test status Coverage Status Go Report Card User Guide Go Reference GitHub DOI:10.5281/zenodo.7656484 MIT license

Arche is an archetype-based Entity Component System for Go.

——

Features   •   Installation   •   Usage   •   Tools   •   Design   •   Benchmarks

Features

  • Designed for performance and highly optimized. See the Benchmarks.
  • Well-documented API and comprehensive User Guide.
  • No systems. Just queries. Use your own structure (or the Tools).
  • No dependencies. Except for unit tests (100% test coverage).
  • World serialization and deserialization with arche-serde.

Installation

To use Arche in a Go project, run:

go get github.com/mlange-42/arche

Usage

Here is the classical Position/Velocity example that every ECS shows in the docs. It uses the type-safe generic API.

See the User Guide, API docs and examples for details. For more complex examples, see arche-demo.

package main

import (
	"math/rand"

	"github.com/mlange-42/arche/ecs"
	"github.com/mlange-42/arche/generic"
)

// Position component
type Position struct {
	X float64
	Y float64
}

// Velocity component
type Velocity struct {
	X float64
	Y float64
}

func main() {
	// Create a World.
	world := ecs.NewWorld()

	// Create a component mapper.
	mapper := generic.NewMap2[Position, Velocity](&world)

	// Create entities.
	for i := 0; i < 1000; i++ {
		// Create a new Entity with components.
		entity := mapper.New()
		// Get the components
		pos, vel := mapper.Get(entity)
		// Initialize component fields.
		pos.X = rand.Float64() * 100
		pos.Y = rand.Float64() * 100
		vel.X = rand.NormFloat64()
		vel.Y = rand.NormFloat64()
	}

	// Create a generic filter.
	filter := generic.NewFilter2[Position, Velocity]()

	// Time loop.
	for t := 0; t < 1000; t++ {
		// Get a fresh query.
		query := filter.Query(&world)
		// Iterate it
		for query.Next() {
			// Component access through the Query.
			pos, vel := query.Get()
			// Update component fields.
			pos.X += vel.X
			pos.Y += vel.Y
		}
	}
}

Tools

Several tools for Arche are provided in separate modules:

  • arche-serde provides JSON serialization and deserialization for Arche's World.
  • arche-model provides a wrapper around Arche, and some common systems and resources. its purpose is to get started with prototyping and developing simulation models immediately, focussing on the model logic.
  • arche-pixel provides OpenGL graphics and live plots for Arche using the Pixel game engine.
  • arche-demo provides examples of Arche models, which can be viewed in a live demo.

Design

Unlike most other ECS implementations, Arche is designed for the development of scientific, individual-based models rather than for game development. This motivates some design decisions, with an emphasis on simplicity, safety and performance. Nevertheless, Arche can also be used for game development.

Simple core API

The ecs.World object is a pure and simple ECS implementation in the sense of a data store for entities and components, with query and iteration capabilities. More advanced features like batch operations or entity relations are provided through separate objects.

There is neither an update loop nor systems. These should be implemented by the user. For a batteries-included implementation, see module arche-model.

The type-safe generic API and advanced logic filters are provided in the packages generic and filter, respectively. Both packages are built on top of the core ecs package, so they could also be implemented by a user.

Determinism

Iteration order in Arche is deterministic and reproducible. This does not mean that entities are iterated in their order of insertion, nor in the same order in successive iterations. However, given the same operations on the ecs.World, iteration order will always be the same.

Strict and panic

Arche puts an emphasis on safety and on avoiding undefined behavior. It panics on unexpected operations, like removing a dead entity, adding a component that is already present, or attempting to change a locked world. This may not seem idiomatic for Go. However, explicit error handling in performance hot spots is not an option. Neither is silent failure, given the scientific background.

Limitations

  • The number of component types per World is limited to 256. This is mainly a performance decision.
  • The number of entities alive at any one time is limited to just under 5 billion (uint32 ID).

Benchmarks

A tabular overview of the runtime cost of typical Arche ECS operations is provided under benchmarks in the Arche's User Guide.

See also the latest Benchmarks CI run and the go-ecs-benchmarks repository.

Cite as

Lange, M. (2023): Arche – An archetype-based Entity Component System for Go. DOI 10.5281/zenodo.7656484, GitHub repository: https://github.com/mlange-42/arche

License

This project is distributed under the MIT license.