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
|
a.game = g
|
||||||
return nil
|
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)
|
return visit(c.Child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Camera) String() string { return "Camera@" + c.Centre.String() }
|
||||||
|
|
||||||
// Transform returns the camera transform.
|
// Transform returns the camera transform.
|
||||||
func (c *Camera) Transform() (opts ebiten.DrawImageOptions) {
|
func (c *Camera) Transform() (opts ebiten.DrawImageOptions) {
|
||||||
opts.GeoM.Translate(geom.CFloat(c.Centre.Mul(-1)))
|
opts.GeoM.Translate(geom.CFloat(c.Centre.Mul(-1)))
|
||||||
|
|
|
@ -18,6 +18,8 @@ func (c Container) Scan(visit func(interface{}) error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Container) String() string { return "Container" }
|
||||||
|
|
||||||
// Register records component in the slice, if parent is the container.
|
// Register records component in the slice, if parent is the container.
|
||||||
func (c *Container) Register(component, parent interface{}) error {
|
func (c *Container) Register(component, parent interface{}) error {
|
||||||
if parent == c {
|
if parent == c {
|
||||||
|
|
|
@ -120,6 +120,8 @@ func (d *DrawDAG) Scan(visit func(interface{}) error) error {
|
||||||
return visit(d.Child)
|
return visit(d.Child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DrawDAG) String() string { return "DrawDAG" }
|
||||||
|
|
||||||
// Update checks for any changes to descendants, and updates its internal
|
// Update checks for any changes to descendants, and updates its internal
|
||||||
// data structures accordingly.
|
// data structures accordingly.
|
||||||
func (d *DrawDAG) Update() error {
|
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
|
var sb strings.Builder
|
||||||
sb.WriteString("digraph {\n")
|
sb.WriteString("digraph {\n")
|
||||||
for v, e := range d.out {
|
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 {
|
func (d *DrawDFS) Scan(visit func(interface{}) error) error {
|
||||||
return visit(d.Child)
|
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)
|
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.
|
// Load loads a component and all subcomponents recursively.
|
||||||
// Note that this method does not implement Loader.
|
// Note that this method does not implement Loader.
|
||||||
func (g *Game) Load(component interface{}, assets fs.FS) error {
|
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
|
// Build the component databases
|
||||||
startBuild := time.Now()
|
startBuild := time.Now()
|
||||||
g.dbmu.Lock()
|
if err := g.build(); err != nil {
|
||||||
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 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.dbmu.Unlock()
|
|
||||||
log.Printf("finished building db in %v", time.Since(startBuild))
|
log.Printf("finished building db in %v", time.Since(startBuild))
|
||||||
|
|
||||||
// Prepare all the Preppers
|
// Prepare all the Preppers
|
||||||
|
@ -277,6 +232,15 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
||||||
return nil
|
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
|
// Register registers a component into the component database (as the
|
||||||
// child of a given parent). Passing a nil component or parent is an error.
|
// 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.
|
// 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()
|
g.dbmu.Lock()
|
||||||
defer g.dbmu.Unlock()
|
defer g.dbmu.Unlock()
|
||||||
// preorderWalk goes in the right order for registering.
|
return g.registerRecursive(component, parent)
|
||||||
return preorderWalk(component, parent, g.registerOne)
|
}
|
||||||
|
|
||||||
|
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 {
|
func (g *Game) registerOne(component, parent interface{}) error {
|
||||||
|
@ -335,12 +310,21 @@ func (g *Game) Unregister(component interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.dbmu.Lock()
|
g.dbmu.Lock()
|
||||||
// postorderWalk goes in the right order for unregistering.
|
g.unregisterRecursive(component)
|
||||||
postorderWalk(component, nil, g.unregisterOne)
|
|
||||||
g.dbmu.Unlock()
|
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
|
// unregister from g.byAB, using g.par to trace the path
|
||||||
ct := reflect.TypeOf(component)
|
ct := reflect.TypeOf(component)
|
||||||
for _, b := range Behaviours {
|
for _, b := range Behaviours {
|
||||||
|
@ -361,9 +345,10 @@ func (g *Game) unregisterOne(component, _ interface{}) error {
|
||||||
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
||||||
delete(g.byID, id.Ident())
|
delete(g.byID, id.Ident())
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Game) String() string { return "Game" }
|
||||||
|
|
||||||
// --------- Helper stuff ---------
|
// --------- Helper stuff ---------
|
||||||
|
|
||||||
type abKey struct {
|
type abKey struct {
|
||||||
|
|
|
@ -57,3 +57,5 @@ func (r *ImageRef) Load(assets fs.FS) error {
|
||||||
imageCache[assetKey{assets, r.Path}] = r.image
|
imageCache[assetKey{assets, r.Path}] = r.image
|
||||||
return nil
|
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)
|
return visit(p.Child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parallax) String() string { return "Parallax" }
|
||||||
|
|
||||||
// Transform returns a GeoM translation of Factor * camera.Centre.
|
// Transform returns a GeoM translation of Factor * camera.Centre.
|
||||||
func (p *Parallax) Transform() (opts ebiten.DrawImageOptions) {
|
func (p *Parallax) Transform() (opts ebiten.DrawImageOptions) {
|
||||||
x, y := geom.CFloat(p.camera.Centre)
|
x, y := geom.CFloat(p.camera.Centre)
|
||||||
|
|
|
@ -125,6 +125,8 @@ func (m *PrismMap) Scan(visit func(interface{}) error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *PrismMap) String() string { return "PrismMap" }
|
||||||
|
|
||||||
// Transform retrurns a translation by the draw offset.
|
// Transform retrurns a translation by the draw offset.
|
||||||
func (m *PrismMap) Transform() (opts ebiten.DrawImageOptions) {
|
func (m *PrismMap) Transform() (opts ebiten.DrawImageOptions) {
|
||||||
opts.GeoM.Translate(geom.CFloat(m.DrawOffset))
|
opts.GeoM.Translate(geom.CFloat(m.DrawOffset))
|
||||||
|
|
|
@ -88,23 +88,26 @@ func (g *Game) cmdTree(dst io.Writer, argv []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PreorderWalk(c, func(w, _ interface{}) error {
|
g.printTreeRecursive(dst, 0, c)
|
||||||
indent := ""
|
}
|
||||||
l := 0
|
|
||||||
for p := w; p != c; p = g.par[p] {
|
func (g *Game) printTreeRecursive(dst io.Writer, depth int, c interface{}) {
|
||||||
l++
|
indent := ""
|
||||||
}
|
if depth > 0 {
|
||||||
if l > 0 {
|
indent = strings.Repeat(" ", depth-1) + "↳ "
|
||||||
indent = strings.Repeat(" ", l-1) + "↳ "
|
}
|
||||||
}
|
i, ok := c.(Identifier)
|
||||||
i, ok := w.(Identifier)
|
if ok {
|
||||||
if ok {
|
fmt.Fprintf(dst, "%s%v %q\n", indent, c, i.Ident())
|
||||||
fmt.Fprintf(dst, "%s%T %q\n", indent, w, i.Ident())
|
} else {
|
||||||
} else {
|
fmt.Fprintf(dst, "%s%v\n", indent, c)
|
||||||
fmt.Fprintf(dst, "%s%T\n", indent, w)
|
}
|
||||||
}
|
if sc, ok := c.(Scanner); ok {
|
||||||
return nil
|
sc.Scan(func(x interface{}) error {
|
||||||
})
|
g.printTreeRecursive(dst, depth+1, x)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) cmdQuery(dst io.Writer, argv []string) {
|
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)
|
return visit(s.Child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Scene) String() string { return "Scene" }
|
||||||
|
|
||||||
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
|
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
|
||||||
// After Load, Scene is usable.
|
// After Load, Scene is usable.
|
||||||
// This is mostly useful for scenes that refer to other scenes, e.g.
|
// 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 {
|
func (r *SceneRef) Save() error {
|
||||||
return SaveGobz(r.Scene, filepath.Base(r.Path))
|
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)}
|
r := image.Rectangle{p, p.Add(s.CellSize)}
|
||||||
return s.Src.Image().SubImage(r).(*ebiten.Image)
|
return s.Src.Image().SubImage(r).(*ebiten.Image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sheet) String() string { return "Sheet" }
|
||||||
|
|
Loading…
Reference in a new issue