You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
2.4 KiB
Go
111 lines
2.4 KiB
Go
package gohan
|
|
|
|
import (
|
|
"reflect"
|
|
)
|
|
|
|
// componentID is a component identifier. Each Component is assigned a unique ID
|
|
// via world.NewComponentID, and implements a componentID method returning its ID.
|
|
type componentID int
|
|
|
|
// newComponentID returns the next available componentID.
|
|
func newComponentID() componentID {
|
|
w.maxComponentID++
|
|
|
|
for i := Entity(1); i <= w.maxEntityID; i++ {
|
|
w.components[i] = append(w.components[i], nil)
|
|
}
|
|
|
|
return w.maxComponentID
|
|
}
|
|
|
|
func componentIDByValue(v interface{}) componentID {
|
|
sV := reflect.ValueOf(v)
|
|
sT := reflect.TypeOf(v)
|
|
if sV.Kind() == reflect.Ptr {
|
|
sV = sV.Elem()
|
|
sT = sT.Elem()
|
|
}
|
|
|
|
componentName := sV.Type().String()
|
|
return componentIDByName(componentName)
|
|
}
|
|
|
|
func componentIDByName(name string) componentID {
|
|
if len(name) == 0 {
|
|
return 0
|
|
}
|
|
|
|
if name[0:1] == "*" {
|
|
name = name[1:]
|
|
}
|
|
|
|
if !w.haveSystemComponentName[name] {
|
|
w.systemComponentNames = append(w.systemComponentNames, name)
|
|
w.haveSystemComponentName[name] = true
|
|
id := newComponentID()
|
|
return id
|
|
}
|
|
|
|
for i, savedName := range w.systemComponentNames {
|
|
if savedName == name {
|
|
return componentID(i)
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// AddComponent adds a Component to an Entity.
|
|
func (e Entity) AddComponent(component interface{}) {
|
|
w.componentMutex.Lock()
|
|
defer w.componentMutex.Unlock()
|
|
|
|
id := componentIDByValue(component)
|
|
w.components[e][id] = component
|
|
|
|
w.entityMutex.Lock()
|
|
defer w.entityMutex.Unlock()
|
|
w.modifiedEntities = append(w.modifiedEntities, e)
|
|
}
|
|
|
|
// With accepts any function which takes one or more components as arguments.
|
|
// This function will block until the provided function returns.
|
|
func (e Entity) With(f interface{}) {
|
|
components := w.components[e]
|
|
if components == nil {
|
|
return
|
|
}
|
|
|
|
t := reflect.TypeOf(f)
|
|
v := reflect.ValueOf(f)
|
|
numIn := t.NumIn()
|
|
|
|
if t.Kind() != reflect.Func || v.IsNil() || numIn == 0 {
|
|
panic("component.With() must be provided with a function containing one or more components as arguments")
|
|
}
|
|
|
|
args := make([]reflect.Value, numIn)
|
|
for i := 0; i < numIn; i++ {
|
|
id := componentIDByName(t.In(i).String())
|
|
|
|
arg := reflect.ValueOf(components[id])
|
|
if components[id] == nil {
|
|
arg = reflect.New(t.In(i)).Elem()
|
|
}
|
|
|
|
args[i] = arg
|
|
}
|
|
|
|
v.Call(args)
|
|
}
|
|
|
|
// getComponent gets a Component of an Entity.
|
|
func (e Entity) getComponent(componentID componentID) interface{} {
|
|
components := w.components[e]
|
|
if components == nil {
|
|
return nil
|
|
}
|
|
return components[componentID]
|
|
}
|