DrawLayer -> DrawManager, iface assertions, etc

This commit is contained in:
Josh Deprez 2021-09-21 12:36:49 +10:00
parent fe40073407
commit 045ab20cd5
5 changed files with 51 additions and 45 deletions

View file

@ -9,6 +9,15 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
var _ interface {
Drawer
DrawManager
Hider
Prepper
Scanner
Updater
} = &DrawDAG{}
// DrawDAG is a DrawLayer that organises DrawBoxer descendants in a directed // DrawDAG is a DrawLayer that organises DrawBoxer descendants in a directed
// acyclic graph (DAG), in order to draw them according to ordering constraints. // acyclic graph (DAG), in order to draw them according to ordering constraints.
// It combines a DAG with a spatial index used when updating vertices to reduce // It combines a DAG with a spatial index used when updating vertices to reduce
@ -26,7 +35,7 @@ type DrawDAG struct {
} }
// Draw draws everything in the DAG in topological order. // Draw draws everything in the DAG in topological order.
func (d *DrawDAG) DrawAll(screen *ebiten.Image, opts *ebiten.DrawImageOptions) { func (d *DrawDAG) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
if d.Hidden() { if d.Hidden() {
return return
} }
@ -89,6 +98,9 @@ func (d *DrawDAG) DrawAll(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
}) })
} }
// exists to satisfy interface
func (DrawDAG) ManagesDrawingSubcomponents() {}
// Prepare adds all subcomponents to the DAG. // Prepare adds all subcomponents to the DAG.
func (d *DrawDAG) Prepare(game *Game) error { func (d *DrawDAG) Prepare(game *Game) error {
d.dag = newDAG() d.dag = newDAG()

View file

@ -2,6 +2,12 @@ package engine
import "github.com/hajimehoshi/ebiten/v2" import "github.com/hajimehoshi/ebiten/v2"
var _ interface {
Drawer
DrawManager
Scanner
} = &DrawDFS{}
// DrawDFS is a DrawLayer that does not add any structure. Components are // DrawDFS is a DrawLayer that does not add any structure. Components are
// drawn in the order in which they are encountered by a depth-first search // drawn in the order in which they are encountered by a depth-first search
// through the game tree, without any extra sorting based on Z values or // through the game tree, without any extra sorting based on Z values or
@ -11,7 +17,7 @@ type DrawDFS struct {
Hides Hides
} }
func (d *DrawDFS) DrawAll(screen *ebiten.Image, opts *ebiten.DrawImageOptions) { func (d *DrawDFS) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
if d.Hidden() { if d.Hidden() {
return return
} }
@ -20,6 +26,9 @@ func (d *DrawDFS) DrawAll(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
} }
} }
// exists to satisfy interface
func (DrawDFS) ManagesDrawingSubcomponents() {}
func (d *DrawDFS) draw(component interface{}, screen *ebiten.Image, opts ebiten.DrawImageOptions) { func (d *DrawDFS) draw(component interface{}, screen *ebiten.Image, opts ebiten.DrawImageOptions) {
// Hidden? stop drawing // Hidden? stop drawing
if h, ok := component.(Hider); ok && h.Hidden() { if h, ok := component.(Hider); ok && h.Hidden() {
@ -29,16 +38,14 @@ func (d *DrawDFS) draw(component interface{}, screen *ebiten.Image, opts ebiten.
if tf, ok := component.(Transformer); ok { if tf, ok := component.(Transformer); ok {
opts = concatOpts(tf.Transform(), opts) opts = concatOpts(tf.Transform(), opts)
} }
// Is it a DrawLayer? draw all and return
if dl, ok := component.(DrawLayer); ok {
dl.DrawAll(screen, &opts)
return
}
// Not a draw layer.
// Does it draw itself? Draw // Does it draw itself? Draw
if dr, ok := component.(Drawer); ok { if dr, ok := component.(Drawer); ok {
dr.Draw(screen, &opts) dr.Draw(screen, &opts)
} }
// Is it a DrawManager? return early (don't recurse)
if _, ok := component.(DrawManager); ok {
return
}
// Has subcomponents? recurse // Has subcomponents? recurse
if sc, ok := component.(Scanner); ok { if sc, ok := component.(Scanner); ok {
for _, ch := range sc.Scan() { for _, ch := range sc.Scan() {

View file

@ -39,7 +39,7 @@ type Game struct {
Disables Disables
Hides Hides
ScreenSize image.Point ScreenSize image.Point
Roots []DrawLayer Root Drawer // usually a DrawManager
Projection geom.Projector Projection geom.Projector
VoxelScale geom.Float3 VoxelScale geom.Float3
@ -54,12 +54,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
if g.Hidden() { if g.Hidden() {
return return
} }
g.Root.Draw(screen, &ebiten.DrawImageOptions{})
// Make all draw managers draw, in order.
opts := &ebiten.DrawImageOptions{}
for _, dm := range g.Roots {
dm.DrawAll(screen, opts)
}
} }
// Layout returns the configured screen width/height. // Layout returns the configured screen width/height.
@ -158,14 +153,8 @@ func (g *Game) Query(ancestor interface{}, behaviour reflect.Type) map[interface
return g.byAB[abKey{ancestor, behaviour}] return g.byAB[abKey{ancestor, behaviour}]
} }
// Scan implements Scanner. // Scan returns g.Root.
func (g *Game) Scan() []interface{} { func (g *Game) Scan() []interface{} { return []interface{}{g.Root} }
rs := make([]interface{}, 0, len(g.Roots))
for _, r := range g.Roots {
rs = append(rs, r)
}
return rs
}
// PreorderWalk calls visit with every component and its parent, reachable from // 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 // the given component via Scan, for as long as visit returns nil. The parent

View file

@ -17,7 +17,7 @@ var (
BoundingBoxerType = reflect.TypeOf((*BoundingBoxer)(nil)).Elem() BoundingBoxerType = reflect.TypeOf((*BoundingBoxer)(nil)).Elem()
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem() ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem() DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
DrawLayerType = reflect.TypeOf((*DrawLayer)(nil)).Elem() DrawLayerType = reflect.TypeOf((*DrawManager)(nil)).Elem()
DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem() DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem()
DrawBoxerType = reflect.TypeOf((*DrawBoxer)(nil)).Elem() DrawBoxerType = reflect.TypeOf((*DrawBoxer)(nil)).Elem()
DrawOrdererType = reflect.TypeOf((*DrawOrderer)(nil)).Elem() DrawOrdererType = reflect.TypeOf((*DrawOrderer)(nil)).Elem()
@ -73,11 +73,11 @@ type Disabler interface {
Enable() Enable()
} }
// DrawLayer is a component responsible for calling Draw on all Drawer // DrawManager is a component responsible for calling Draw on all Drawer
// components beneath it, except those beneath another DrawLayer (it calls // components beneath it, except those beneath another DrawManager (it might
// DrawAll on those). // call Draw on the DrawManager, but that's it).
type DrawLayer interface { type DrawManager interface {
DrawAll(*ebiten.Image, *ebiten.DrawImageOptions) ManagesDrawingSubcomponents()
} }
// Drawer components can draw themselves. Draw is called often. Draw is not // Drawer components can draw themselves. Draw is called often. Draw is not

30
main.go
View file

@ -67,25 +67,23 @@ func main() {
Y: 1, Y: 1,
Z: math.Sqrt(3), Z: math.Sqrt(3),
}, },
Roots: []engine.DrawLayer{ Root: &engine.DrawDFS{
&engine.DrawDFS{ Components: []interface{}{
Components: []interface{}{ &engine.Fill{
&engine.Fill{ ID: "bg_fill",
ID: "bg_fill", Color: color.Gray{100},
Color: color.Gray{100}, },
}, &engine.DrawDAG{
&engine.DrawDAG{ ChunkSize: 16,
ChunkSize: 16, Components: []interface{}{
Components: []interface{}{ &engine.Camera{
&engine.Camera{ ID: "game_camera",
ID: "game_camera", Child: lev1,
Child: lev1,
},
}, },
}, },
&engine.DebugToast{ID: "toast", Pos: image.Pt(0, 15)},
engine.PerfDisplay{},
}, },
&engine.DebugToast{ID: "toast", Pos: image.Pt(0, 15)},
engine.PerfDisplay{},
}, },
}, },
} }