2021-08-05 12:26:41 +10:00
|
|
|
package engine
|
|
|
|
|
2021-08-05 12:33:23 +10:00
|
|
|
import (
|
|
|
|
"image"
|
2021-08-23 10:09:49 +10:00
|
|
|
"io/fs"
|
2021-08-27 15:39:10 +10:00
|
|
|
"reflect"
|
2021-08-05 12:33:23 +10:00
|
|
|
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
|
|
)
|
|
|
|
|
2021-08-27 15:39:10 +10:00
|
|
|
// Reflection types used for queries... Is there a better way?
|
|
|
|
var (
|
|
|
|
// TypeOf(pointer to interface).Elem() is "idiomatic" -
|
|
|
|
// see https://pkg.go.dev/reflect#example-TypeOf
|
|
|
|
AnimerType = reflect.TypeOf((*Animer)(nil)).Elem()
|
|
|
|
BounderType = reflect.TypeOf((*Bounder)(nil)).Elem()
|
|
|
|
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
|
|
|
|
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
|
|
|
|
DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem()
|
|
|
|
DrawUpdaterType = reflect.TypeOf((*DrawUpdater)(nil)).Elem()
|
|
|
|
HiderType = reflect.TypeOf((*Hider)(nil)).Elem()
|
|
|
|
IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem()
|
|
|
|
LoaderType = reflect.TypeOf((*Loader)(nil)).Elem()
|
|
|
|
ParallaxScalerType = reflect.TypeOf((*ParallaxScaler)(nil)).Elem()
|
|
|
|
PrepperType = reflect.TypeOf((*Prepper)(nil)).Elem()
|
|
|
|
ScannerType = reflect.TypeOf((*Scanner)(nil)).Elem()
|
|
|
|
ScenerType = reflect.TypeOf((*Scener)(nil)).Elem()
|
|
|
|
SaverType = reflect.TypeOf((*Saver)(nil)).Elem()
|
|
|
|
UpdaterType = reflect.TypeOf((*Updater)(nil)).Elem()
|
|
|
|
|
|
|
|
// Behaviours lists all the behaviours that can be queried with Game.Query.
|
|
|
|
Behaviours = []reflect.Type{
|
|
|
|
AnimerType,
|
|
|
|
BounderType,
|
|
|
|
ColliderType,
|
|
|
|
DisablerType,
|
|
|
|
DrawerType,
|
|
|
|
DrawUpdaterType,
|
|
|
|
HiderType,
|
|
|
|
IdentifierType,
|
|
|
|
LoaderType,
|
|
|
|
ParallaxScalerType,
|
|
|
|
PrepperType,
|
|
|
|
ScannerType,
|
|
|
|
ScenerType,
|
|
|
|
SaverType,
|
|
|
|
UpdaterType,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2021-08-23 20:28:49 +10:00
|
|
|
// Animer components have a current frame index.
|
|
|
|
type Animer interface {
|
|
|
|
Updater
|
|
|
|
|
|
|
|
CurrentFrame() int
|
|
|
|
Reset()
|
|
|
|
}
|
|
|
|
|
2021-08-23 10:34:56 +10:00
|
|
|
// Bounder components have a bounding rectangle.
|
|
|
|
type Bounder interface {
|
|
|
|
BoundingRect() image.Rectangle
|
|
|
|
}
|
|
|
|
|
2021-08-05 12:33:23 +10:00
|
|
|
// Collider components have tangible form.
|
|
|
|
type Collider interface {
|
|
|
|
CollidesWith(image.Rectangle) bool
|
|
|
|
}
|
2021-08-05 12:26:41 +10:00
|
|
|
|
2021-08-23 11:10:46 +10:00
|
|
|
// Disabler components can be disabled.
|
|
|
|
type Disabler interface {
|
|
|
|
IsDisabled() bool
|
|
|
|
Disable()
|
|
|
|
Enable()
|
|
|
|
}
|
|
|
|
|
2021-08-05 12:26:41 +10:00
|
|
|
// Drawer components can draw themselves. Draw is called often.
|
2021-08-05 12:40:32 +10:00
|
|
|
// Each component is responsible for calling Draw on its child components
|
|
|
|
// (so that hiding the parent can hide the children, etc).
|
2021-08-05 12:26:41 +10:00
|
|
|
type Drawer interface {
|
2021-08-12 14:06:01 +10:00
|
|
|
Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions)
|
2021-08-18 14:25:51 +10:00
|
|
|
DrawOrder() float64
|
|
|
|
}
|
|
|
|
|
2021-08-20 16:46:26 +10:00
|
|
|
// DrawUpdater components can be both drawn and updated.
|
|
|
|
// Same comments as for Drawer and Updater.
|
|
|
|
type DrawUpdater interface {
|
|
|
|
Drawer
|
|
|
|
Updater
|
|
|
|
}
|
|
|
|
|
2021-08-23 10:34:56 +10:00
|
|
|
// Hider components can be hidden.
|
|
|
|
type Hider interface {
|
|
|
|
IsHidden() bool
|
|
|
|
Hide()
|
|
|
|
Show()
|
|
|
|
}
|
|
|
|
|
2021-08-05 12:26:41 +10:00
|
|
|
// Identifier components have a sense of self. This makes it easier for
|
|
|
|
// components to find and interact with one another.
|
|
|
|
type Identifier interface {
|
|
|
|
Ident() string
|
|
|
|
}
|
|
|
|
|
2021-08-20 15:01:31 +10:00
|
|
|
// Loader components get the chance to load themselves. This happens
|
|
|
|
// before preparation.
|
|
|
|
type Loader interface {
|
2021-08-23 10:09:49 +10:00
|
|
|
Load(fs.FS) error
|
2021-08-20 15:01:31 +10:00
|
|
|
}
|
|
|
|
|
2021-08-18 20:41:55 +10:00
|
|
|
// ParallaxScaler components have a scaling factor. This is used for
|
|
|
|
// parallax layers in a scene, and can be thought of as 1/distance.
|
|
|
|
type ParallaxScaler interface {
|
|
|
|
ParallaxFactor() float64
|
|
|
|
}
|
|
|
|
|
2021-08-05 12:26:41 +10:00
|
|
|
// Prepper components can be prepared. It is called after the component
|
|
|
|
// database has been populated but before the game is run. The component can
|
|
|
|
// store the reference to game, if needed, and also query the component database.
|
|
|
|
type Prepper interface {
|
2021-08-27 14:52:24 +10:00
|
|
|
Prepare(game *Game) error
|
2021-08-05 12:26:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
type Scanner interface {
|
|
|
|
Scan() []interface{}
|
|
|
|
}
|
|
|
|
|
2021-08-20 15:52:01 +10:00
|
|
|
// Scener components are a scene (Scene or SceneRef).
|
2021-08-20 15:01:31 +10:00
|
|
|
type Scener interface {
|
2021-08-31 13:41:26 +10:00
|
|
|
// 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.
|
2021-08-20 16:23:10 +10:00
|
|
|
|
2021-08-23 10:34:56 +10:00
|
|
|
Bounder
|
2021-08-23 11:10:46 +10:00
|
|
|
Disabler
|
2021-08-20 16:23:10 +10:00
|
|
|
Drawer
|
2021-08-23 10:34:56 +10:00
|
|
|
Hider
|
2021-08-20 16:23:10 +10:00
|
|
|
Identifier
|
|
|
|
Prepper
|
|
|
|
Scanner
|
|
|
|
Updater
|
2021-08-20 15:01:31 +10:00
|
|
|
}
|
|
|
|
|
2021-08-25 16:46:30 +10:00
|
|
|
// Saver components can be saved to disk.
|
|
|
|
type Saver interface {
|
|
|
|
Save() error
|
|
|
|
}
|
|
|
|
|
2021-08-05 12:26:41 +10:00
|
|
|
// Updater components can update themselves. Update is called repeatedly.
|
2021-08-05 12:40:32 +10:00
|
|
|
// Each component is responsible for calling Update on its child components
|
|
|
|
// (so that disabling the parent prevents updates to the children, etc).
|
2021-08-05 12:26:41 +10:00
|
|
|
type Updater interface {
|
|
|
|
Update() error
|
|
|
|
}
|