|
|
|
@ -4,17 +4,16 @@ package ecs
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"sort"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Controller struct {
|
|
|
|
|
systems map[reflect.Type]System
|
|
|
|
|
systems map[string]System
|
|
|
|
|
sortedSystems map[int][]System
|
|
|
|
|
priorityKeys []int
|
|
|
|
|
nextEntityID Entity
|
|
|
|
|
components map[reflect.Type][]Entity
|
|
|
|
|
entities map[Entity]map[reflect.Type]Component
|
|
|
|
|
components map[string][]Entity
|
|
|
|
|
entities map[Entity]map[string]Component
|
|
|
|
|
deadEntities []int
|
|
|
|
|
|
|
|
|
|
// The component map will keep track of what components are available
|
|
|
|
@ -24,12 +23,12 @@ type Controller struct {
|
|
|
|
|
// NewController is a convenience/constructor method to properly initialize a new processor
|
|
|
|
|
func NewController() *Controller {
|
|
|
|
|
controller := Controller{}
|
|
|
|
|
controller.systems = make(map[reflect.Type]System)
|
|
|
|
|
controller.systems = make(map[string]System)
|
|
|
|
|
controller.sortedSystems = make(map[int][]System)
|
|
|
|
|
controller.priorityKeys = []int{}
|
|
|
|
|
controller.nextEntityID = 0
|
|
|
|
|
controller.components = make(map[reflect.Type][]Entity)
|
|
|
|
|
controller.entities = make(map[Entity]map[reflect.Type]Component)
|
|
|
|
|
controller.components = make(map[string][]Entity)
|
|
|
|
|
controller.entities = make(map[Entity]map[string]Component)
|
|
|
|
|
controller.deadEntities = []int{}
|
|
|
|
|
controller.componentMap = make(map[string]Component)
|
|
|
|
|
|
|
|
|
@ -47,7 +46,7 @@ func (c *Controller) CreateEntity(components []Component) Entity {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.entities[c.nextEntityID] = make(map[reflect.Type]Component)
|
|
|
|
|
c.entities[c.nextEntityID] = make(map[string]Component)
|
|
|
|
|
|
|
|
|
|
return c.nextEntityID
|
|
|
|
|
}
|
|
|
|
@ -89,7 +88,7 @@ func (c *Controller) GetMappedComponentClass(componentName string) Component {
|
|
|
|
|
// as you can check which entites are associated with a component, and vice versa.
|
|
|
|
|
func (c *Controller) AddComponent(entity Entity, component Component) {
|
|
|
|
|
// First, get the type of the component
|
|
|
|
|
componentType := reflect.TypeOf(component)
|
|
|
|
|
componentType := component.Type()
|
|
|
|
|
|
|
|
|
|
// Record that the component type is associated with the entity.
|
|
|
|
|
c.components[componentType] = append(c.components[componentType], entity)
|
|
|
|
@ -97,14 +96,14 @@ func (c *Controller) AddComponent(entity Entity, component Component) {
|
|
|
|
|
// Now, check to see if the entity is already tracked in the controller entity list. If it is not, add it, and
|
|
|
|
|
// associate the component with it
|
|
|
|
|
if _, ok := c.entities[entity]; !ok {
|
|
|
|
|
c.entities[entity] = make(map[reflect.Type]Component)
|
|
|
|
|
c.entities[entity] = make(map[string]Component)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.entities[entity][componentType] = component
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HasComponent checks a given entity to see if it has a given component associated with it
|
|
|
|
|
func (c *Controller) HasComponent(entity Entity, componentType reflect.Type) bool {
|
|
|
|
|
func (c *Controller) HasComponent(entity Entity, componentType string) bool {
|
|
|
|
|
if _, ok := c.entities[entity][componentType]; ok {
|
|
|
|
|
return true
|
|
|
|
|
} else {
|
|
|
|
@ -113,7 +112,7 @@ func (c *Controller) HasComponent(entity Entity, componentType reflect.Type) boo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetComponent returns the component instance for a component type, if one exists for the provided entity
|
|
|
|
|
func (c *Controller) GetComponent(entity Entity, componentType reflect.Type) Component {
|
|
|
|
|
func (c *Controller) GetComponent(entity Entity, componentType string) Component {
|
|
|
|
|
// Check the given entity has the provided component
|
|
|
|
|
if c.HasComponent(entity, componentType) {
|
|
|
|
|
return c.entities[entity][componentType]
|
|
|
|
@ -123,7 +122,7 @@ func (c *Controller) GetComponent(entity Entity, componentType reflect.Type) Com
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetEntity gets a specific entity, and all of its component instances
|
|
|
|
|
func (c *Controller) GetEntity(entity Entity) map[reflect.Type]Component {
|
|
|
|
|
func (c *Controller) GetEntity(entity Entity) map[string]Component {
|
|
|
|
|
for i, _ := range c.entities {
|
|
|
|
|
if i == entity {
|
|
|
|
|
return c.entities[entity]
|
|
|
|
@ -134,13 +133,13 @@ func (c *Controller) GetEntity(entity Entity) map[reflect.Type]Component {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetEntities returns a map of all entities and their component instances
|
|
|
|
|
func (c *Controller) GetEntities() map[Entity]map[reflect.Type]Component {
|
|
|
|
|
func (c *Controller) GetEntities() map[Entity]map[string]Component {
|
|
|
|
|
return c.entities
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetEntitiesWithComponent returns a list of all entities with a given component attached
|
|
|
|
|
// TODO: Allow for passing a list of components
|
|
|
|
|
func (c *Controller) GetEntitiesWithComponent(componentType reflect.Type) []Entity {
|
|
|
|
|
func (c *Controller) GetEntitiesWithComponent(componentType string) []Entity {
|
|
|
|
|
entitiesWithComponent := make([]Entity, 0)
|
|
|
|
|
for entity := range c.entities {
|
|
|
|
|
if c.HasComponent(entity, componentType) {
|
|
|
|
@ -152,7 +151,7 @@ func (c *Controller) GetEntitiesWithComponent(componentType reflect.Type) []Enti
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateComponent updates a component on an entity with a new version of the same component
|
|
|
|
|
func (c *Controller) UpdateComponent(entity Entity, componentType reflect.Type, newComponent Component) Entity {
|
|
|
|
|
func (c *Controller) UpdateComponent(entity Entity, componentType string, newComponent Component) Entity {
|
|
|
|
|
// First, remove the component in question (Don't actually update things, but rather remove and replace)
|
|
|
|
|
c.RemoveComponent(entity, componentType)
|
|
|
|
|
|
|
|
|
@ -165,7 +164,7 @@ func (c *Controller) UpdateComponent(entity Entity, componentType reflect.Type,
|
|
|
|
|
// DeleteComponent will delete a component instance from an entity, based on component type. It will also remove the
|
|
|
|
|
// association between the component and the entity, and remove the component from the processor completely if no
|
|
|
|
|
// other entities are using it.
|
|
|
|
|
func (c *Controller) RemoveComponent(entity Entity, componentType reflect.Type) Entity {
|
|
|
|
|
func (c *Controller) RemoveComponent(entity Entity, componentType string) Entity {
|
|
|
|
|
// Find the index of the entity to operate on in the components slice
|
|
|
|
|
index := -1
|
|
|
|
|
for i, v := range c.components[componentType] {
|
|
|
|
@ -194,7 +193,7 @@ func (c *Controller) RemoveComponent(entity Entity, componentType reflect.Type)
|
|
|
|
|
// numeric order, low to high. If multiple systems are registered as the same priority, they will be randomly run within
|
|
|
|
|
// that priority group.
|
|
|
|
|
func (c *Controller) AddSystem(system System, priority int) {
|
|
|
|
|
systemType := reflect.TypeOf(system)
|
|
|
|
|
systemType := system.SystemType()
|
|
|
|
|
|
|
|
|
|
if _, ok := c.systems[systemType]; !ok {
|
|
|
|
|
// A system of this type has not been added yet, so add it to the systems list
|
|
|
|
@ -214,10 +213,10 @@ func (c *Controller) AddSystem(system System, priority int) {
|
|
|
|
|
// Process kicks off system processing for all systems attached to the controller. Systems will be processed in the
|
|
|
|
|
// order they are found, or if they have a priority, in priority order. If there is a mix of systems with priority and
|
|
|
|
|
// without, systems with priority will be processed first (in order).
|
|
|
|
|
func (c *Controller) Process(excludedSystems []reflect.Type) {
|
|
|
|
|
func (c *Controller) Process(excludedSystems []string) {
|
|
|
|
|
for _, key := range c.priorityKeys {
|
|
|
|
|
for _, system := range c.sortedSystems[key] {
|
|
|
|
|
systemType := reflect.TypeOf(system)
|
|
|
|
|
systemType := system.SystemType()
|
|
|
|
|
|
|
|
|
|
// Check if the current system type was marked as excluded on this call. If it was, not process it.
|
|
|
|
|
if !TypeInSlice(systemType, excludedSystems) {
|
|
|
|
@ -228,7 +227,7 @@ func (c *Controller) Process(excludedSystems []reflect.Type) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HasSystem checks the controller to see if it has a given system associated with it
|
|
|
|
|
func (c *Controller) HasSystem(systemType reflect.Type) bool {
|
|
|
|
|
func (c *Controller) HasSystem(systemType string) bool {
|
|
|
|
|
if _, ok := c.systems[systemType]; ok {
|
|
|
|
|
return true
|
|
|
|
|
} else {
|
|
|
|
@ -237,7 +236,7 @@ func (c *Controller) HasSystem(systemType reflect.Type) bool {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProcessSystem allows for on demand processing of individual systems, rather than processing all at once via Process
|
|
|
|
|
func (c *Controller) ProcessSystem(systemType reflect.Type) {
|
|
|
|
|
func (c *Controller) ProcessSystem(systemType string) {
|
|
|
|
|
if c.HasSystem(systemType) {
|
|
|
|
|
system := c.systems[systemType]
|
|
|
|
|
system.Process()
|
|
|
|
|