change how walk works

This commit is contained in:
Josh Deprez 2021-08-01 16:41:10 +10:00 committed by Josh Deprez
parent 51d9a69a4b
commit cd7b0fae99
3 changed files with 47 additions and 21 deletions

View file

@ -2,6 +2,7 @@ package engine
import ( import (
"encoding/gob" "encoding/gob"
"errors"
"fmt" "fmt"
"math" "math"
"os" "os"
@ -12,6 +13,7 @@ import (
) )
func init() { func init() {
gob.Register(GobDumper{})
gob.Register(PerfDisplay{}) gob.Register(PerfDisplay{})
} }
@ -30,19 +32,32 @@ func (PerfDisplay) Z() float64 {
// GobDumper waits for a given key combo, then dumps the game into a gob file // GobDumper waits for a given key combo, then dumps the game into a gob file
// in the current directory. // in the current directory.
type GobDumper struct { type GobDumper struct {
combo []ebiten.Key KeyCombo []ebiten.Key
game ebiten.Game
game *Game
} }
func (d GobDumper) Update() error { func (d *GobDumper) Scan(g *Game) []interface{} {
for _, key := range d.combo { d.game = g
return nil
}
func (d *GobDumper) Update() error {
for _, key := range d.KeyCombo {
if !ebiten.IsKeyPressed(key) { if !ebiten.IsKeyPressed(key) {
return nil return nil
} }
} }
if d.game == nil {
return errors.New("nil d.game in GobDumper.Update")
}
f, err := os.Create(time.Now().Format("20060102030405.gob")) f, err := os.Create(time.Now().Format("20060102030405.gob"))
if err != nil { if err != nil {
return err return err
} }
return gob.NewEncoder(f).Encode(d.game) defer f.Close()
if err := gob.NewEncoder(f).Encode(d.game); err != nil {
return err
}
return f.Close()
} }

View file

@ -29,7 +29,6 @@ type Game struct {
ScreenHeight int ScreenHeight int
Scene *Scene Scene *Scene
allComponents []interface{}
componentsByID map[string]interface{} componentsByID map[string]interface{}
} }
@ -51,11 +50,21 @@ func (g *Game) Update() error {
// Component returns the component with a given ID. // Component returns the component with a given ID.
func (g *Game) Component(id string) interface{} { return g.componentsByID[id] } func (g *Game) Component(id string) interface{} { return g.componentsByID[id] }
// Walk calls visit with every component, for as long as visit returns true. // Walk calls v with every component, for as long as visit returns true.
func (g *Game) Walk(visit func(interface{}) bool) { func (g *Game) Walk(v func(interface{}) bool) {
for _, c := range g.allComponents { g.walk(g.Scene, v)
if !visit(c) { }
return
func (g *Game) walk(c interface{}, v func(interface{}) bool) {
if !v(c) {
return
}
if sc, ok := c.(Scanner); ok {
for _, c := range sc.Scan(g) {
if !v(c) {
return
}
g.walk(c, v)
} }
} }
} }
@ -63,16 +72,11 @@ func (g *Game) Walk(visit func(interface{}) bool) {
// Build builds the component database. // Build builds the component database.
func (g *Game) Build() { func (g *Game) Build() {
byID := make(map[string]interface{}) byID := make(map[string]interface{})
all := []interface{}{g.Scene} g.walk(g.Scene, func(c interface{}) bool {
for offset := 0; offset < len(all); offset++ { if id, ok := c.(IDer); ok {
head := all[offset] byID[id.ID()] = c
if id, ok := head.(IDer); ok {
byID[id.ID()] = head
} }
if sc, ok := head.(Scanner); ok { return true
all = append(all, sc.Scan(g)) })
}
}
g.allComponents = all
g.componentsByID = byID g.componentsByID = byID
} }

View file

@ -75,6 +75,12 @@ func main() {
ScreenWidth: screenWidth, ScreenWidth: screenWidth,
Scene: &engine.Scene{ Scene: &engine.Scene{
Components: []interface{}{ Components: []interface{}{
&engine.GobDumper{
KeyCombo: []ebiten.Key{
ebiten.KeyControl,
ebiten.KeyD,
},
},
&engine.Tilemap{ &engine.Tilemap{
Map: tiles, Map: tiles,
Src: engine.ImageRef{Path: "assets/boxes.png"}, Src: engine.ImageRef{Path: "assets/boxes.png"},
@ -84,6 +90,7 @@ func main() {
}, },
}, },
} }
game.Build()
if err := ebiten.RunGame(game); err != nil { if err := ebiten.RunGame(game); err != nil {
log.Fatalf("Game error: %v", err) log.Fatalf("Game error: %v", err)