a nicer solution :)
This commit is contained in:
parent
228f8b9b9a
commit
91785fb6c0
4 changed files with 35 additions and 80 deletions
|
@ -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
|
||||||
|
|
|
@ -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.
9
main.go
9
main.go
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue