Update uses Query, Query is fixed
This commit is contained in:
parent
6792db5d7a
commit
3ad1cf8d4d
3 changed files with 52 additions and 36 deletions
|
@ -44,11 +44,10 @@ func (a *Actor) CollidesAt(p geom.Int3) bool {
|
|||
bounds := a.Bounds.Add(p)
|
||||
cd := a.game.Component(a.CollisionDomain)
|
||||
if cd == nil {
|
||||
log.Printf("collision domain %q not found in game", a.CollisionDomain)
|
||||
log.Printf("collision domain %q not found", a.CollisionDomain)
|
||||
return false
|
||||
}
|
||||
return errCollision == a.game.Query(cd, ColliderType, func(c interface{}) error {
|
||||
log.Printf("checking for collision with %v", c)
|
||||
return errCollision == a.game.Query(cd, ColliderType, nil, func(c interface{}) error {
|
||||
if c.(Collider).CollidesWith(bounds) {
|
||||
return errCollision
|
||||
}
|
||||
|
|
|
@ -66,24 +66,18 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (w, h int) {
|
|||
|
||||
// Update updates everything.
|
||||
func (g *Game) Update() error {
|
||||
return g.updateRecursive(g)
|
||||
}
|
||||
|
||||
// updateRecursive updates everything in a post-order traversal. It terminates
|
||||
// the recursion early if the component reports it is Disabled.
|
||||
func (g *Game) updateRecursive(c interface{}) error {
|
||||
//return g.updateRecursive(g)
|
||||
return g.Query(g.Root, UpdaterType,
|
||||
func(c interface{}) error {
|
||||
if d, ok := c.(Disabler); ok && d.Disabled() {
|
||||
return nil
|
||||
}
|
||||
if sc, ok := c.(Scanner); ok {
|
||||
if err := sc.Scan(g.updateRecursive); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if u, ok := c.(Updater); ok && c != g {
|
||||
return u.Update()
|
||||
return Skip
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(c interface{}) error {
|
||||
return c.(Updater).Update()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Ident returns "__GAME__".
|
||||
|
@ -162,23 +156,37 @@ func (g *Game) ReversePath(component interface{}) []interface{} {
|
|||
|
||||
// Query looks for components having both a given ancestor and implementing
|
||||
// a given behaviour (see Behaviors in interface.go). This only returns sensible
|
||||
// values after LoadAndPrepare. Note that every component is its own ancestor.
|
||||
func (g *Game) Query(ancestor interface{}, behaviour reflect.Type, visit func(interface{}) error) error {
|
||||
// NB: per the godoc, do not use RLock for recursive read locking.
|
||||
g.dbmu.RLock()
|
||||
defer g.dbmu.RUnlock()
|
||||
return g.queryRecursive(ancestor, behaviour, visit)
|
||||
}
|
||||
|
||||
// Post-order visit p and descendants of p having behaviour b.
|
||||
func (g *Game) queryRecursive(p interface{}, b reflect.Type, v func(interface{}) error) error {
|
||||
for x := range g.byAB[abKey{p, b}] {
|
||||
if err := g.queryRecursive(x, b, v); err != nil {
|
||||
// values for registered components.
|
||||
//
|
||||
// Note that every component is its own ancestor.
|
||||
//
|
||||
// visitPre is visited before descendants, while visitPost is visited after
|
||||
// descendants. nil visitors are ignored.
|
||||
func (g *Game) Query(ancestor interface{}, behaviour reflect.Type, visitPre, visitPost func(interface{}) error) error {
|
||||
pi := reflect.TypeOf(ancestor).Implements(behaviour)
|
||||
if pi && visitPre != nil {
|
||||
if err := visitPre(ancestor); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if reflect.TypeOf(p).Implements(b) {
|
||||
return v(p)
|
||||
// * Update uses Query.
|
||||
// * Updaters can Register new components.
|
||||
// * Register acquires g.dbmu.Lock.
|
||||
// ==> Wrapping the whole thing in RLock would deadlock.
|
||||
// Make the read lock as tight as possible.
|
||||
g.dbmu.RLock()
|
||||
q := g.byAB[abKey{ancestor, behaviour}]
|
||||
g.dbmu.RUnlock()
|
||||
for x := range q {
|
||||
if err := g.Query(x, behaviour, visitPre, visitPost); err != nil {
|
||||
if errors.Is(err, Skip) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
if pi && visitPost != nil {
|
||||
return visitPost(ancestor)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -416,3 +424,12 @@ func concatOpts(a, b ebiten.DrawImageOptions) ebiten.DrawImageOptions {
|
|||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Skip is an "error" value that can be returned from visitor callbacks. It
|
||||
// tells recursive methods of Game to skip processing the current item and its
|
||||
// descendants, but will otherwise continue processing.
|
||||
const Skip = skip("skip")
|
||||
|
||||
type skip string
|
||||
|
||||
func (s skip) Error() string { return string(s) }
|
||||
|
|
|
@ -151,7 +151,7 @@ func (g *Game) cmdQuery(dst io.Writer, argv []string) {
|
|||
fmt.Fprintf(dst, "%T\n", c)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}, nil)
|
||||
if noResults {
|
||||
fmt.Fprintln(dst, "No results")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue