Documentation ¶
Overview ¶
Package ecs contains Arche's core API.
See the top-level module github.com/mlange-42/arche for an overview.
🕮 Also read Arche's User Guide!
Outline ¶
- World provides most of the basic functionality, like World.Query, World.NewEntity, World.Add, World.Remove, World.RemoveEntity, etc.
- Relations provide access to and manipulation of entity relations, like Relations.Get and Relations.Set.
- Builder provides advanced entity creation and batched creation with Builder.NewBatch and Builder.NewBatchQ.
- Batch provides batch-manipulation of entities, like Batch.Add, Batch.Remove and Batch.SetRelation.
- Cache serves for registering and un-registering cached filters with Cache.Register and Cache.Unregister.
- Resources provide a storage for global resources, with functionality like Resources.Get, Resources.Add and Resources.Remove.
- Listener provides EntityEvent notifications for ECS operations.
- Useful functions: All, ComponentID, ResourceID, GetResource, AddResource.
Sub-packages ¶
- github.com/mlange-42/arche/ecs/event provides event subscription masks.
- github.com/mlange-42/arche/ecs/stats provides world statistics for monitoring purposes.
ECS Manipulations ¶
This section gives an overview on how to achieve typical ECS manipulation operations with Arche.
Simple manipulations of a single entity:
- Create an entity: World.NewEntity, World.NewEntityFn
- Remove an entity: World.RemoveEntity
- Add components: World.Add, World.AddFn
- Remove components: World.Remove
- Exchange components: World.Exchange, World.ExchangeFn
- Change entity relation target: Relations.Set
Manipulations of a single entity, with a relation target:
- Create an entity: Builder.New
- Add components: Builder.Add, Relations.Exchange
- Remove components: Relations.Exchange
- Exchange components: Relations.Exchange
Batch-manipulations of many entities:
- Create entities: Builder.NewBatch, Builder.NewBatchQ
- Remove entities: Batch.RemoveEntities
- Add components: Batch.Add, Batch.AddQ
- Remove components: Batch.Remove, Batch.RemoveQ
- Exchange components: Batch.Exchange
- Change entity relation target: Batch.SetRelation, Batch.SetRelationQ
Batch-manipulations of many entities, with a relation target:
- Create an entity: Builder.NewBatch, Builder.NewBatchQ
- Add components: Relations.ExchangeBatch, Relations.ExchangeBatchQ
- Remove components: Relations.ExchangeBatch, Relations.ExchangeBatchQ
- Exchange components: Relations.ExchangeBatch, Relations.ExchangeBatchQ
Build tags ¶
Arche provides two build tags:
- tiny -- Reduces the maximum number of components to 64, giving a performance boost for mask-related operations.
- debug -- Improves error messages on Query misuse, at the cost of performance. Use this if you get panics from queries.
When building your application, use them like this:
go build -tags tiny . go build -tags debug . go build -tags tiny,debug .
Index ¶
- Constants
- func GetResource[T any](w *World) *T
- func ResourceType(w *World, id ResID) (reflect.Type, bool)
- type Batch
- func (b *Batch) Add(filter Filter, comps ...ID) int
- func (b *Batch) AddQ(filter Filter, comps ...ID) Query
- func (b *Batch) Exchange(filter Filter, add []ID, rem []ID) int
- func (b *Batch) ExchangeQ(filter Filter, add []ID, rem []ID) Query
- func (b *Batch) Remove(filter Filter, comps ...ID) int
- func (b *Batch) RemoveEntities(filter Filter) int
- func (b *Batch) RemoveQ(filter Filter, comps ...ID) Query
- func (b *Batch) SetRelation(filter Filter, comp ID, target Entity) int
- func (b *Batch) SetRelationQ(filter Filter, comp ID, target Entity) Query
- type Builder
- type Cache
- type CachedFilter
- type CompInfo
- type Component
- type Config
- type Entity
- type EntityDump
- type EntityEvent
- type Filter
- type ID
- type Listener
- type Mask
- func (b *Mask) And(other *Mask) Mask
- func (b *Mask) Contains(other *Mask) bool
- func (b *Mask) ContainsAny(other *Mask) bool
- func (b Mask) Exclusive() MaskFilter
- func (b *Mask) Get(bit ID) bool
- func (b *Mask) IsZero() bool
- func (b Mask) Matches(bits *Mask) bool
- func (b *Mask) Not() Mask
- func (b *Mask) Or(other *Mask) Mask
- func (b *Mask) Reset()
- func (b *Mask) Set(bit ID, value bool)
- func (b *Mask) TotalBitsSet() int
- func (b Mask) Without(comps ...ID) MaskFilter
- func (b *Mask) Xor(other *Mask) Mask
- type MaskFilter
- type Query
- func (q *Query) Close()
- func (q *Query) Count() int
- func (q *Query) Entity() Entity
- func (q *Query) EntityAt(index int) Entity
- func (q *Query) Get(comp ID) unsafe.Pointer
- func (q *Query) Has(comp ID) bool
- func (q *Query) Ids() []ID
- func (q *Query) Mask() Mask
- func (q *Query) Next() bool
- func (q *Query) Relation(comp ID) Entity
- func (q *Query) Step(step int) bool
- type Relation
- type RelationFilter
- type Relations
- func (r *Relations) Exchange(entity Entity, add []ID, rem []ID, relation ID, target Entity)
- func (r *Relations) ExchangeBatch(filter Filter, add []ID, rem []ID, relation ID, target Entity) int
- func (r *Relations) ExchangeBatchQ(filter Filter, add []ID, rem []ID, relation ID, target Entity) Query
- func (r *Relations) Get(entity Entity, comp ID) Entity
- func (r *Relations) GetUnchecked(entity Entity, comp ID) Entity
- func (r *Relations) Set(entity Entity, comp ID, target Entity)
- func (r *Relations) SetBatch(filter Filter, comp ID, target Entity) int
- func (r *Relations) SetBatchQ(filter Filter, comp ID, target Entity) Query
- type ResID
- type Resources
- type World
- func (w *World) Add(entity Entity, comps ...ID)
- func (w *World) AddFn(entity Entity, fn func(Entity), comps ...ID)
- func (w *World) Alive(entity Entity) bool
- func (w *World) Assign(entity Entity, comps ...Component)deprecated
- func (w *World) Batch() *Batch
- func (w *World) Cache() *Cache
- func (w *World) DumpEntities() EntityDump
- func (w *World) Exchange(entity Entity, add []ID, rem []ID)
- func (w *World) ExchangeFn(entity Entity, add []ID, rem []ID, fn func(Entity))
- func (w *World) Get(entity Entity, comp ID) unsafe.Pointer
- func (w *World) GetUnchecked(entity Entity, comp ID) unsafe.Pointer
- func (w *World) Has(entity Entity, comp ID) bool
- func (w *World) HasUnchecked(entity Entity, comp ID) bool
- func (w *World) Ids(entity Entity) []ID
- func (w *World) IsLocked() bool
- func (w *World) LoadEntities(data *EntityDump)
- func (w *World) Mask(entity Entity) Mask
- func (w *World) NewEntity(comps ...ID) Entity
- func (w *World) NewEntityFn(fn func(e Entity), comps ...ID) Entity
- func (w *World) NewEntityWith(comps ...Component) Entitydeprecated
- func (w *World) Query(filter Filter) Query
- func (w *World) Relations() *Relations
- func (w *World) Remove(entity Entity, comps ...ID)
- func (w *World) RemoveEntity(entity Entity)
- func (w *World) Reset()
- func (w *World) Resources() *Resources
- func (w *World) Set(entity Entity, id ID, comp interface{}) unsafe.Pointerdeprecated
- func (w *World) SetListener(listener Listener)
- func (w *World) Stats() *stats.World
Examples ¶
- AddResource
- Batch
- Batch.Add
- Batch.AddQ
- Batch.Exchange
- Batch.ExchangeQ
- Batch.Remove
- Batch.RemoveEntities
- Batch.RemoveQ
- Batch.SetRelation
- Batch.SetRelationQ
- Builder
- Builder.Add
- Builder.New
- Builder.NewBatch
- Builder.NewBatchQ
- Builder.WithRelation
- Cache
- CachedFilter
- ComponentID
- Config
- Entity
- Entity.IsZero
- EntityEvent
- EntityEvent.Contains
- GetResource
- Mask
- Mask.Exclusive
- Mask.Without
- MaskFilter
- NewBuilder
- NewBuilderWith
- NewWorld
- Query
- Query.Close
- Query.Count
- Query.EntityAt
- Relation
- RelationFilter
- Relations
- Relations.SetBatch
- Relations.SetBatchQ
- ResourceID
- Resources
- TypeID
- World
- World.Add
- World.Alive
- World.Assign
- World.Batch
- World.Cache
- World.Exchange
- World.Get
- World.Has
- World.Mask
- World.NewEntity
- World.NewEntityWith
- World.Query
- World.Relations
- World.Remove
- World.RemoveEntity
- World.Reset
- World.Resources
- World.Set
- World.SetListener
- World.Stats
Constants ¶
const MaskTotalBits = 256
MaskTotalBits is the size of a Mask in bits. It is the maximum number of component types that may exist in any World.
Use build tag `tiny` to reduce all masks to 64 bits.
Variables ¶
This section is empty.
Functions ¶
func GetResource ¶ added in v0.5.0
GetResource returns a pointer to the given resource type in the world. Returns nil if there is no such resource.
Uses reflection. For more efficient access, see World.Resources, and github.com/mlange-42/arche/generic.Resource.Get for a generic variant. These methods are more than 20 times faster than the GetResource function.
See also AddResource.
Example ¶
world := ecs.NewWorld() myRes := Position{100, 100} ecs.AddResource(&world, &myRes) res := ecs.GetResource[Position](&world) fmt.Println(res)
Output: &{100 100}
Types ¶
type Batch ¶ added in v0.6.0
type Batch struct {
// contains filtered or unexported fields
}
Batch is a helper to perform batched operations on the world.
Create using World.Batch.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) builder.NewBatch(100) world.Batch().Remove(ecs.All(posID, velID), velID) world.Batch().RemoveEntities(ecs.All(posID))
Output:
func (*Batch) Add ¶ added in v0.8.0
Add adds components to many entities, matching a filter. Returns the number of affected entities.
Panics:
- when called with components that can't be added because they are already present.
- when called on a locked world. Do not use during Query iteration!
See also Batch.AddQ and World.Add.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) filter := ecs.All(posID) world.Batch().Add(filter, velID)
Output:
func (*Batch) AddQ ¶ added in v0.8.0
AddQ adds components to many entities, matching a filter. It returns a query over the affected entities.
Panics:
- when called with components that can't be added because they are already present.
- when called on a locked world. Do not use during Query iteration!
See also Batch.Add and World.Add.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) filter := ecs.All(posID) query := world.Batch().AddQ(filter, velID) for query.Next() { pos := (*Position)(query.Get(posID)) pos.X = 100 }
Output:
func (*Batch) Exchange ¶ added in v0.8.0
Exchange exchanges components for many entities, matching a filter. Returns the number of affected entities.
When a Relation component is removed and another one is added, the target entity of the relation is reset to zero.
Panics:
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called on a locked world. Do not use during Query iteration!
See also Batch.ExchangeQ and World.Exchange. For batch-exchange with a relation target, see Relations.ExchangeBatch.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) filter := ecs.All(posID) world.Batch().Exchange( filter, // Filter []ecs.ID{velID}, // Add components []ecs.ID{posID}, // Remove components )
Output:
func (*Batch) ExchangeQ ¶ added in v0.8.0
ExchangeQ exchanges components for many entities, matching a filter. It returns a query over the affected entities.
When a Relation component is removed and another one is added, the target entity of the relation is reset to zero.
Panics:
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called on a locked world. Do not use during Query iteration!
See also Batch.Exchange and World.Exchange. For batch-exchange with a relation target, see Relations.ExchangeBatchQ.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) filter := ecs.All(posID) query := world.Batch().ExchangeQ( filter, // Filter []ecs.ID{velID}, // Add components []ecs.ID{posID}, // Remove components ) for query.Next() { vel := (*Velocity)(query.Get(velID)) vel.X = 100 }
Output:
func (*Batch) Remove ¶ added in v0.8.0
Remove removes components from many entities, matching a filter. Returns the number of affected entities.
Panics:
- when called with components that can't be removed because they are not present.
- when called on a locked world. Do not use during Query iteration!
See also Batch.RemoveQ and World.Remove.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) builder.NewBatch(100) filter := ecs.All(posID, velID) world.Batch().Remove(filter, velID)
Output:
func (*Batch) RemoveEntities ¶ added in v0.6.0
RemoveEntities removes and recycles all entities matching a filter. Returns the number of removed entities.
Panics when called on a locked world. Do not use during Query iteration!
Unlike with the other batch operations, it is not easily possible to provide a query version RemoveEntitiesQ. However, one can simply query with the same filter before calling RemoveEntities.
See also World.RemoveEntity
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) filter := ecs.All(posID) world.Batch().RemoveEntities(filter)
Output:
func (*Batch) RemoveQ ¶ added in v0.8.0
RemoveQ removes components from many entities, matching a filter. It returns a query over the affected entities.
Panics:
- when called with components that can't be removed because they are not present.
- when called on a locked world. Do not use during Query iteration!
See also Batch.Remove and World.Remove.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) builder.NewBatch(100) filter := ecs.All(posID, velID) query := world.Batch().RemoveQ(filter, velID) for query.Next() { pos := (*Position)(query.Get(posID)) pos.X = 100 }
Output:
func (*Batch) SetRelation ¶ added in v0.8.0
SetRelation sets the Relation target for many entities, matching a filter. Returns the number of affected entities.
Entities that match the filter but already have the desired target entity are not processed, and no events are emitted for them.
Panics:
- when called for a missing component.
- when called for a component that is not a relation.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Set and Relations.SetBatch.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) childID := ecs.ComponentID[ChildOf](&world) target := world.NewEntity() builder := ecs.NewBuilder(&world, posID, childID) builder.NewBatch(100) filter := ecs.All(childID) world.Batch().SetRelation(filter, childID, target)
Output:
func (*Batch) SetRelationQ ¶ added in v0.8.0
SetRelationQ sets the Relation target for many entities, matching a filter. It returns a query over the affected entities.
Entities that match the filter but already have the desired target entity are not processed, not included in the query, and no events are emitted for them.
Panics:
- when called for a missing component.
- when called for a component that is not a relation.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Set and Relations.SetBatch.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) childID := ecs.ComponentID[ChildOf](&world) target := world.NewEntity() builder := ecs.NewBuilder(&world, posID, childID) builder.NewBatch(100) filter := ecs.All(childID) query := world.Batch().SetRelationQ(filter, childID, target) for query.Next() { pos := (*Position)(query.Get(posID)) pos.X = 100 }
Output:
type Builder ¶ added in v0.8.0
type Builder struct {
// contains filtered or unexported fields
}
Builder for more flexible and batched entity creation.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) _ = builder.New()
Output:
func NewBuilder ¶ added in v0.8.0
NewBuilder creates a builder from component IDs.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) _ = builder.New()
Output:
func NewBuilderWith
deprecated
added in
v0.8.0
NewBuilderWith creates a builder from component pointers.
Deprecated: This method is slow. Instead, use NewWith of the generic API under github.com/mlange-42/arche/generic.Map1, etc. This function may be removed in a future version.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) components := []ecs.Component{ {ID: posID, Comp: &Position{X: 0, Y: 0}}, {ID: velID, Comp: &Velocity{X: 10, Y: 2}}, } builder := ecs.NewBuilderWith(&world, components...) _ = builder.New()
Output:
func (*Builder) Add ¶ added in v0.8.0
Add the builder's components to an entity.
The optional argument can be used to set the target Entity for the Builder's Relation. See Builder.WithRelation.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) entity := world.NewEntity() builder.Add(entity)
Output:
func (*Builder) New ¶ added in v0.8.0
New creates an entity.
The optional argument can be used to set the target Entity for the Builder's Relation. See Builder.WithRelation.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) _ = builder.New()
Output:
func (*Builder) NewBatch ¶ added in v0.8.0
NewBatch creates many entities.
The optional argument can be used to set the target Entity for the Builder's Relation. See Builder.WithRelation.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) builder.NewBatch(1000)
Output:
func (*Builder) NewBatchQ ¶ added in v0.8.0
NewBatchQ creates many entities and returns a query over them.
The optional argument can be used to set the target Entity for the Builder's Relation. See Builder.WithRelation.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) builder := ecs.NewBuilder(&world, posID, velID) query := builder.NewBatchQ(1000) for query.Next() { // initialize components of the newly created entities }
Output:
func (*Builder) WithRelation ¶ added in v0.8.0
WithRelation sets the Relation component for the builder.
Use in conjunction with the optional target argument of Builder.New, Builder.NewBatch and Builder.NewBatchQ.
See Relation for details and examples.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) childID := ecs.ComponentID[ChildOf](&world) target := world.NewEntity() builder := ecs.NewBuilder(&world, posID, childID). WithRelation(childID) builder.New(target)
Output:
type Cache ¶ added in v0.6.0
type Cache struct {
// contains filtered or unexported fields
}
Cache provides Filter caching to speed up queries.
Access it using World.Cache.
For registered filters, the relevant archetypes are tracked internally, so that there are no mask checks required during iteration. This is particularly helpful to avoid query iteration slowdown by a very high number of archetypes. If the number of archetypes exceeds approx. 50-100, uncached filters experience a slowdown. The relative slowdown increases with lower numbers of entities queried (noticeable below a few thousand entities). Cached filters avoid this slowdown.
The overhead of tracking cached filters internally is very low, as updates are required only when new archetypes are created.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) filter := All(posID) cached := world.Cache().Register(filter) query := world.Query(&cached) for query.Next() { // ... }
Output:
func (*Cache) Register ¶ added in v0.6.0
func (c *Cache) Register(f Filter) CachedFilter
Register a Filter.
Use the returned CachedFilter to construct queries:
filter := All(posID, velID) cached := world.Cache().Register(&filter) query := world.Query(&cached)
func (*Cache) Unregister ¶ added in v0.6.0
func (c *Cache) Unregister(f *CachedFilter) Filter
Unregister a filter.
Returns the original filter.
type CachedFilter ¶ added in v0.6.0
type CachedFilter struct {
// contains filtered or unexported fields
}
CachedFilter is a filter that is cached by the world.
Create a cached filter from any other filter using Cache.Register. For details on caching, see Cache.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) filter := All(posID) cached := world.Cache().Register(filter) query := world.Query(&cached) for query.Next() { // ... }
Output:
func (*CachedFilter) Matches ¶ added in v0.6.0
func (f *CachedFilter) Matches(bits *Mask) bool
Matches the filter against a mask.
type CompInfo ¶ added in v0.10.0
CompInfo provides information about a registered component. Returned by ComponentInfo.
type Component ¶ added in v0.2.0
type Component struct { ID ID // Component ID. Comp interface{} // The component, as a pointer to a struct. }
Component is a component ID/pointer pair.
It is a helper for World.Assign, World.NewEntityWith and NewBuilderWith. It is not related to how components are implemented in Arche.
type Config ¶ added in v0.1.3
type Config struct { // Capacity increment for archetypes and the entity index. // The default value is 128. CapacityIncrement int // Capacity increment for archetypes with a relation component. // The default value is CapacityIncrement. RelationCapacityIncrement int }
Config provides configuration for an ECS World.
Example ¶
package main import ( "github.com/mlange-42/arche/ecs" ) func main() { config := ecs.NewConfig(). WithCapacityIncrement(1024). // Optionally set capacity increment WithRelationCapacityIncrement(128) // Optionally set capacity increment for relations world := ecs.NewWorld(config) world.NewEntity() }
Output:
func NewConfig ¶ added in v0.1.3
func NewConfig() Config
NewConfig creates a new default World configuration.
func (Config) WithCapacityIncrement ¶ added in v0.1.3
WithCapacityIncrement return a new Config with CapacityIncrement set. Use with method chaining.
func (Config) WithRelationCapacityIncrement ¶ added in v0.8.0
WithRelationCapacityIncrement return a new Config with RelationCapacityIncrement set. Use with method chaining.
type Entity ¶
type Entity struct {
// contains filtered or unexported fields
}
Entity identifier. Holds an entity ID and its generation for recycling.
Entities are only created via the World, using World.NewEntity or World.NewEntityWith. Batch creation of entities is possible via Builder.
⚠️ Important: Entities are intended to be stored and passed around via copy, not via pointers! The zero value should be used to indicate "nil", and can be checked with Entity.IsZero.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) velID := ComponentID[Velocity](&world) e1 := world.NewEntity() e2 := world.NewEntity(posID, velID) fmt.Println(e1.IsZero(), e2.IsZero())
Output: false false
func (Entity) Generation ¶ added in v0.12.0
Generation returns the entity's generation.
func (Entity) IsZero ¶ added in v0.1.1
IsZero returns whether this entity is the reserved zero entity.
Example ¶
world := NewWorld() var e1 Entity var e2 Entity = world.NewEntity() fmt.Println(e1.IsZero(), e2.IsZero())
Output: true false
func (Entity) MarshalJSON ¶ added in v0.10.0
MarshalJSON returns a JSON representation of the entity, for serialization purposes.
The JSON representation of an entity is a two-element array of entity ID and generation.
func (*Entity) UnmarshalJSON ¶ added in v0.10.0
UnmarshalJSON into an entity.
For serialization purposes only. Do not use this to create entities!
type EntityDump ¶ added in v0.10.0
type EntityDump struct { Entities []Entity // Entities in the World's entity pool. Alive []uint32 // IDs of all alive entities in query iteration order. Next uint32 // The next free entity of the World's entity pool. Available uint32 // The number of allocated and available entities in the World's entity pool. }
EntityDump is a dump of the entire entity data of the world.
See World.DumpEntities and World.LoadEntities.
type EntityEvent ¶ added in v0.4.0
type EntityEvent struct {
OldRelation, NewRelation *ID // Old and new relation component ID. No relation is indicated by nil.
AddedIDs, RemovedIDs []ID // Components added and removed. DO NOT MODIFY! Get the current components with [World.Ids].
Added, Removed Mask // Masks indicating changed components (additions and removals).
Entity Entity // The entity that was changed.
OldTarget Entity // Old relation target entity. Get the new target with [World.Relations] and [Relations.Get].
EventTypes event.Subscription // Bit mask of event types. See [event.Subscription].
}
EntityEvent contains information about ECS operations like component and relation changes to an Entity.
To receive change events, register a Listener with World.SetListener.
Event types & subscriptions ¶
Events notified are entity creation and removal, component addition and removal, and change of relations and their targets.
Event types that are subscribed are determined by Listener.Subscriptions. Events that cover multiple types (e.g. entity creation and component addition) are only notified once. Field EventTypes contains the event.Subscription bits of covered event types.
See sub-package event and the event.Subscription constants for event types and subscription logic.
Event scheduling ¶
Events are emitted immediately after the change is applied.
Except for removed entities, events are always fired when the World is in an unlocked state. Events for removed entities are fired right before removal of the entity, to allow for inspection of its components. Therefore, the World is in a locked state during entity removal events.
Events for batch-creation of entities using a Builder are fired after all entities are created. For batch methods that return a Query, events are fired after the Query is closed (or fully iterated). This allows the World to be in an unlocked state, and notifies after potential entity initialization.
Example ¶
world := ecs.NewWorld() listener := TestListener{ Callback: func(world *ecs.World, evt ecs.EntityEvent) { fmt.Println(evt.Entity) }, } world.SetListener(&listener) world.NewEntity()
Output: {1 0}
func (*EntityEvent) Contains ¶ added in v0.10.0
func (e *EntityEvent) Contains(bit event.Subscription) bool
Contains returns whether the event's types contain the given type/subscription bit.
Example ¶
package main import ( "fmt" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/ecs/event" ) func main() { evt := ecs.EntityEvent{EventTypes: event.EntityCreated | event.EntityRemoved} fmt.Println(evt.Contains(event.EntityRemoved)) fmt.Println(evt.Contains(event.RelationChanged)) }
Output: true false
type Filter ¶ added in v0.4.0
type Filter interface { // Matches the filter against a mask, i.e. a component composition. Matches(bits *Mask) bool }
Filter is the interface for logic filters. Filters are required to query entities using World.Query.
See Mask, MaskFilter anf RelationFilter for basic filters. For type-safe generics queries, see package github.com/mlange-42/arche/generic. For advanced filtering, see package github.com/mlange-42/arche/filter.
type ID ¶
type ID struct {
// contains filtered or unexported fields
}
ID is the component identifier type.
func ComponentID ¶
ComponentID returns the ID for a component type via generics. Registers the type if it is not already registered.
The number of unique component types per World is limited to 256 (MaskTotalBits). (64 with build tag `tiny`).
Panics if called on a locked world and the type is not registered yet.
Note that type aliases are not considered separate component types. Type re-definitions, however, are separate types.
⚠️ Warning: Using IDs that are outside of the range of registered IDs anywhere in World or other places will result in undefined behavior!
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) world.NewEntity(posID)
Output:
func ComponentIDs ¶ added in v0.10.0
ComponentIDs returns a list of all registered component IDs.
func TypeID ¶ added in v0.4.0
TypeID returns the ID for a component type. Registers the type if it is not already registered.
The number of unique component types per World is limited to MaskTotalBits.
Example ¶
world := ecs.NewWorld() posID := ecs.TypeID(&world, reflect.TypeOf(Position{})) world.NewEntity(posID)
Output:
type Listener ¶ added in v0.10.0
type Listener interface { // Notify the listener about a subscribed event. Notify(world *World, evt EntityEvent) // Subscriptions to one or more event types. Subscriptions() event.Subscription // Components the listener subscribes to. Listening to all components indicated by nil. Components() *Mask }
Listener interface for listening to EntityEvent notifications on ECS operations like entity creation and removal, component addition and removal, and relation changes.
A listener can be added to a World with World.SetListener.
Subscriptions ¶
Listeners can subscribe to one or more event types via method Subscriptions. Further, subscriptions can be restricted to one or more components via method Components.
See sub-package event and the event.Subscription constants for event types and subscription logic.
See also ¶
See EntityEvent for more details. See package github.com/mlange-42/arche/listener for Listener implementations.
type Mask ¶
type Mask struct {
// contains filtered or unexported fields
}
Mask is a 256 bit bitmask. It is also a Filter for including certain components.
Use All to create a mask for a list of component IDs. A mask can be further specified using Mask.Without or Mask.Exclusive.
Use build tag `tiny` to reduce all masks to 64 bits.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) velID := ComponentID[Velocity](&world) filter := All(posID, velID) query := world.Query(filter) for query.Next() { // ... }
Output:
func All ¶ added in v0.4.0
All creates a new Mask from a list of IDs. Matches all entities that have the respective components, and potentially further components.
See also Mask.Without and Mask.Exclusive
func (*Mask) ContainsAny ¶ added in v0.4.0
ContainsAny reports if any bit of the other mask is in this mask.
func (Mask) Exclusive ¶ added in v0.6.0
func (b Mask) Exclusive() MaskFilter
Exclusive creates a MaskFilter which filters for exactly the mask's components. Matches only entities that have exactly the given components, and no other.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) velID := ComponentID[Velocity](&world) filter := All(posID, velID).Exclusive() query := world.Query(&filter) for query.Next() { // ... }
Output:
func (*Mask) TotalBitsSet ¶
TotalBitsSet returns how many bits are set in this mask.
func (Mask) Without ¶ added in v0.4.0
func (b Mask) Without(comps ...ID) MaskFilter
Without creates a MaskFilter which filters for including the mask's components, and excludes the components given as arguments.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) velID := ComponentID[Velocity](&world) filter := All(posID).Without(velID) query := world.Query(&filter) for query.Next() { // ... }
Output:
type MaskFilter ¶ added in v0.4.0
type MaskFilter struct { Include Mask // Components to include. Exclude Mask // Components to exclude. }
MaskFilter is a Filter for including and excluding certain components.
See All, Mask.Without and Mask.Exclusive.
Example ¶
world := NewWorld() posID := ComponentID[Position](&world) velID := ComponentID[Velocity](&world) filter := All(posID).Without(velID) query := world.Query(&filter) for query.Next() { // ... }
Output:
func (*MaskFilter) Matches ¶ added in v0.4.0
func (f *MaskFilter) Matches(bits *Mask) bool
Matches the filter against a mask.
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query is an iterator to iterate entities, filtered by a Filter.
Create queries through the World using World.Query. See there for more details.
In case you get error messages like "index out of range [-1]" or "invalid memory address or nil pointer dereference", try running with build tag `debug`.
See also the generic alternatives github.com/mlange-42/arche/generic.Query1, github.com/mlange-42/arche/generic.Query2, etc. For advanced filtering, see package github.com/mlange-42/arche/filter.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) filter := ecs.All(posID, velID) query := world.Query(filter) for query.Next() { pos := (*Position)(query.Get(posID)) vel := (*Velocity)(query.Get(velID)) pos.X += vel.X pos.Y += vel.Y }
Output:
func (*Query) Close ¶ added in v0.1.2
func (q *Query) Close()
Close closes the Query and unlocks the world.
Automatically called when iteration finishes. Needs to be called only if breaking out of the query iteration or not iterating at all.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) world.NewEntity(posID) query := world.Query(ecs.All(posID)) cnt := query.Count() fmt.Println(cnt) query.Close()
Output: 1
func (*Query) Count ¶ added in v0.1.3
Count counts the entities matching this query.
Involves a small overhead of iterating through archetypes when called the first time. However, this is still much faster than manual counting via iteration.
Does not close the query.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) world.NewEntity(posID) query := world.Query(ecs.All(posID)) cnt := query.Count() fmt.Println(cnt) query.Close()
Output: 1
func (*Query) EntityAt ¶ added in v0.11.0
EntityAt returns the entity at a given index.
Do not use this to iterate a query! Use Query.Next instead.
The method is particularly useful for random sampling of entities from a query (see the example). However, performance heavily depends on the number of archetypes in the world and in the query. It is recommended to use a filter which is registered via the World.Cache, This increases performance at least by factor 4.
Some numbers for comparison, with given number of archetypes in the query:
- 1 archetype, filter not registered: ≈ 11ns
- 1 archetype, filter registered: ≈ 3ns
- 10 archetypes, filter not registered: ≈ 50ns
- 10 archetypes, filter registered: ≈ 10ns
The total number of archetypes in the world has no performance impact for registered filters, while for filters that are not registered, it has.
Panics if the index is out of range, as indicated by Query.Count.
Example ¶
// Set up the world. world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) // Create entities. builder := ecs.NewBuilder(&world, posID) builder.NewBatch(100) // Create a random generator. rng := rand.New(rand.NewSource(42)) // Register a filter (optional, but recommended). filter := world.Cache().Register(ecs.All(posID)) // Query some entities. query := world.Query(&filter) // Get the number of entities in the query cnt := query.Count() // Sample some random entities. for i := 0; i < 5; i++ { randomEntity := query.EntityAt(rng.Intn(cnt)) fmt.Println(randomEntity) } // Close the query. query.Close()
Output: {6 0} {88 0} {69 0} {51 0} {24 0}
func (*Query) Ids ¶ added in v0.10.0
Ids returns the component IDs for the archetype of the Entity at the iterator's current position.
Returns a copy of the archetype's component IDs slice, for safety. This means that the result can be manipulated safely, but also that calling the method may incur some significant cost.
func (*Query) Mask ¶ added in v0.4.0
Mask returns the archetype Mask for the Entity at the iterator's current position.
func (*Query) Next ¶
Next proceeds to the next Entity in the Query.
Returns false if no next entity could be found.
func (*Query) Relation ¶ added in v0.8.0
Relation returns the target entity for an entity relation.
Panics if the entity does not have the given component, or if the component is not a Relation.
func (*Query) Step ¶ added in v0.4.4
Step advances the query iterator by the given number of entities. Returns whether the query is still at a valid position. Returning false indicates that the step exceeded the Query's entities. The query is closed in this case.
Query.Step(1) is equivalent to Query.Next(), although probably slower.
type Relation ¶ added in v0.8.0
type Relation struct{}
Relation is a marker for entity relation components. It must be embedded as first field of a component that represent an entity relation (see the example).
Entity relations allow for fast queries using entity relationships. E.g. to iterate over all entities that are the child of a certain parent entity. Currently, each entity can only have a single relation component.
See also RelationFilter, World.Relations, Relations.Get, Relations.Set and Builder.WithRelation.
Example ¶
package main import ( "fmt" "github.com/mlange-42/arche/ecs" ) // ChildOf demonstrates how to define a relation component. // There may be more fields _after_ the embed. type ChildOf struct { ecs.Relation } func main() { world := ecs.NewWorld() childID := ecs.ComponentID[ChildOf](&world) // Create a target/parent entity for the relation. parent := world.NewEntity() // Create a builder with a relation. childBuilder := ecs.NewBuilder(&world, childID).WithRelation(childID) // Create a child entity with a relation to the parent. child := childBuilder.New(parent) // Create a child entity with a relation to the zero entity. child2 := childBuilder.New(parent) // Get the relation target of the child. _ = world.Relations().Get(child, childID) // Set the relation target. world.Relations().Set(child2, childID, parent) // Filter for the relation with a given target. filter := ecs.NewRelationFilter(ecs.All(childID), parent) query := world.Query(&filter) for query.Next() { fmt.Println( query.Entity(), query.Relation(childID), // Get the relation target in a query. ) } }
Output: {2 0} {1 0} {3 0} {1 0}
type RelationFilter ¶ added in v0.8.0
type RelationFilter struct { Filter Filter // Components filter. Target Entity // Relation target entity. }
RelationFilter is a Filter for a Relation target, in addition to components.
See Relation for details and examples.
Example ¶
world := NewWorld() childID := ComponentID[ChildOf](&world) target := world.NewEntity() builder := NewBuilder(&world, childID).WithRelation(childID) builder.NewBatch(100, target) filter := NewRelationFilter(All(childID), target) query := world.Query(&filter) for query.Next() { // ... }
Output:
func NewRelationFilter ¶ added in v0.8.0
func NewRelationFilter(filter Filter, target Entity) RelationFilter
NewRelationFilter creates a new RelationFilter. It is a Filter for a Relation target, in addition to components.
func (*RelationFilter) Matches ¶ added in v0.8.0
func (f *RelationFilter) Matches(bits *Mask) bool
Matches the filter against a mask.
type Relations ¶ added in v0.8.0
type Relations struct {
// contains filtered or unexported fields
}
Relations provides access to entity Relation targets.
Access it using World.Relations.
Example ¶
world := ecs.NewWorld() relID := ecs.ComponentID[ChildOf](&world) parent := world.NewEntity() child := world.NewEntity(relID) world.Relations().Set(child, relID, parent) fmt.Println(world.Relations().Get(child, relID))
Output: {1 0}
func (*Relations) Exchange ¶ added in v0.10.0
Exchange adds and removes components in one pass. This is more efficient than subsequent use of World.Add and World.Remove. In contrast to World.Exchange, it allows to also set a relation target.
When a Relation component is removed and another one is added, the target entity of the relation is set to zero if no target is given.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called for a missing relation component.
- when called for a component that is not a relation.
- when called without any components to add or remove. Use World.Relations instead.
- when called on a locked world. Do not use during Query iteration!
See also the generic variants under github.com/mlange-42/arche/generic.Exchange.
func (*Relations) ExchangeBatch ¶ added in v0.10.0
func (r *Relations) ExchangeBatch(filter Filter, add []ID, rem []ID, relation ID, target Entity) int
ExchangeBatch exchanges components for many entities, matching a filter. Returns the number of affected entities. In contrast to Batch.Exchange, it allows to also set a relation target.
When a Relation component is removed and another one is added, the target entity of the relation is set to zero if no target is given.
Panics:
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called for a missing relation component.
- when called for a component that is not a relation.
- when called without any components to add or remove. Use Batch.SetRelation instead.
- when called on a locked world. Do not use during Query iteration!
See also Batch.Exchange, Batch.ExchangeQ, Relations.ExchangeBatch and World.Exchange.
func (*Relations) ExchangeBatchQ ¶ added in v0.10.0
func (r *Relations) ExchangeBatchQ(filter Filter, add []ID, rem []ID, relation ID, target Entity) Query
ExchangeBatchQ exchanges components for many entities, matching a filter. It returns a query over the affected entities. In contrast to Batch.ExchangeQ, it allows to also set a relation target.
When a Relation component is removed and another one is added, the target entity of the relation is set to zero if no target is given.
Panics:
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called for a missing relation component.
- when called for a component that is not a relation.
- when called without any components to add or remove. Use Batch.SetRelationQ instead.
- when called on a locked world. Do not use during Query iteration!
See also Batch.Exchange, Batch.ExchangeQ, Relations.ExchangeBatch and World.Exchange.
func (*Relations) Get ¶ added in v0.8.0
Get returns the target entity for an entity relation.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called for a missing component.
- when called for a component that is not a relation.
See Relation for details and examples.
func (*Relations) GetUnchecked ¶ added in v0.8.0
GetUnchecked returns the target entity for an entity relation.
GetUnchecked is an optimized version of Relations.Get. Does not check if the entity is alive or that the component ID is applicable.
Panics when called for a removed entity, but not for a recycled entity.
func (*Relations) Set ¶ added in v0.8.0
Set sets the target entity for an entity relation.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called for a removed (and potentially recycled) target.
- when called for a missing component.
- when called for a component that is not a relation.
- when called on a locked world. Do not use during Query iteration!
See Relation for details and examples.
func (*Relations) SetBatch ¶ added in v0.8.0
SetBatch sets the Relation target for many entities, matching a filter. Returns the number of affected entities.
Panics:
- when called for a missing component.
- when called for a component that is not a relation.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Set, Relations.SetBatchQ and Batch.SetRelation.
Example ¶
world := ecs.NewWorld() relID := ecs.ComponentID[ChildOf](&world) parent := world.NewEntity() ecs.NewBuilder(&world, relID).NewBatch(100) filter := ecs.All(relID) world.Relations().SetBatch(filter, relID, parent)
Output:
func (*Relations) SetBatchQ ¶ added in v0.8.0
SetBatchQ sets the Relation target for many entities, matching a filter. Returns a query over all affected entities.
Panics:
- when called for a missing component.
- when called for a component that is not a relation.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Set, Relations.SetBatch and Batch.SetRelation.
Example ¶
world := ecs.NewWorld() relID := ecs.ComponentID[ChildOf](&world) parent := world.NewEntity() ecs.NewBuilder(&world, relID).NewBatch(100) filter := ecs.All(relID) query := world.Relations().SetBatchQ(filter, relID, parent) fmt.Println(query.Count()) query.Close()
Output: 100
type ResID ¶ added in v0.5.0
type ResID struct {
// contains filtered or unexported fields
}
ResID is the resource identifier type.
func AddResource ¶ added in v0.5.0
AddResource adds a resource to the world. Returns the ID for the added resource.
Panics if there is already such a resource.
Uses reflection. For more efficient access, see World.Resources, and github.com/mlange-42/arche/generic.Resource.Add for a generic variant.
The number of resources per World is limited to MaskTotalBits.
Example ¶
world := ecs.NewWorld() myRes := Position{100, 100} ecs.AddResource(&world, &myRes) res := ecs.GetResource[Position](&world) fmt.Println(res)
Output: &{100 100}
func ResourceID ¶ added in v0.5.0
ResourceID returns the ResID for a resource type via generics. Registers the type if it is not already registered.
The number of resources per World is limited to MaskTotalBits.
Example ¶
world := ecs.NewWorld() resID := ecs.ResourceID[Position](&world) world.Resources().Add(resID, &Position{100, 100})
Output:
func ResourceIDs ¶ added in v0.10.0
ResourceIDs returns a list of all registered resource IDs.
func ResourceTypeID ¶ added in v0.13.0
ResourceTypeID returns the ResID for a resource type. Registers the type if it is not already registered.
See ResourceID for a more commonly used generic variant.
The number of resources per World is limited to MaskTotalBits.
type Resources ¶ added in v0.6.0
type Resources struct {
// contains filtered or unexported fields
}
Resources manage a world's resources.
Access it using World.Resources.
Example ¶
world := NewWorld() resID := ResourceID[Position](&world) myRes := Position{100, 100} world.Resources().Add(resID, &myRes) res := (world.Resources().Get(resID)).(*Position) fmt.Println(res) if world.Resources().Has(resID) { world.Resources().Remove(resID) }
Output: &{100 100}
func (*Resources) Add ¶ added in v0.6.0
Add a resource to the world. The resource should always be a pointer.
Panics if there is already a resource of the given type.
See also github.com/mlange-42/arche/generic.Resource.Add for a generic variant.
func (*Resources) Get ¶ added in v0.6.0
Get returns a pointer to the resource of the given type.
Returns nil if there is no such resource.
See also github.com/mlange-42/arche/generic.Resource.Get for a generic variant.
func (*Resources) Has ¶ added in v0.6.0
Has returns whether the world has the given resource.
See also github.com/mlange-42/arche/generic.Resource.Has for a generic variant.
func (*Resources) Remove ¶ added in v0.6.0
Remove a resource from the world.
Panics if there is no resource of the given type.
See also github.com/mlange-42/arche/generic.Resource.Remove for a generic variant.
type World ¶
type World struct {
// contains filtered or unexported fields
}
World is the central type holding entity and component data, as well as resources.
The World provides all the basic ECS functionality of Arche, like World.Query, World.NewEntity, World.Add, World.Remove or World.RemoveEntity.
For more advanced functionality, see World.Relations, World.Resources, World.Batch, World.Cache and Builder.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) _ = world.NewEntity(posID, velID)
Output:
func NewWorld ¶
NewWorld creates a new World from an optional Config.
Uses the default Config if called without an argument. Accepts zero or one arguments.
Example ¶
package main import ( "github.com/mlange-42/arche/ecs" ) func main() { defaultWorld := ecs.NewWorld() configWorld := ecs.NewWorld( ecs.NewConfig(). WithCapacityIncrement(1024). WithRelationCapacityIncrement(64), ) _, _ = defaultWorld, configWorld }
Output:
func (*World) Add ¶
Add adds components to an Entity.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added because they are already present.
- when called on a locked world. Do not use during Query iteration!
Note that calling a method with varargs in Go causes a slice allocation. For maximum performance, pre-allocate a slice of component IDs and pass it using ellipsis:
// fast world.Add(entity, idA, idB, idC) // even faster world.Add(entity, ids...)
See also World.AddFn, World.Exchange and World.ExchangeFn. See also the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) e := world.NewEntity() world.Add(e, posID, velID)
Output:
func (*World) AddFn ¶ added in v0.14.1
Add adds components to an Entity.
The callback fn is called before the world's listener is notified. Use this to configure the entity's components so that listener subscribers are notified after full initialization.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added because they are already present.
- when called on a locked world. Do not use during Query iteration!
Note that calling a method with varargs in Go causes a slice allocation. For maximum performance, pre-allocate a slice of component IDs and pass it using ellipsis:
// fast world.AddFn(entity, nil, idA, idB, idC) // even faster world.AddFn(entity, nil, ids...)
See also World.Add, World.Exchange and World.ExchangeFn. See also the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
func (*World) Alive ¶
Alive reports whether an entity is still alive.
Example ¶
package main import ( "fmt" "github.com/mlange-42/arche/ecs" ) func main() { world := ecs.NewWorld() e := world.NewEntity() fmt.Println(world.Alive(e)) world.RemoveEntity(e) fmt.Println(world.Alive(e)) }
Output: true false
func (*World) Assign
deprecated
added in
v0.2.0
Assign assigns multiple components to an Entity, using pointers for the content.
Deprecated: This method is slow. Instead, use Assign of the generic API under github.com/mlange-42/arche/generic.Map1, etc. This method may be removed in a future version.
The components in the Comp field of Component must be pointers. The passed pointers are no valid references to the assigned memory!
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added because they are already present.
- when called on a locked world. Do not use during Query iteration!
See also the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) e := world.NewEntity() world.Assign(e, ecs.Component{ID: posID, Comp: &Position{X: 0, Y: 0}}, ecs.Component{ID: velID, Comp: &Velocity{X: 10, Y: 2}}, )
Output:
func (*World) Batch ¶ added in v0.6.0
Batch creates a Batch processing helper. It provides the functionality to manipulate large numbers of entities in batches, which is more efficient than handling them one by one.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) filter := ecs.All(posID) world.Batch().RemoveEntities(filter)
Output:
func (*World) Cache ¶ added in v0.6.0
Cache returns the Cache of the world, for registering filters.
See Cache for details on filter caching.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) filter := ecs.All(posID) cached := world.Cache().Register(filter) query := world.Query(&cached) for query.Next() { // handle entities... }
Output:
func (*World) DumpEntities ¶ added in v0.10.0
func (w *World) DumpEntities() EntityDump
DumpEntities dumps entity information into an EntityDump object. This dump can be used with World.LoadEntities to set the World's entity state.
For world serialization with components and resources, see module github.com/mlange-42/arche-serde.
func (*World) Exchange ¶ added in v0.2.0
Exchange adds and removes components in one pass. This is more efficient than subsequent use of World.Add and World.Remove.
When a Relation component is removed and another one is added, the target entity of the relation is reset to zero.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Exchange and the generic variants under github.com/mlange-42/arche/generic.Exchange.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) e := world.NewEntity(posID) world.Exchange(e, []ecs.ID{velID}, []ecs.ID{posID})
Output:
func (*World) ExchangeFn ¶ added in v0.14.1
Exchange adds and removes components in one pass. This is more efficient than subsequent use of World.Add and World.Remove.
The callback fn is called before the world's listener is notified. Use this to configure the entity's components so that listener subscribers are notified after full initialization.
When a Relation component is removed and another one is added, the target entity of the relation is reset to zero.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be added or removed because they are already present/not present, respectively.
- when called on a locked world. Do not use during Query iteration!
See also Relations.Exchange and the generic variants under github.com/mlange-42/arche/generic.Exchange.
func (*World) Get ¶
Get returns a pointer to the given component of an Entity. Returns nil if the entity has no such component.
Panics when called for a removed (and potentially recycled) entity.
See World.GetUnchecked for an optimized version for static entities. See also github.com/mlange-42/arche/generic.Map.Get for a generic variant.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) e := world.NewEntity(posID) pos := (*Position)(world.Get(e, posID)) pos.X, pos.Y = 10, 5
Output:
func (*World) GetUnchecked ¶ added in v0.7.0
GetUnchecked returns a pointer to the given component of an Entity. Returns nil if the entity has no such component.
GetUnchecked is an optimized version of World.Get, for cases where entities are static or checked with World.Alive in user code. It can also be used after getting another component of the same entity with World.Get.
Panics when called for a removed entity, but not for a recycled entity.
See also github.com/mlange-42/arche/generic.Map.Get for a generic variant.
func (*World) Has ¶
Has returns whether an Entity has a given component.
Panics when called for a removed (and potentially recycled) entity.
See World.HasUnchecked for an optimized version for static entities. See also github.com/mlange-42/arche/generic.Map.Has for a generic variant.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) e := world.NewEntity(posID) if world.Has(e, posID) { world.Remove(e, posID) }
Output:
func (*World) HasUnchecked ¶ added in v0.7.0
HasUnchecked returns whether an Entity has a given component.
HasUnchecked is an optimized version of World.Has, for cases where entities are static or checked with World.Alive in user code.
Panics when called for a removed entity, but not for a recycled entity.
See also github.com/mlange-42/arche/generic.Map.Has for a generic variant.
func (*World) Ids ¶ added in v0.10.0
Ids returns the component IDs for the archetype of the given Entity.
Returns a copy of the archetype's component IDs slice, for safety. This means that the result can be manipulated safely, but also that calling the method may incur some significant cost.
func (*World) IsLocked ¶ added in v0.1.2
IsLocked returns whether the world is locked by any queries.
func (*World) LoadEntities ¶ added in v0.10.0
func (w *World) LoadEntities(data *EntityDump)
LoadEntities resets all entities to the state saved with World.DumpEntities.
Use this only on an empty world! Can be used after World.Reset.
The resulting world will have the same entities (in terms of ID, generation and alive state) as the original world. This is necessary for proper serialization of entity relations. However, the entities will not have any components.
Panics if the world has any dead or alive entities.
For world serialization with components and resources, see module github.com/mlange-42/arche-serde.
func (*World) Mask ¶ added in v0.4.0
Mask returns the archetype Mask for the given Entity.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) e1 := world.NewEntity(posID) e2 := world.NewEntity(velID) filter := ecs.All(posID) // Use the entity's mask to check whether it is in the filter: m1 := world.Mask(e1) m2 := world.Mask(e2) fmt.Println(filter.Matches(&m1)) fmt.Println(filter.Matches(&m2))
Output: true false
func (*World) NewEntity ¶
NewEntity returns a new or recycled Entity. The given component types are added to the entity.
Panics when called on a locked world. Do not use during Query iteration!
⚠️ Important: Entities are intended to be stored and passed around via copy, not via pointers! See Entity.
Note that calling a method with varargs in Go causes a slice allocation. For maximum performance, pre-allocate a slice of component IDs and pass it using ellipsis:
// fast world.NewEntity(idA, idB, idC) // even faster world.NewEntity(ids...)
For more advanced and batched entity creation, see Builder and Batch. See also World.NewEntityFn the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) _ = world.NewEntity(posID, velID)
Output:
func (*World) NewEntityFn ¶ added in v0.14.1
NewEntityFn returns a new or recycled Entity. The given component types are added to the entity.
The callback fn is called before the world's listener is notified. Use this to configure the entity's components so that listener subscribers are notified after full initialization.
Panics when called on a locked world. Do not use during Query iteration!
⚠️ Important: Entities are intended to be stored and passed around via copy, not via pointers! See Entity.
Note that calling a method with varargs in Go causes a slice allocation. For maximum performance, pre-allocate a slice of component IDs and pass it using ellipsis:
// fast world.NewEntityFn(nil, idA, idB, idC) // even faster world.NewEntity(nil, ids...)
For more advanced and batched entity creation, see Builder and Batch. See also World.NewEntity and the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
func (*World) NewEntityWith
deprecated
added in
v0.4.0
NewEntityWith returns a new or recycled Entity. The given component values are assigned to the entity.
Deprecated: This method is slow. Instead, use NewWith of the generic API under github.com/mlange-42/arche/generic.Map1, etc. This method may be removed in a future version.
The components in the Comp field of Component must be pointers. The passed pointers are no valid references to the assigned memory!
Panics when called on a locked world. Do not use during Query iteration!
⚠️ Important: Entities are intended to be stored and passed around via copy, not via pointers! See Entity.
For more advanced and batched entity creation, see Builder. See also the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) _ = world.NewEntityWith( ecs.Component{ID: posID, Comp: &Position{X: 0, Y: 0}}, ecs.Component{ID: velID, Comp: &Velocity{X: 10, Y: 2}}, )
Output:
func (*World) Query ¶
Query creates a Query iterator.
Locks the world to prevent changes to component compositions. The lock is released automatically when the query finishes iteration, or when Query.Close is called. The number of simultaneous locks (and thus open queries) at a given time is limited to MaskTotalBits (256).
A query can iterate through its entities only once, and can't be used anymore afterwards.
To create a Filter for querying, see All, Mask.Without, Mask.Exclusive and RelationFilter.
For type-safe generics queries, see package github.com/mlange-42/arche/generic. For advanced filtering, see package github.com/mlange-42/arche/filter.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) filter := ecs.All(posID, velID) query := world.Query(filter) for query.Next() { pos := (*Position)(query.Get(posID)) vel := (*Velocity)(query.Get(velID)) pos.X += vel.X pos.Y += vel.Y }
Output:
func (*World) Relations ¶ added in v0.8.0
Relations returns the Relations of the world, for accessing entity Relation targets.
See Relations for details.
Example ¶
world := ecs.NewWorld() relID := ecs.ComponentID[ChildOf](&world) parent := world.NewEntity() child := world.NewEntity(relID) world.Relations().Set(child, relID, parent) fmt.Println(world.Relations().Get(child, relID))
Output: {1 0}
func (*World) Remove ¶
Remove removes components from an entity.
Panics:
- when called for a removed (and potentially recycled) entity.
- when called with components that can't be removed because they are not present.
- when called on a locked world. Do not use during Query iteration!
See also World.Exchange. See also the generic variants under github.com/mlange-42/arche/generic.Map1, etc.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) velID := ecs.ComponentID[Velocity](&world) e := world.NewEntity(posID, velID) world.Remove(e, posID, velID)
Output:
func (*World) RemoveEntity ¶ added in v0.4.0
RemoveEntity removes an Entity, making it eligible for recycling.
Panics when called on a locked world or for an already removed entity. Do not use during Query iteration!
Example ¶
package main import ( "github.com/mlange-42/arche/ecs" ) func main() { world := ecs.NewWorld() e := world.NewEntity() world.RemoveEntity(e) }
Output:
func (*World) Reset ¶ added in v0.6.0
func (w *World) Reset()
Reset removes all entities and resources from the world.
Does NOT free reserved memory, remove archetypes, clear the registry, clear cached filters, etc. However, it removes archetypes with a relation component that is not zero.
Can be used to run systematic simulations without the need to re-allocate memory for each run. Accelerates re-populating the world by a factor of 2-3.
Example ¶
package main import ( "github.com/mlange-42/arche/ecs" ) func main() { world := ecs.NewWorld() _ = world.NewEntity() world.Reset() }
Output:
func (*World) Resources ¶ added in v0.6.0
Resources of the world.
Resources are component-like data that is not associated to an entity, but unique to the world.
Example ¶
world := ecs.NewWorld() resID := ecs.ResourceID[Position](&world) myRes := Position{} world.Resources().Add(resID, &myRes) res := (world.Resources().Get(resID)).(*Position) res.X, res.Y = 10, 5
Output:
func (*World) Set
deprecated
added in
v0.3.0
Set overwrites a component for an Entity, using the given pointer for the content.
Deprecated: This method is slow. Instead, use Set of the generic API under github.com/mlange-42/arche/generic.Map. This method may be removed in a future version.
The passed component must be a pointer. Returns a pointer to the assigned memory. The passed in pointer is not a valid reference to that memory!
Panics:
- when called for a removed (and potentially recycled) entity.
- if the entity does not have a component of that type.
- when called on a locked world. Do not use during Query iteration!
See also github.com/mlange-42/arche/generic.Map.Set for a generic variant.
Example ¶
world := ecs.NewWorld() posID := ecs.ComponentID[Position](&world) e := world.NewEntity(posID) world.Set(e, posID, &Position{X: 0, Y: 0})
Output:
func (*World) SetListener ¶ added in v0.4.0
SetListener sets a Listener for the world. The listener is immediately called on every ecs.Entity change. Replaces the current listener. Call with nil to remove a listener.
For details, see EntityEvent, Listener and sub-package event.
Example ¶
package main import ( "fmt" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/ecs/event" ) func main() { world := ecs.NewWorld() listener := TestListener{ Callback: func(world *ecs.World, evt ecs.EntityEvent) { fmt.Println(evt.Entity) }, } world.SetListener(&listener) world.NewEntity() } // TestListener for all [EntityEvent]s. type TestListener struct { Callback func(world *ecs.World, evt ecs.EntityEvent) } // Notify the listener. // Calls the Callback. func (l *TestListener) Notify(world *ecs.World, evt ecs.EntityEvent) { l.Callback(world, evt) } // Subscriptions of the listener. // Subscribes to all events. func (l *TestListener) Subscriptions() event.Subscription { return event.All } // Components the listener subscribes to. // Subscribes to all components. func (l *TestListener) Components() *ecs.Mask { return nil }
Output: {1 0}
func (*World) Stats ¶ added in v0.4.0
Stats reports statistics for inspecting the World.
The underlying stats.World object is re-used and updated between calls. The returned pointer should thus not be stored for later analysis. Rather, the required data should be extracted immediately.
Example ¶
package main import ( "fmt" "github.com/mlange-42/arche/ecs" ) func main() { world := ecs.NewWorld() stats := world.Stats() fmt.Println(stats.Entities.String()) }
Output: Entities -- Used: 0, Recycled: 0, Total: 0, Capacity: 128
Source Files ¶
- archetype.go
- archetype_node.go
- archetypes.go
- batch.go
- bitmask.go
- bitmask_common.go
- bitset.go
- builder.go
- cache.go
- config.go
- doc.go
- entity.go
- event.go
- filter.go
- functions.go
- id_map.go
- pool.go
- query.go
- query_no_debug.go
- registry.go
- relation.go
- relations.go
- resources.go
- types.go
- util.go
- world.go
- world_internal.go
Directories ¶
Path | Synopsis |
---|---|
Package event contains a mask type and bit switches for listener subscriptions.
|
Package event contains a mask type and bit switches for listener subscriptions. |
Package stats provides the structs returned by ecs.World.Stats().
|
Package stats provides the structs returned by ecs.World.Stats(). |