WIP: Scan now uses visitor pattern

This commit is contained in:
Josh Deprez 2021-09-22 15:48:02 +10:00
parent 83c3182be1
commit fe2558b2c1
16 changed files with 143 additions and 28 deletions

View file

@ -52,7 +52,10 @@ func (b *Billboard) Prepare(g *Game) error {
}
// Scan returns a slice containing Src.
func (b *Billboard) Scan() []interface{} { return []interface{}{&b.Src} }
//func (b *Billboard) Scan() []interface{} { return []interface{}{&b.Src} }
func (b *Billboard) Scan(visit func(interface{}) error) error {
return visit(&b.Src)
}
func (b *Billboard) String() string {
return fmt.Sprintf("Billboard@%v", b.Pos)

View file

@ -86,7 +86,10 @@ func (c *Camera) Prepare(game *Game) error {
}
// Scan returns s.Child.
func (c *Camera) Scan() []interface{} { return []interface{}{c.Child} }
//func (c *Camera) Scan() []interface{} { return []interface{}{c.Child} }
func (c *Camera) Scan(visit func(interface{}) error) error {
return visit(c.Child)
}
// Transform returns the camera transform.
func (c *Camera) Transform() (opts ebiten.DrawImageOptions) {

View file

@ -1,10 +1,23 @@
package engine
var _ interface {
Registrar
Scanner
} = &Container{}
// Container contains many components.
type Container []interface{}
// Scan returns c.
func (c Container) Scan() []interface{} { return c }
//func (c Container) Scan() []interface{} { return c }
func (c Container) Scan(visit func(interface{}) error) error {
for _, x := range c {
if err := visit(x); err != nil {
return err
}
}
return nil
}
// Register records component in the slice, if parent is the container.
func (c *Container) Register(component, parent interface{}) error {

View file

@ -114,7 +114,10 @@ func (d *DrawDAG) Prepare(game *Game) error {
return d.Register(d, nil)
}
func (d *DrawDAG) Scan() []interface{} { return []interface{}{d.Child} }
//func (d *DrawDAG) Scan() []interface{} { return []interface{}{d.Child} }
func (d *DrawDAG) Scan(visit func(interface{}) error) error {
return visit(d.Child)
}
// Update checks for any changes to descendants, and updates its internal
// data structures accordingly.
@ -160,11 +163,15 @@ func (d *DrawDAG) Register(component, _ interface{}) error {
return nil
}
if sc, ok := component.(Scanner); ok {
for _, x := range sc.Scan() {
/*for _, x := range sc.Scan() {
if err := d.Register(x, nil); err != nil {
return err
}
}*/
scv := func(x interface{}) error {
return d.Register(x, nil)
}
return sc.Scan(scv)
}
return nil
}
@ -232,9 +239,14 @@ func (d *DrawDAG) Unregister(component interface{}) {
return
}
if sc, ok := component.(Scanner); ok {
for _, x := range sc.Scan() {
/*for _, x := range sc.Scan() {
d.Unregister(x)
}*/
scv := func(x interface{}) error {
d.Unregister(x)
return nil
}
sc.Scan(scv)
}
}

View file

@ -46,10 +46,18 @@ func (d *DrawDFS) draw(component interface{}, screen *ebiten.Image, opts ebiten.
}
// Has subcomponents? recurse
if sc, ok := component.(Scanner); ok {
for _, ch := range sc.Scan() {
/*for _, ch := range sc.Scan() {
d.draw(ch, screen, opts)
}*/
scv := func(x interface{}) error {
d.draw(x, screen, opts)
return nil
}
sc.Scan(scv)
}
}
func (d *DrawDFS) Scan() []interface{} { return []interface{}{d.Child} }
//func (d *DrawDFS) Scan() []interface{} { return []interface{}{d.Child} }
func (d *DrawDFS) Scan(visit func(interface{}) error) error {
return visit(d.Child)
}

View file

@ -75,11 +75,15 @@ func (g *Game) updateRecursive(c interface{}) error {
return nil
}
if sc, ok := c.(Scanner); ok {
for _, x := range sc.Scan() {
/*for _, x := range sc.Scan() {
if err := g.updateRecursive(x); err != nil {
return err
}
}
*/
if err := sc.Scan(g.updateRecursive); err != nil {
return err
}
}
if c == g { // prevent infinite recursion
return nil
@ -167,7 +171,10 @@ func (g *Game) Query(ancestor interface{}, behaviour reflect.Type) map[interface
}
// Scan returns g.Root.
func (g *Game) Scan() []interface{} { return []interface{}{g.Root} }
//func (g *Game) Scan() []interface{} { return []interface{}{g.Root} }
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
@ -185,12 +192,15 @@ func preorderWalk(component, parent interface{}, visit func(component, parent in
if !ok {
return nil
}
for _, c := range sc.Scan() {
/*for _, c := range sc.Scan() {
if err := preorderWalk(c, component, visit); err != nil {
return err
}
}*/
scv := func(c interface{}) error {
return preorderWalk(c, component, visit)
}
return nil
return sc.Scan(scv)
}
// PostorderWalk calls visit with every component and its parent, reachable from
@ -203,10 +213,16 @@ func PostorderWalk(component interface{}, visit func(component, parent interface
func postorderWalk(component, parent interface{}, visit func(component, parent interface{}) error) error {
if sc, ok := component.(Scanner); ok {
for _, c := range sc.Scan() {
scv := func(c interface{}) error {
return postorderWalk(c, component, visit)
}
/*for _, c := range sc.Scan() {
if err := postorderWalk(c, component, visit); err != nil {
return err
}
}*/
if err := sc.Scan(scv); err != nil {
return err
}
}
return visit(component, parent)

View file

@ -144,10 +144,12 @@ type Saver interface {
}
// Scanner components can be scanned. It is called when the game tree is walked
// (such as when the game component database is constructed).
// Scan should return a slice containing all immediate subcomponents.
// (such as when the game component database is constructed) and various times
// afterward (such as during Update).
// Scan should visit each immediate subcomponent, aborting early if an error is
// returned from the visitor.
type Scanner interface {
Scan() []interface{}
Scan(visit func(interface{}) error) error
}
// Transformer components can provide draw options to apply to themselves and

View file

@ -39,7 +39,10 @@ func (p *Parallax) Prepare(game *Game) error {
}
// Scan returns the child component.
func (p *Parallax) Scan() []interface{} { return []interface{}{p.Child} }
//func (p *Parallax) Scan() []interface{} { return []interface{}{p.Child} }
func (p *Parallax) Scan(visit func(interface{}) error) error {
return visit(p.Child)
}
// Transform returns a GeoM translation of Factor * camera.Centre.
func (p *Parallax) Transform() (opts ebiten.DrawImageOptions) {

View file

@ -113,13 +113,24 @@ func (m *PrismMap) Prepare(g *Game) error {
}
// Scan returns the Sheet and all the Prisms.
func (m *PrismMap) Scan() []interface{} {
/*func (m *PrismMap) Scan() []interface{} {
c := make([]interface{}, 1, len(m.Map)+1)
c[0] = &m.Sheet
for _, prism := range m.Map {
c = append(c, prism)
}
return c
}*/
func (m *PrismMap) Scan(visit func(interface{}) error) error {
if err := visit(&m.Sheet); err != nil {
return err
}
for _, prism := range m.Map {
if err := visit(prism); err != nil {
return err
}
}
return nil
}
// Transform retrurns a translation by the draw offset.

View file

@ -38,7 +38,10 @@ type Scene struct {
Hides
}
func (s *Scene) Scan() []interface{} { return []interface{}{s.Child} }
//func (s *Scene) Scan() []interface{} { return []interface{}{s.Child} }
func (s *Scene) Scan(visit func(interface{}) error) error {
return visit(s.Child)
}
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
// After Load, Scene is usable.

View file

@ -47,7 +47,10 @@ func (s *Sheet) Prepare(*Game) error {
}
// Scan returns the Src.
func (s *Sheet) Scan() []interface{} { return []interface{}{&s.Src} }
//func (s *Sheet) Scan() []interface{} { return []interface{}{&s.Src} }
func (s *Sheet) Scan(visit func(interface{}) error) error {
return visit(&s.Src)
}
// SubImage returns an *ebiten.Image corresponding to the given cell index.
func (s *Sheet) SubImage(i int) *ebiten.Image {

View file

@ -41,11 +41,17 @@ func (s *Sprite) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
}
// Scan returns the Actor and the Sheet.
func (s *Sprite) Scan() []interface{} {
/*func (s *Sprite) Scan() []interface{} {
return []interface{}{
&s.Actor,
&s.Sheet,
}
}*/
func (s *Sprite) Scan(visit func(interface{}) error) error {
if err := visit(&s.Actor); err != nil {
return err
}
return visit(&s.Sheet)
}
// SetAnim sets the Anim to use for the sprite. If it is not the same as the

View file

@ -100,13 +100,24 @@ func (t *Tilemap) Load(fs.FS) error {
}
// Scan returns a slice containing Src and all non-nil tiles.
func (t *Tilemap) Scan() []interface{} {
/*func (t *Tilemap) Scan() []interface{} {
c := make([]interface{}, 1, len(t.Map)+1)
c[0] = &t.Sheet
for _, tile := range t.Map {
c = append(c, tile)
}
return c
}*/
func (t *Tilemap) Scan(visit func(interface{}) error) error {
if err := visit(&t.Sheet); err != nil {
return err
}
for _, tile := range t.Map {
if err := visit(tile); err != nil {
return err
}
}
return nil
}
// Transform returns a translation by t.Offset.
@ -152,4 +163,7 @@ type AnimatedTile struct {
func (a *AnimatedTile) Cell() int { return a.anim.Cell() }
// Scan returns a.anim.
func (a *AnimatedTile) Scan() []interface{} { return []interface{}{a.anim} }
//func (a *AnimatedTile) Scan() []interface{} { return []interface{}{a.anim} }
func (a *AnimatedTile) Scan(visit func(interface{}) error) error {
return visit(a.anim)
}

View file

@ -61,6 +61,7 @@ func (w *Wall) CollidesWith(b geom.Box) bool {
}
// Scan returns the Sheet and all WallUnits.
/*
func (w *Wall) Scan() []interface{} {
c := make([]interface{}, 1, len(w.Units)+1)
c[0] = &w.Sheet
@ -69,6 +70,18 @@ func (w *Wall) Scan() []interface{} {
}
return c
}
*/
func (w *Wall) Scan(visit func(interface{}) error) error {
if err := visit(&w.Sheet); err != nil {
return err
}
for _, unit := range w.Units {
if err := visit(unit); err != nil {
return err
}
}
return nil
}
// Prepare makes sure all WallUnits know about Wall and where they are, for
// drawing.
@ -103,7 +116,10 @@ func (u *WallUnit) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
}
// Scan returns the Tile.
func (u *WallUnit) Scan() []interface{} { return []interface{}{u.Tile} }
//func (u *WallUnit) Scan() []interface{} { return []interface{}{u.Tile} }
func (u *WallUnit) Scan(visit func(interface{}) error) error {
return visit(u.Tile)
}
func (u *WallUnit) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat(

View file

@ -270,8 +270,9 @@ func (aw *Awakeman) Prepare(game *engine.Game) error {
return nil
}
func (aw *Awakeman) Scan() []interface{} {
return []interface{}{&aw.Sprite}
//func (aw *Awakeman) Scan() []interface{} { return []interface{}{&aw.Sprite} }
func (aw *Awakeman) Scan(visit func(interface{}) error) error {
return visit(&aw.Sprite)
}
func (aw *Awakeman) String() string {

View file

@ -55,8 +55,9 @@ func NewBubble(pos geom.Int3) *Bubble {
}
}
func (b *Bubble) Scan() []interface{} {
return []interface{}{&b.Sprite}
//func (b *Bubble) Scan() []interface{} { return []interface{}{&b.Sprite} }
func (b *Bubble) Scan(visit func(interface{}) error) error {
return visit(&b.Sprite)
}
func (b *Bubble) String() string {