children?

This commit is contained in:
Josh Deprez 2021-09-28 20:57:15 +10:00
parent 3a5a150351
commit a9401b505a

View file

@ -33,6 +33,9 @@ func init() {
gob.Register(&Game{}) gob.Register(&Game{})
} }
// ComponentSet is a set of components.
type ComponentSet map[interface{}]struct{}
// Game implements the ebiten methods using a collection of components. One // Game implements the ebiten methods using a collection of components. One
// component must be the designated root component. // component must be the designated root component.
type Game struct { type Game struct {
@ -45,8 +48,9 @@ type Game struct {
dbmu sync.RWMutex dbmu sync.RWMutex
byID map[string]Identifier // Named components by ID byID map[string]Identifier // Named components by ID
byAB map[abKey]map[interface{}]struct{} // Ancestor/behaviour index byAB map[abKey]ComponentSet // Ancestor/behaviour index
par map[interface{}]interface{} // par[x] is parent of x parent map[interface{}]interface{} // parent[x] is parent of x
children map[interface{}]ComponentSet // children[x] are chilren of x
} }
// Draw draws everything. // Draw draws everything.
@ -102,7 +106,13 @@ func (g *Game) Component(id string) Identifier {
func (g *Game) Parent(c interface{}) interface{} { func (g *Game) Parent(c interface{}) interface{} {
g.dbmu.RLock() g.dbmu.RLock()
defer g.dbmu.RUnlock() defer g.dbmu.RUnlock()
return g.par[c] return g.parent[c]
}
func (g *Game) Children(c interface{}) ComponentSet {
g.dbmu.RLock()
defer g.dbmu.RUnlock()
return g.children[c]
} }
// PathRegister calls Register on every Registrar in the path between g and // PathRegister calls Register on every Registrar in the path between g and
@ -154,7 +164,7 @@ func (g *Game) ReversePath(component interface{}) []interface{} {
// Query looks for components having both a given ancestor and implementing // Query looks for components having both a given ancestor and implementing
// a given behaviour (see Behaviors in interface.go). This only returns sensible // a given behaviour (see Behaviors in interface.go). This only returns sensible
// values after LoadAndPrepare. Note that every component is its own ancestor. // values after LoadAndPrepare. Note that every component is its own ancestor.
func (g *Game) Query(ancestor interface{}, behaviour reflect.Type) map[interface{}]struct{} { func (g *Game) Query(ancestor interface{}, behaviour reflect.Type) ComponentSet {
g.dbmu.RLock() g.dbmu.RLock()
defer g.dbmu.RUnlock() defer g.dbmu.RUnlock()
return g.byAB[abKey{ancestor, behaviour}] return g.byAB[abKey{ancestor, behaviour}]
@ -232,8 +242,9 @@ func (g *Game) build() error {
g.dbmu.Lock() g.dbmu.Lock()
defer g.dbmu.Unlock() defer g.dbmu.Unlock()
g.byID = make(map[string]Identifier) g.byID = make(map[string]Identifier)
g.byAB = make(map[abKey]map[interface{}]struct{}) g.byAB = make(map[abKey]ComponentSet)
g.par = make(map[interface{}]interface{}) g.parent = make(map[interface{}]interface{})
g.children = make(map[interface{}]ComponentSet)
return g.registerRecursive(g, nil) return g.registerRecursive(g, nil)
} }
@ -277,8 +288,12 @@ func (g *Game) registerOne(component, parent interface{}) error {
} }
} }
// register in g.par // register in g.parent and g.children
g.par[component] = parent g.parent[component] = parent
if g.children[parent] == nil {
g.children[parent] = make(ComponentSet)
}
g.children[parent][component] = struct{}{}
// register in g.byAB // register in g.byAB
ct := reflect.TypeOf(component) ct := reflect.TypeOf(component)
@ -287,10 +302,10 @@ func (g *Game) registerOne(component, parent interface{}) error {
continue continue
} }
// TODO: better than O(len(path)^2) time and memory? // TODO: better than O(len(path)^2) time and memory?
for p := component; p != nil; p = g.par[p] { for p := component; p != nil; p = g.parent[p] {
k := abKey{p, b} k := abKey{p, b}
if g.byAB[k] == nil { if g.byAB[k] == nil {
g.byAB[k] = make(map[interface{}]struct{}) g.byAB[k] = make(ComponentSet)
} }
g.byAB[k][component] = struct{}{} g.byAB[k][component] = struct{}{}
} }
@ -327,15 +342,16 @@ func (g *Game) unregisterOne(component interface{}) {
if !ct.Implements(b) { if !ct.Implements(b) {
continue continue
} }
for p := component; p != nil; p = g.par[p] { for p := component; p != nil; p = g.parent[p] {
if k := (abKey{p, b}); g.byAB[k] != nil { if k := (abKey{p, b}); g.byAB[k] != nil {
delete(g.byAB[k], component) delete(g.byAB[k], component)
} }
} }
} }
// unregister from g.par // unregister from g.parent and g.children
delete(g.par, component) delete(g.children[g.parent[component]], component)
delete(g.parent, component)
// unregister from g.byID if needed // unregister from g.byID if needed
if id, ok := component.(Identifier); ok && id.Ident() != "" { if id, ok := component.(Identifier); ok && id.Ident() != "" {