a nicer solution :)

This commit is contained in:
Josh Deprez 2021-09-01 13:28:07 +10:00
parent 228f8b9b9a
commit 91785fb6c0
4 changed files with 35 additions and 80 deletions

View file

@ -17,13 +17,11 @@ var (
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem() ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem() DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem() DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem()
DrawUpdaterType = reflect.TypeOf((*DrawUpdater)(nil)).Elem()
HiderType = reflect.TypeOf((*Hider)(nil)).Elem() HiderType = reflect.TypeOf((*Hider)(nil)).Elem()
IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem() IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem()
LoaderType = reflect.TypeOf((*Loader)(nil)).Elem() LoaderType = reflect.TypeOf((*Loader)(nil)).Elem()
PrepperType = reflect.TypeOf((*Prepper)(nil)).Elem() PrepperType = reflect.TypeOf((*Prepper)(nil)).Elem()
ScannerType = reflect.TypeOf((*Scanner)(nil)).Elem() ScannerType = reflect.TypeOf((*Scanner)(nil)).Elem()
ScenerType = reflect.TypeOf((*Scener)(nil)).Elem()
SaverType = reflect.TypeOf((*Saver)(nil)).Elem() SaverType = reflect.TypeOf((*Saver)(nil)).Elem()
TransformerType = reflect.TypeOf((*Transformer)(nil)).Elem() TransformerType = reflect.TypeOf((*Transformer)(nil)).Elem()
UpdaterType = reflect.TypeOf((*Updater)(nil)).Elem() UpdaterType = reflect.TypeOf((*Updater)(nil)).Elem()
@ -35,13 +33,11 @@ var (
ColliderType, ColliderType,
DisablerType, DisablerType,
DrawerType, DrawerType,
DrawUpdaterType,
HiderType, HiderType,
IdentifierType, IdentifierType,
LoaderType, LoaderType,
PrepperType, PrepperType,
ScannerType, ScannerType,
ScenerType,
SaverType, SaverType,
TransformerType, TransformerType,
UpdaterType, UpdaterType,
@ -81,13 +77,6 @@ type Drawer interface {
DrawOrder() float64 DrawOrder() float64
} }
// DrawUpdater components can be both drawn and updated.
// Same comments as for Drawer and Updater.
type DrawUpdater interface {
Drawer
Updater
}
// Hider components can be hidden. // Hider components can be hidden.
type Hider interface { type Hider interface {
IsHidden() bool IsHidden() bool
@ -121,33 +110,6 @@ type Scanner interface {
Scan() []interface{} Scan() []interface{}
} }
// Scener components are a scene (Scene or SceneRef).
type Scener interface {
// Q: Why not make Scene able to load itself?
// A: Having separate types makes it easier to reason about what is loading
// what. There is less ambiguity about what "save" means (the contents of
// the scene, or the path to the file?) Additionally, the gob decoder
// decodes over existing fields, which could lead to some fun bugs.
//
// Q: Why not make Scener a small interface, e.g. with just Scene() ?
// A: Everything in the engine would then need to type switch for Scener or
// SceneRef, i.e.
// switch x := i.(type) {
// case Drawer:
// i.Draw(screen, opts)
// case Scener:
// i.Scene().Draw(screen, opts)
// }
// It seems cleaner to let the engine assert only for the interface it
// needs at that moment.
Bounder
Disabler
Hider
Identifier
Scanner
}
// Saver components can be saved to disk. // Saver components can be saved to disk.
type Saver interface { type Saver interface {
Save() error Save() error

View file

@ -2,29 +2,34 @@ package engine
import ( import (
"encoding/gob" "encoding/gob"
"image"
"io/fs" "io/fs"
"path/filepath" "path/filepath"
) )
var ( var (
// Ensure Scene satisfies Scener. _ scener = &Scene{}
_ Scener = &Scene{}
// Ensure SceneRef satisfies interfaces.
_ interface { _ interface {
Loader Loader
Scener Saver
scener
} = &SceneRef{} } = &SceneRef{}
) )
type scener interface {
Bounder
Disabler
Hider
Identifier
Scanner
}
func init() { func init() {
gob.Register(&Scene{}) gob.Register(&Scene{})
gob.Register(&SceneRef{}) gob.Register(&SceneRef{})
} }
// Scene just contains a bunch of components. // Scene contains a bunch of components.
type Scene struct { type Scene struct {
ID ID
Bounds // world coordinates Bounds // world coordinates
@ -48,7 +53,18 @@ func (s *Scene) Scan() []interface{} { return s.Components }
type SceneRef struct { type SceneRef struct {
Path string Path string
scene *Scene // not exported for gob reasons *Scene // not gob encoded
}
// GobDecode saves the byte slice as Path.
func (r *SceneRef) GobDecode(b []byte) error {
r.Path = string(b)
return nil
}
// GobEncode returns Path as a byte slice.
func (r *SceneRef) GobEncode() ([]byte, error) {
return []byte(r.Path), nil
} }
// Load loads the scene from the file. // Load loads the scene from the file.
@ -57,39 +73,11 @@ func (r *SceneRef) Load(assets fs.FS) error {
if err := LoadGobz(sc, assets, r.Path); err != nil { if err := LoadGobz(sc, assets, r.Path); err != nil {
return err return err
} }
r.scene = sc r.Scene = sc
return nil return nil
} }
// Save saves the scene to a file in the current directory. // Save saves the scene to a file in the current directory.
func (r *SceneRef) Save() error { return SaveGobz(r.scene, filepath.Base(r.Path)) } func (r *SceneRef) Save() error {
return SaveGobz(r.Scene, filepath.Base(r.Path))
// The rest of the methods forward to r.scene, as such they will }
// panic if the scene isn't loaded.
// BoundingRect returns the Bounds from the scene.
func (r SceneRef) BoundingRect() image.Rectangle { return r.scene.BoundingRect() }
// IsDisabled returns the value of IsDisabled from the scene.
func (r SceneRef) IsDisabled() bool { return r.scene.IsDisabled() }
// Disable calls Disable on the scene.
func (r SceneRef) Disable() { r.scene.Disable() }
// Enable calls Enable on the scene.
func (r SceneRef) Enable() { r.scene.Enable() }
// IsHidden returns the value of IsHidden from the scene.
func (r SceneRef) IsHidden() bool { return r.scene.IsHidden() }
// Hide calls Hide on the scene.
func (r SceneRef) Hide() { r.scene.Hide() }
// Show calls Show on the scene.
func (r SceneRef) Show() { r.scene.Show() }
// Ident returns the value of Ident from the scene.
func (r SceneRef) Ident() string { return r.scene.Ident() }
// Scan returns the components in the scene.
func (r SceneRef) Scan() []interface{} { return r.scene.Scan() }

Binary file not shown.

View file

@ -14,9 +14,14 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
const (
enableCPUProfile = false
rewriteLevel1 = false
)
func main() { func main() {
// Change to true to enable cpu profile // Change to true to enable cpu profile
if false && runtime.GOOS != "js" { if enableCPUProfile && runtime.GOOS != "js" {
f, err := os.Create("cpuprofile.pprof") f, err := os.Create("cpuprofile.pprof")
if err != nil { if err != nil {
log.Fatal("could not create CPU profile: ", err) log.Fatal("could not create CPU profile: ", err)
@ -33,7 +38,7 @@ func main() {
ebiten.SetWindowTitle("TODO") ebiten.SetWindowTitle("TODO")
// Change to true to rewrite level1.gobz // Change to true to rewrite level1.gobz
if false && runtime.GOOS != "js" { if rewriteLevel1 && runtime.GOOS != "js" {
writeLevel1() writeLevel1()
} }