String methods, no separate walkers
This commit is contained in:
parent
aab99dab8f
commit
4dba7b22c7
12 changed files with 81 additions and 70 deletions
|
@ -127,3 +127,5 @@ func (a *Actor) Prepare(g *Game) error {
|
|||
a.game = g
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Actor) String() string { return "Actor@" + a.Pos.String() }
|
||||
|
|
|
@ -90,6 +90,8 @@ func (c *Camera) Scan(visit func(interface{}) error) error {
|
|||
return visit(c.Child)
|
||||
}
|
||||
|
||||
func (c *Camera) String() string { return "Camera@" + c.Centre.String() }
|
||||
|
||||
// Transform returns the camera transform.
|
||||
func (c *Camera) Transform() (opts ebiten.DrawImageOptions) {
|
||||
opts.GeoM.Translate(geom.CFloat(c.Centre.Mul(-1)))
|
||||
|
|
|
@ -18,6 +18,8 @@ func (c Container) Scan(visit func(interface{}) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c Container) String() string { return "Container" }
|
||||
|
||||
// Register records component in the slice, if parent is the container.
|
||||
func (c *Container) Register(component, parent interface{}) error {
|
||||
if parent == c {
|
||||
|
|
|
@ -120,6 +120,8 @@ func (d *DrawDAG) Scan(visit func(interface{}) error) error {
|
|||
return visit(d.Child)
|
||||
}
|
||||
|
||||
func (d *DrawDAG) String() string { return "DrawDAG" }
|
||||
|
||||
// Update checks for any changes to descendants, and updates its internal
|
||||
// data structures accordingly.
|
||||
func (d *DrawDAG) Update() error {
|
||||
|
@ -325,7 +327,8 @@ func newDAG() *dag {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *dag) String() string {
|
||||
// Dot returns a dot-syntax-like description of the graph.
|
||||
func (d *dag) Dot() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("digraph {\n")
|
||||
for v, e := range d.out {
|
||||
|
|
|
@ -58,3 +58,5 @@ func (d *DrawDFS) draw(component interface{}, screen *ebiten.Image, opts ebiten.
|
|||
func (d *DrawDFS) Scan(visit func(interface{}) error) error {
|
||||
return visit(d.Child)
|
||||
}
|
||||
|
||||
func (d *DrawDFS) String() string { return "DrawDFS" }
|
||||
|
|
|
@ -169,46 +169,6 @@ func (g *Game) Scan(visit func(interface{}) error) error {
|
|||
return visit(g.Root)
|
||||
}
|
||||
|
||||
// PreorderWalk calls visit with every component and its parent, reachable from
|
||||
// the given component via Scan, for as long as visit returns nil. The parent
|
||||
// value passed to visit when visiting component will be nil. The parent will be
|
||||
// visited before the children.
|
||||
func PreorderWalk(component interface{}, visit func(component, parent interface{}) error) error {
|
||||
return preorderWalk(component, nil, visit)
|
||||
}
|
||||
|
||||
func preorderWalk(component, parent interface{}, visit func(component, parent interface{}) error) error {
|
||||
if err := visit(component, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
if sc, ok := component.(Scanner); ok {
|
||||
return sc.Scan(func(c interface{}) error {
|
||||
return preorderWalk(c, component, visit)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostorderWalk calls visit with every component and its parent, reachable from
|
||||
// the given component via Scan, for as long as visit returns nil. The parent
|
||||
// value passed to visit when visiting component will be nil. The children will
|
||||
// be visited before the parent.
|
||||
func PostorderWalk(component interface{}, visit func(component, parent interface{}) error) error {
|
||||
return postorderWalk(component, nil, visit)
|
||||
}
|
||||
|
||||
func postorderWalk(component, parent interface{}, visit func(component, parent interface{}) error) error {
|
||||
if sc, ok := component.(Scanner); ok {
|
||||
scv := func(c interface{}) error {
|
||||
return postorderWalk(c, component, visit)
|
||||
}
|
||||
if err := sc.Scan(scv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return visit(component, parent)
|
||||
}
|
||||
|
||||
// Load loads a component and all subcomponents recursively.
|
||||
// Note that this method does not implement Loader.
|
||||
func (g *Game) Load(component interface{}, assets fs.FS) error {
|
||||
|
@ -258,14 +218,9 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
|||
|
||||
// Build the component databases
|
||||
startBuild := time.Now()
|
||||
g.dbmu.Lock()
|
||||
g.byID = make(map[string]Identifier)
|
||||
g.byAB = make(map[abKey]map[interface{}]struct{})
|
||||
g.par = make(map[interface{}]interface{})
|
||||
if err := PreorderWalk(g, g.registerOne); err != nil {
|
||||
if err := g.build(); err != nil {
|
||||
return err
|
||||
}
|
||||
g.dbmu.Unlock()
|
||||
log.Printf("finished building db in %v", time.Since(startBuild))
|
||||
|
||||
// Prepare all the Preppers
|
||||
|
@ -277,6 +232,15 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) build() error {
|
||||
g.dbmu.Lock()
|
||||
defer g.dbmu.Unlock()
|
||||
g.byID = make(map[string]Identifier)
|
||||
g.byAB = make(map[abKey]map[interface{}]struct{})
|
||||
g.par = make(map[interface{}]interface{})
|
||||
return g.registerRecursive(g, nil)
|
||||
}
|
||||
|
||||
// Register registers a component into the component database (as the
|
||||
// child of a given parent). Passing a nil component or parent is an error.
|
||||
// Registering multiple components with the same ID is also an error.
|
||||
|
@ -291,8 +255,19 @@ func (g *Game) Register(component, parent interface{}) error {
|
|||
}
|
||||
g.dbmu.Lock()
|
||||
defer g.dbmu.Unlock()
|
||||
// preorderWalk goes in the right order for registering.
|
||||
return preorderWalk(component, parent, g.registerOne)
|
||||
return g.registerRecursive(component, parent)
|
||||
}
|
||||
|
||||
func (g *Game) registerRecursive(component, parent interface{}) error {
|
||||
if err := g.registerOne(component, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
if sc, ok := component.(Scanner); ok {
|
||||
return sc.Scan(func(x interface{}) error {
|
||||
return g.registerRecursive(x, component)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) registerOne(component, parent interface{}) error {
|
||||
|
@ -335,12 +310,21 @@ func (g *Game) Unregister(component interface{}) {
|
|||
return
|
||||
}
|
||||
g.dbmu.Lock()
|
||||
// postorderWalk goes in the right order for unregistering.
|
||||
postorderWalk(component, nil, g.unregisterOne)
|
||||
g.unregisterRecursive(component)
|
||||
g.dbmu.Unlock()
|
||||
}
|
||||
|
||||
func (g *Game) unregisterOne(component, _ interface{}) error {
|
||||
func (g *Game) unregisterRecursive(component interface{}) {
|
||||
if sc, ok := component.(Scanner); ok {
|
||||
sc.Scan(func(x interface{}) error {
|
||||
g.unregisterRecursive(x)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
g.unregisterOne(component)
|
||||
}
|
||||
|
||||
func (g *Game) unregisterOne(component interface{}) {
|
||||
// unregister from g.byAB, using g.par to trace the path
|
||||
ct := reflect.TypeOf(component)
|
||||
for _, b := range Behaviours {
|
||||
|
@ -361,9 +345,10 @@ func (g *Game) unregisterOne(component, _ interface{}) error {
|
|||
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
||||
delete(g.byID, id.Ident())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) String() string { return "Game" }
|
||||
|
||||
// --------- Helper stuff ---------
|
||||
|
||||
type abKey struct {
|
||||
|
|
|
@ -57,3 +57,5 @@ func (r *ImageRef) Load(assets fs.FS) error {
|
|||
imageCache[assetKey{assets, r.Path}] = r.image
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ImageRef) String() string { return "ImageRef{" + r.Path + "}" }
|
||||
|
|
|
@ -43,6 +43,8 @@ func (p *Parallax) Scan(visit func(interface{}) error) error {
|
|||
return visit(p.Child)
|
||||
}
|
||||
|
||||
func (p *Parallax) String() string { return "Parallax" }
|
||||
|
||||
// Transform returns a GeoM translation of Factor * camera.Centre.
|
||||
func (p *Parallax) Transform() (opts ebiten.DrawImageOptions) {
|
||||
x, y := geom.CFloat(p.camera.Centre)
|
||||
|
|
|
@ -125,6 +125,8 @@ func (m *PrismMap) Scan(visit func(interface{}) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *PrismMap) String() string { return "PrismMap" }
|
||||
|
||||
// Transform retrurns a translation by the draw offset.
|
||||
func (m *PrismMap) Transform() (opts ebiten.DrawImageOptions) {
|
||||
opts.GeoM.Translate(geom.CFloat(m.DrawOffset))
|
||||
|
|
|
@ -88,23 +88,26 @@ func (g *Game) cmdTree(dst io.Writer, argv []string) {
|
|||
return
|
||||
}
|
||||
}
|
||||
PreorderWalk(c, func(w, _ interface{}) error {
|
||||
g.printTreeRecursive(dst, 0, c)
|
||||
}
|
||||
|
||||
func (g *Game) printTreeRecursive(dst io.Writer, depth int, c interface{}) {
|
||||
indent := ""
|
||||
l := 0
|
||||
for p := w; p != c; p = g.par[p] {
|
||||
l++
|
||||
if depth > 0 {
|
||||
indent = strings.Repeat(" ", depth-1) + "↳ "
|
||||
}
|
||||
if l > 0 {
|
||||
indent = strings.Repeat(" ", l-1) + "↳ "
|
||||
}
|
||||
i, ok := w.(Identifier)
|
||||
i, ok := c.(Identifier)
|
||||
if ok {
|
||||
fmt.Fprintf(dst, "%s%T %q\n", indent, w, i.Ident())
|
||||
fmt.Fprintf(dst, "%s%v %q\n", indent, c, i.Ident())
|
||||
} else {
|
||||
fmt.Fprintf(dst, "%s%T\n", indent, w)
|
||||
fmt.Fprintf(dst, "%s%v\n", indent, c)
|
||||
}
|
||||
if sc, ok := c.(Scanner); ok {
|
||||
sc.Scan(func(x interface{}) error {
|
||||
g.printTreeRecursive(dst, depth+1, x)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) cmdQuery(dst io.Writer, argv []string) {
|
||||
|
|
|
@ -43,6 +43,8 @@ func (s *Scene) Scan(visit func(interface{}) error) error {
|
|||
return visit(s.Child)
|
||||
}
|
||||
|
||||
func (s *Scene) String() string { return "Scene" }
|
||||
|
||||
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
|
||||
// After Load, Scene is usable.
|
||||
// This is mostly useful for scenes that refer to other scenes, e.g.
|
||||
|
@ -83,3 +85,5 @@ func (r *SceneRef) Load(assets fs.FS) error {
|
|||
func (r *SceneRef) Save() error {
|
||||
return SaveGobz(r.Scene, filepath.Base(r.Path))
|
||||
}
|
||||
|
||||
func (r *SceneRef) String() string { return "SceneRef{" + r.Path + "}" }
|
||||
|
|
|
@ -57,3 +57,5 @@ func (s *Sheet) SubImage(i int) *ebiten.Image {
|
|||
r := image.Rectangle{p, p.Add(s.CellSize)}
|
||||
return s.Src.Image().SubImage(r).(*ebiten.Image)
|
||||
}
|
||||
|
||||
func (s *Sheet) String() string { return "Sheet" }
|
||||
|
|
Loading…
Reference in a new issue