From 46c6a72fddff78eb1292ab5bc1da6c2adb3c12b9 Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Tue, 31 Aug 2021 22:05:21 +1000 Subject: [PATCH] game does drawing --- engine/camera.go | 11 ++++++++ engine/game.go | 65 ++++++++++++++++++++++++++------------------- engine/interface.go | 1 + engine/scene.go | 10 ++++++- engine/sceneref.go | 3 +++ 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/engine/camera.go b/engine/camera.go index 33463e6..2f053f5 100644 --- a/engine/camera.go +++ b/engine/camera.go @@ -11,6 +11,7 @@ import ( var _ interface { Identifier Prepper + Transformer } = &Camera{} func init() { @@ -37,3 +38,13 @@ func (c *Camera) Prepare(game *Game) error { c.game = game return nil } + +// Transform returns the camera transform. +func (c *Camera) Transform() ebiten.DrawImageOptions { + var opts ebiten.DrawImageOptions + opts.GeoM.Translate(float2(c.Centre.Mul(-1))) + opts.GeoM.Scale(c.Zoom, c.Zoom) + opts.GeoM.Rotate(c.Rotation) + opts.GeoM.Translate(float64(c.game.ScreenWidth/2), float64(c.game.ScreenHeight/2)) + return opts +} diff --git a/engine/game.go b/engine/game.go index 906eb5f..ab46b18 100644 --- a/engine/game.go +++ b/engine/game.go @@ -13,7 +13,7 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) -const gameDoesEverything = false +const gameDoesEverything = true var _ interface { Disabler @@ -68,60 +68,71 @@ func (d drawers) Less(i, j int) bool { return d[i].DrawOrder() < d[j].DrawOrder( func (d drawers) Len() int { return len(d) } func (d drawers) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func concatOpts(a, b ebiten.DrawImageOptions) ebiten.DrawImageOptions { + a.ColorM.Concat(b.ColorM) + a.GeoM.Concat(b.GeoM) + a.CompositeMode = b.CompositeMode + a.Filter = b.Filter + return a +} + // Draw draws the entire thing, with default draw options. func (g *Game) Draw(screen *ebiten.Image) { if g.Hidden { return } - if !gameDoesEverything { - g.Root.Draw(screen, ebiten.DrawImageOptions{}) - } + if gameDoesEverything { - hidden := map[interface{}]bool{ - g: false, // g.Hidden checked above + type state struct { + hidden bool + opts ebiten.DrawImageOptions } - transform := map[interface{}]ebiten.DrawImageOptions{ - g: {}, + accum := map[interface{}]state{ + g: {hidden: false}, } // draw everything for _, d := range g.drawList { - // directly hidden? + // is d directly hidden? if h, ok := d.(Hider); ok && h.IsHidden() { - hidden[d] = true - continue + accum[d] = state{hidden: true} + continue // skip drawing } - // hidden by parent? - // walk up the parents to find the lowest known - hid := false + // walk up g.par to find the nearest parent state in accum + var st state stack := []interface{}{d} - for p := g.par[d]; p != nil; p = g.par[p] { - if h, found := hidden[p]; found { - hid = h + for p := g.par[d]; ; p = g.par[p] { + if s, found := accum[p]; found { + st = s break } stack = append(stack, p) } - // unwind the stack, setting known values + // unwind the stack, accumulating state along the way for len(stack) > 0 { l1 := len(stack) - 1 p := stack[l1] stack = stack[:l1] if h, ok := p.(Hider); ok { - hid = hid || h.IsHidden() - hidden[p] = hid + st.hidden = st.hidden || h.IsHidden() } + if st.hidden { + accum[p] = state{hidden: true} + continue + } + if t, ok := p.(Transformer); ok { + st.opts = concatOpts(t.Transform(), st.opts) + } + accum[p] = st } - // now...skip if hidden - if hid { + // now...skip drawing if hidden :P + if st.hidden { continue } - - if t, ok := d.(Transformer); ok { - transform[t] = t.Transform() // concatted with parent transform... - } - d.Draw(screen, ebiten.DrawImageOptions{}) + d.Draw(screen, st.opts) } + } else { // !gameDoesEverything + g.Root.Draw(screen, ebiten.DrawImageOptions{}) } } diff --git a/engine/interface.go b/engine/interface.go index f5ac88a..07e9df5 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -156,6 +156,7 @@ type Scener interface { Identifier Prepper Scanner + Transformer Updater } diff --git a/engine/scene.go b/engine/scene.go index bdbc19b..02a5231 100644 --- a/engine/scene.go +++ b/engine/scene.go @@ -28,7 +28,7 @@ type Scene struct { // Draw draws all components in order. func (s *Scene) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) { - if s.Hidden { + if s.Hidden || gameDoesEverything { return } if s.Camera == nil { @@ -106,6 +106,14 @@ func (s *Scene) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) { } } +// Transform returns the camera transform +func (s *Scene) Transform() ebiten.DrawImageOptions { + if s.Camera == nil { + return ebiten.DrawImageOptions{} + } + return s.Camera.Transform() +} + // Prepare does an initial Z-order sort. func (s *Scene) Prepare(game *Game) error { s.sortByDrawOrder() diff --git a/engine/sceneref.go b/engine/sceneref.go index 5cb702a..c80c425 100644 --- a/engine/sceneref.go +++ b/engine/sceneref.go @@ -88,5 +88,8 @@ func (r SceneRef) Prepare(g *Game) error { return r.scene.Prepare(g) } // Scan returns the components in the scene. func (r SceneRef) Scan() []interface{} { return r.scene.Scan() } +// Transform returns the value of Transform from the scene. +func (r SceneRef) Transform() ebiten.DrawImageOptions { return r.scene.Transform() } + // Update updates the scene. func (r SceneRef) Update() error { return r.scene.Update() }