Documentation
¶
Overview ¶
Package goecs provides a Go implementation of an Entity–component–system (ECS)
Entity–component–system (ECS) is an architectural patter that follows the composition over inheritance principle that allows greater flexibility in defining entities where every object in a world.
Every entity consists of one or more components which contains data or state. Therefore, the behavior of an entity can be changed at runtime by systems that add, remove or mutate components.
This eliminates the ambiguity problems of deep and wide inheritance hierarchies that are difficult to understand, maintain and extend.
Common ECS approaches are highly compatible and often combined with data-oriented design techniques.
See: World, Entity
Example ¶
Simple Usage
/* * Copyright (c) 2020 Juan Medina. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package main import ( "fmt" "github.com/juan-medina/goecs" ) // Simple Usage func main() { // creates the world world := goecs.Default() // add our movement system world.AddSystem(MovementSystem) // add a listener world.AddListener(ChangePostListener, PosChangeSignalType) // add a first entity world.AddEntity( Pos{X: 0, Y: 0}, Vel{X: 2, Y: 2}, ) // this entity shouldn't be updated world.AddEntity( Pos{X: 6, Y: 6}, ) // add a third entity world.AddEntity( Pos{X: 8, Y: 8}, Vel{X: 4, Y: 4}, ) // print the world PrintWorld(world) fmt.Println() fmt.Println("updating world for halve a second:") // ask the world to update if err := world.Update(0.5); err != nil { fmt.Printf("error on update %v\n", err) } // print the world fmt.Println() PrintWorld(world) } // PrintWorld prints the content of our world func PrintWorld(world *goecs.World) { fmt.Println("World:") for it := world.Iterator(); it != nil; it = it.Next() { ent := it.Value() id := ent.ID() pos := ent.Get(PosType).(Pos) if ent.Contains(VelType) { vel := ent.Get(VelType).(Vel) fmt.Printf("Id: %d, Pos: %v, Vel: %v/s\n", id, pos, vel) } else { fmt.Printf("Id: %d, Pos: %v\n", id, pos) } } } // MovementSystem is a simple movement system func MovementSystem(world *goecs.World, delta float32) error { // get all the entities that we need to update, only if they have Pos & Vel for it := world.Iterator(PosType, VelType); it != nil; it = it.Next() { // get the values ent := it.Value() pos := ent.Get(PosType).(Pos) vel := ent.Get(VelType).(Vel) // calculate new pos npos := Pos{ X: pos.X + vel.X*delta, Y: pos.Y + vel.Y*delta, } // set the new pos ent.Set(npos) // signal the change world.Signal(PosChangeSignal{ID: ent.ID(), From: pos, To: npos}) } return nil } // ChangePostListener listen to PosChangeSignal func ChangePostListener(world *goecs.World, signal goecs.Component, delta float32) error { switch s := signal.(type) { case PosChangeSignal: // print the change fmt.Printf("pos change for id: %d, from Pos%v to Pos%v\n", s.ID, s.From, s.To) } return nil } // PosType is the ComponentType of Pos var PosType = goecs.NewComponentType() // Pos represent a 2D position type Pos struct { X float32 Y float32 } // Type will return Pos goecs.ComponentType func (p Pos) Type() goecs.ComponentType { return PosType } // VelType is the ComponentType of Vel var VelType = goecs.NewComponentType() // Vel represent a 2D velocity type Vel struct { X float32 Y float32 } // Type will return Vel goecs.ComponentType func (v Vel) Type() goecs.ComponentType { return VelType } // PosChangeSignalType is the type of the PosChangeSignal var PosChangeSignalType = goecs.NewComponentType() // PosChangeSignal is a signal that a Pos has change type PosChangeSignal struct { ID goecs.EntityID From Pos To Pos } // Type will return PosChangeSignal goecs.ComponentType func (p PosChangeSignal) Type() goecs.ComponentType { return PosChangeSignalType }
Output: World: Id: 1, Pos: {0 0}, Vel: {2 2}/s Id: 2, Pos: {6 6} Id: 3, Pos: {8 8}, Vel: {4 4}/s updating world for halve a second: pos change for id: 1, from Pos{0 0} to Pos{1 1} pos change for id: 3, from Pos{8 8} to Pos{10 10} World: Id: 1, Pos: {1 1}, Vel: {2 2}/s Id: 2, Pos: {6 6} Id: 3, Pos: {10 10}, Vel: {4 4}/s
Index ¶
- Constants
- Variables
- type Component
- type ComponentType
- type Entity
- func (ent *Entity) Add(component Component) *Entity
- func (ent *Entity) Clear()
- func (ent Entity) Contains(types ...ComponentType) bool
- func (ent Entity) Get(ctype ComponentType) Component
- func (ent Entity) ID() EntityID
- func (ent Entity) IsEmpty() bool
- func (ent Entity) NotContains(types ...ComponentType) bool
- func (ent *Entity) Remove(ctype ComponentType)
- func (ent *Entity) Reuse(id EntityID, components ...Component)
- func (ent *Entity) Set(component Component) *Entity
- func (ent Entity) String() string
- type EntityID
- type Iterator
- type Listener
- type Subscriptions
- type System
- type Systems
- type View
- func (v *View) AddEntity(data ...Component) EntityID
- func (v *View) Clear()
- func (v *View) First(components ...ComponentType) (EntityID, error)
- func (v *View) Get(id EntityID) *Entity
- func (v *View) Iterator(types ...ComponentType) *Iterator
- func (v *View) Remove(id EntityID) error
- func (v View) Size() int
- func (v *View) Sort(less func(a, b *Entity) bool)
- func (v View) String() string
- type World
- func (world *World) AddListener(lis Listener, signals ...ComponentType)
- func (world *World) AddListenerWithPriority(lis Listener, priority int32, signals ...ComponentType)
- func (world *World) AddResource(components ...Component) EntityID
- func (world *World) AddSystem(sys System)
- func (world *World) AddSystemWithPriority(sys System, priority int32)
- func (world *World) Clear()
- func (world World) FindResource(components ...ComponentType) EntityID
- func (world World) GetResource(id EntityID) *Entity
- func (world World) RemoveResource(id EntityID) error
- func (world *World) Signal(signal interface{})
- func (world World) String() string
- func (world *World) Update(delta float32) error
Examples ¶
Constants ¶
const ( DefaultSignalsInitialCapacity = 20 // Default Signals initial capacity DefaultSystemsInitialCapacity = 50 // Default System initial capacity DefaultListenersInitialCapacity = 50 // Default Listener initial capacity DefaultEntitiesInitialCapacity = 2000 // Default Entity initial capacity DefaultResourcesInitialCapacity = 20 // Default Resources initial capacity )
Default values for Default()
Variables ¶
var ( // ErrEntityNotFound is the error when we could not find an viewItem ErrEntityNotFound = errors.New("entity not found") )
Functions ¶
This section is empty.
Types ¶
type Component ¶ added in v1.5.0
type Component interface {
Type() ComponentType
}
Component represent a Entity component
type ComponentType ¶ added in v1.5.0
type ComponentType uint64
ComponentType represents the type of a Component
func NewComponentType ¶ added in v1.5.0
func NewComponentType() ComponentType
NewComponentType return a new component type
type Entity ¶
type Entity struct {
// contains filtered or unexported fields
}
Entity represents a instance of an object in a ECS
func (Entity) Contains ¶
func (ent Entity) Contains(types ...ComponentType) bool
Contains check that the Entity has the given varg ComponentType
func (Entity) Get ¶
func (ent Entity) Get(ctype ComponentType) Component
Get the component of the given ComponentType
func (Entity) NotContains ¶
func (ent Entity) NotContains(types ...ComponentType) bool
NotContains check that the Entity has not the given varg ComponentType
func (*Entity) Remove ¶
func (ent *Entity) Remove(ctype ComponentType)
Remove the component of the given ComponentType
type Iterator ¶
type Iterator struct {
// contains filtered or unexported fields
}
Iterator allow to iterate trough the View
type Subscriptions ¶ added in v1.4.0
type Subscriptions struct {
// contains filtered or unexported fields
}
Subscriptions manage subscriptions of Listeners to signals
func NewSubscriptions ¶ added in v1.4.0
func NewSubscriptions(listeners, signals int) *Subscriptions
NewSubscriptions creates a new Subscriptions
func (*Subscriptions) Clear ¶ added in v1.4.0
func (subs *Subscriptions) Clear()
Clear the subscriptions & signals
func (*Subscriptions) Signal ¶ added in v1.4.0
func (subs *Subscriptions) Signal(signal interface{})
Signal adds a signal to to be sent
func (Subscriptions) String ¶ added in v1.4.0
func (subs Subscriptions) String() string
String returns the string representation of the subscriptions
func (*Subscriptions) Subscribe ¶ added in v1.4.0
func (subs *Subscriptions) Subscribe(listener Listener, priority int32, signals ...ComponentType)
Subscribe adds a new subscription given a priority and set of signals types
type Systems ¶ added in v1.4.0
type Systems struct {
// contains filtered or unexported fields
}
Systems manage registration of systems
func NewSystems ¶ added in v1.4.0
NewSystems creates a new Systems
type View ¶
type View struct {
// contains filtered or unexported fields
}
View represent a set of Entity objects
func (*View) First ¶ added in v1.5.1
func (v *View) First(components ...ComponentType) (EntityID, error)
First return the first EntityID that match the given ComponentType
func (*View) Iterator ¶
func (v *View) Iterator(types ...ComponentType) *Iterator
Iterator return an view.Iterator for the given varg ComponentType
type World ¶
type World struct { *View // contains filtered or unexported fields }
World is a view.View that contains the Entity and System of our ECS
func Default ¶ added in v1.3.1
func Default() *World
Default creates a default World with a initial capacity
const ( DefaultSignalsInitialCapacity = 20 // Default Signals initial capacity DefaultSystemsInitialCapacity = 50 // Default System initial capacity DefaultListenersInitialCapacity = 50 // Default Listener initial capacity DefaultEntitiesInitialCapacity = 2000 // Default Entity initial capacity )
func New ¶
New creates World with a giving initial capacity of entities, systems, listeners and signals
Since those elements are sparse.Slice the will grow dynamically
func (*World) AddListener ¶
func (world *World) AddListener(lis Listener, signals ...ComponentType)
AddListener adds the given Listener to the world
func (*World) AddListenerWithPriority ¶
func (world *World) AddListenerWithPriority(lis Listener, priority int32, signals ...ComponentType)
AddListenerWithPriority adds the given Listener to the world with a priority
func (*World) AddResource ¶ added in v1.5.1
AddResource create a new resource and add it to the world resources a global entities with a single instance that are no return by the Iterator for example things like a game score
func (*World) AddSystemWithPriority ¶
AddSystemWithPriority adds the given System to the world with a priority
func (*World) Clear ¶
func (world *World) Clear()
Clear removes all System, Listener, Subscriptions, Entity and Resources from the World
func (World) FindResource ¶ added in v1.5.1
func (world World) FindResource(components ...ComponentType) EntityID
FindResource find a resource in the world that match the given ComponentType
func (World) GetResource ¶ added in v1.5.1
GetResource gets a resource from the world
func (World) RemoveResource ¶ added in v1.5.2
RemoveResource removes a resource from the world
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package sparse provides the creation of sparse.Slice via sparse.NewSlice Sparse items are design to automatically grow and reuse memory so they try to minimize the GC pauses
|
Package sparse provides the creation of sparse.Slice via sparse.NewSlice Sparse items are design to automatically grow and reuse memory so they try to minimize the GC pauses |