...
1 package gohan
2
3 import (
4 "reflect"
5 )
6
7
8
9 type componentID int
10
11
12 func newComponentID() componentID {
13 w.maxComponentID++
14
15 for i := Entity(1); i <= w.maxEntityID; i++ {
16 w.components[i] = append(w.components[i], nil)
17 }
18
19 return w.maxComponentID
20 }
21
22 func componentIDByValue(v interface{}) componentID {
23 sV := reflect.ValueOf(v)
24 sT := reflect.TypeOf(v)
25 if sV.Kind() == reflect.Ptr {
26 sV = sV.Elem()
27 sT = sT.Elem()
28 }
29
30 componentName := sV.Type().String()
31 return componentIDByName(componentName)
32 }
33
34 func componentIDByName(name string) componentID {
35 if len(name) == 0 {
36 return 0
37 }
38
39 if name[0:1] == "*" {
40 name = name[1:]
41 }
42
43 if !w.haveSystemComponentName[name] {
44 w.systemComponentNames = append(w.systemComponentNames, name)
45 w.haveSystemComponentName[name] = true
46 id := newComponentID()
47 return id
48 }
49
50 for i, savedName := range w.systemComponentNames {
51 if savedName == name {
52 return componentID(i)
53 }
54 }
55
56 return 0
57 }
58
59
60 func (e Entity) AddComponent(component interface{}) {
61 w.componentMutex.Lock()
62 defer w.componentMutex.Unlock()
63
64 id := componentIDByValue(component)
65 w.components[e][id] = component
66
67 w.entityMutex.Lock()
68 defer w.entityMutex.Unlock()
69 w.modifiedEntities = append(w.modifiedEntities, e)
70 }
71
72
73
74 func (e Entity) With(f interface{}) {
75 components := w.components[e]
76 if components == nil {
77 return
78 }
79
80 t := reflect.TypeOf(f)
81 v := reflect.ValueOf(f)
82 numIn := t.NumIn()
83
84 if t.Kind() != reflect.Func || v.IsNil() || numIn == 0 {
85 panic("component.With() must be provided with a function containing one or more components as arguments")
86 }
87
88 args := make([]reflect.Value, numIn)
89 for i := 0; i < numIn; i++ {
90 id := componentIDByName(t.In(i).String())
91
92 arg := reflect.ValueOf(components[id])
93 if components[id] == nil {
94 arg = reflect.New(t.In(i)).Elem()
95 }
96
97 args[i] = arg
98 }
99
100 v.Call(args)
101 }
102
103
104 func (e Entity) getComponent(componentID componentID) interface{} {
105 components := w.components[e]
106 if components == nil {
107 return nil
108 }
109 return components[componentID]
110 }
111
View as plain text