Categorygithub.com/kostayne/ecs/v2
2.1.0
Repository: https://github.com/kostayne/ecs.git
Documentation: pkg.go.dev

# Packages

No description provided by the author
No description provided by the author
No description provided by the author

# README

Kostayne ECS v2

GitHub Tag GitHub License GitHub Actions Workflow Status GitHub top language

This package provides a basic implementation of Entity Component System pattern. ECS separates logic from data, which makes the app more scalable and flexible. It's ideal for complex games or simulations.

Definitions

Entity - a unique object in the world, it has no any logic.

Component - a piece of data that can be attached to an entity.

System - a set of logic that can be applied to the entity.

TOC

Usage

Full example code is here!

To use ECS, you need to define components and systems, then create a main loop.

Define components

First, we'll define a simple component (component.go):

package example

type PositionComponent struct {
	X float64
	Y float64
}

func (c *PositionComponent) Type() string {
	return "position"
}

func MakePositionComponent(x, y float64) *PositionComponent {
	return &PositionComponent{
		X: x,
		Y: y,
	}
}

Define systems

Next, we'll define a simple system (system.go):

package example

import (
	"time"

	"github.com/kostayne/ecs/v2/core"
)

// Use SystemBase to reduce boilerplate
type MovementSystem struct {
	core.SystemBase
}

// Main logic
func (s *MovementSystem) Process(es *core.EntityStore, dt time.Duration) {
	finder := core.MakeFinder(es)
	entities := finder.Has("position").GetMany()

	for _, e := range entities {
		pos := (*e.Get("position")).(*PositionComponent)

		pos.X += 1
		pos.Y += 2
	}
}

func MakeMovementSystem() *MovementSystem {
	return &MovementSystem{
		// Define system params here
		SystemBase: *core.MakeSystemBase("sys_movement", 0, 0),
	}
}

The code above reduces boilerplate with the SystemBase struct, here is a more explicit version without it.

Start the app

Finally, we'll start the app (app.go):

package example

import (
	"fmt"

	"github.com/kostayne/ecs/v2/core"
)

func main() {
	ecs := core.MakeECS()

	// create component & system instances
	moveSys := MakeMovementSystem()
	posComp := MakePositionComponent(0, 0)

	// add them to ecs
	player := ecs.EntityStore.New(posComp)
	ecs.SystemStore.Add(moveSys)

	ecs.Setup()

	// run the main loop
	for i := 0; i < 5; i++ {
		ecs.Process()
		fmt.Printf("XY: (%v, %v)\n", posComp.X, posComp.Y)
	}

	ecs.Cleanup()
}

Wiki

To find out more, see the documentation.

ECS

ECS is a core data structure that holds all entities and their components.

type ECS struct {
	EntityStore EntityStore
	SystemStore SystemStore
}

EntityStore

Use entity store to manage entities.

Manage entities

entity := ecs.EntityStore.New()
ecs.EntityStore.Get(entity.Id())
ecs.EntityStore.Remove(entity.Id())
ecs.EntityStore.GetAll(entity.Id())

Manage components

ecs.EntityStore.GetById(entity.Id())
ecs.EntityStore.AddTo(entity.Id(), MakePositionComponent(0, 0))
ecs.EntityStore.RemoveFrom(entity.Id(), "position")

Finder

Finder is a helper that allows to find entities by components or arbitrary criteria.

--- Finder Interface ---

type FinderI interface {
	Get() Entity
	GetMany() []Entity
	Has(components ...string) FinderI
	Where(predicate func(Entity) bool) FinderI
}

--- Finder Constructor ---

ecs := core.MakeECS()

finder := core.MakeFinder(&ecs.SystemStore)

--- Finder Methods ---

Finder.Has(components ...string) FinderI

Returns a finder with entities that have provided components.

entities := finder.Has("position", "velocity").GetMany()

Finder.Where(predicate func(Entity) bool) FinderI

Returns a finder with entities that match provided predicate.

func isEntityOnTheRight(e *Entity) bool {
	pos := (*e.GetOne("position")).(*PositionComponent)
	return pos.X > 0
}

entities := finder.Where(isEntityOnTheRight).GetMany()

Finder.GetOne() *Entity

Returns a single matched entity.

player := finder.Has("character_controller").GetOne()

Finder.GetMany() []Entity

Returns a list of matched entities.

weapons := finder.Has("weapon").GetMany()