bubbleless topsort working

This commit is contained in:
Josh Deprez 2021-09-17 11:13:39 +10:00
parent 17de1d6b97
commit 091d36094b
8 changed files with 81 additions and 26 deletions

View file

@ -2,6 +2,7 @@ package engine
import ( import (
"encoding/gob" "encoding/gob"
"fmt"
"drjosh.dev/gurgle/geom" "drjosh.dev/gurgle/geom"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@ -75,6 +76,10 @@ func (b *Billboard) Prepare(g *Game) error {
// Scan returns a slice containing Src. // Scan returns a slice containing Src.
func (b *Billboard) Scan() []interface{} { return []interface{}{&b.Src} } func (b *Billboard) Scan() []interface{} { return []interface{}{&b.Src} }
func (b *Billboard) String() string {
return fmt.Sprintf("Billboard@%v", b.Pos)
}
// Transform returns a translation by the projected position. // Transform returns a translation by the projected position.
func (b *Billboard) Transform() (opts ebiten.DrawImageOptions) { func (b *Billboard) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat( opts.GeoM.Translate(geom.CFloat(

View file

@ -41,8 +41,20 @@ func (d *DebugToast) Draw(screen *ebiten.Image, _ *ebiten.DrawImageOptions) {
} }
// Draw last. // Draw last.
func (DebugToast) DrawAfter(Drawer) bool { return true } func (DebugToast) DrawAfter(x Drawer) bool {
func (DebugToast) DrawBefore(Drawer) bool { return false } switch x.(type) {
case *DebugToast, PerfDisplay, tombstone:
return false
}
return true
}
func (DebugToast) DrawBefore(x Drawer) bool {
return false
}
func (d *DebugToast) String() string {
return fmt.Sprintf("DebugToast@%v", d.Pos)
}
func (d *DebugToast) Toast(text string) { func (d *DebugToast) Toast(text string) {
d.Text = text d.Text = text
@ -67,5 +79,16 @@ func (p PerfDisplay) Draw(screen *ebiten.Image, _ *ebiten.DrawImageOptions) {
} }
// Draw last. // Draw last.
func (PerfDisplay) DrawAfter(Drawer) bool { return true } func (PerfDisplay) DrawAfter(x Drawer) bool {
func (PerfDisplay) DrawBefore(Drawer) bool { return false } switch x.(type) {
case *DebugToast, PerfDisplay, tombstone:
return false
}
return true
}
func (PerfDisplay) DrawBefore(Drawer) bool {
return false
}
func (PerfDisplay) String() string { return "PerfDisplay" }

View file

@ -17,6 +17,8 @@ func (tombstone) Draw(*ebiten.Image, *ebiten.DrawImageOptions) {}
func (tombstone) DrawAfter(x Drawer) bool { return x != tombstone{} } func (tombstone) DrawAfter(x Drawer) bool { return x != tombstone{} }
func (tombstone) DrawBefore(Drawer) bool { return false } func (tombstone) DrawBefore(Drawer) bool { return false }
func (tombstone) String() string { return "tombstone" }
type drawList struct { type drawList struct {
list []Drawer list []Drawer
rev map[Drawer]int rev map[Drawer]int
@ -80,9 +82,10 @@ func (d drawList) Swap(i, j int) {
// Bad, slow, topological sort // Bad, slow, topological sort
func (d *drawList) topsort() error { func (d *drawList) topsort() error {
// Count indegrees // Count indegrees - O(|V|^2)
indegree := make(map[Drawer]int) indegree := make(map[Drawer]int)
for _, u := range d.list { for _, u := range d.list {
indegree[u] += 0
for _, v := range d.list { for _, v := range d.list {
if u == v { if u == v {
continue continue
@ -92,6 +95,7 @@ func (d *drawList) topsort() error {
} }
} }
} }
//log.Printf("indegree: %v", indegree)
// Sort into new list // Sort into new list
list := make([]Drawer, 0, len(d.list)) list := make([]Drawer, 0, len(d.list))
for len(indegree) > 0 { for len(indegree) > 0 {
@ -99,10 +103,11 @@ func (d *drawList) topsort() error {
for v, n := range indegree { for v, n := range indegree {
if n == 0 { if n == 0 {
bag = append(bag, v) bag = append(bag, v)
break
} }
} }
//log.Printf("zero indegree vertices: %v", bag)
if len(bag) == 0 { if len(bag) == 0 {
//log.Printf("remaining vertices: %v", indegree)
return errors.New("no vertices with zero indegree") return errors.New("no vertices with zero indegree")
} }
list = append(list, bag...) list = append(list, bag...)

View file

@ -31,3 +31,5 @@ type Fill struct {
func (f *Fill) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) { func (f *Fill) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
screen.Fill(opts.ColorM.Apply(f.Color)) screen.Fill(opts.ColorM.Apply(f.Color))
} }
func (f *Fill) String() string { return "Fill" }

View file

@ -237,6 +237,10 @@ func (p *Prism) DrawBefore(x Drawer) bool {
return false return false
} }
func (p *Prism) String() string {
return fmt.Sprintf("Prism(%d)@%v", p.Cell, p.pos)
}
// Transform returns a translation by the projected position. // Transform returns a translation by the projected position.
func (p *Prism) Transform() (opts ebiten.DrawImageOptions) { func (p *Prism) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat( opts.GeoM.Translate(geom.CFloat(

View file

@ -2,6 +2,7 @@ package engine
import ( import (
"encoding/gob" "encoding/gob"
"fmt"
"image" "image"
"drjosh.dev/gurgle/geom" "drjosh.dev/gurgle/geom"
@ -108,6 +109,10 @@ func (s *Sprite) SetAnim(a *Anim) {
s.anim = a s.anim = a
} }
func (s *Sprite) String() string {
return fmt.Sprintf("Sprite@%v", s.Actor.Pos)
}
// Transform returns a translation by the DrawOffset and Actor.Pos projected // Transform returns a translation by the DrawOffset and Actor.Pos projected
func (s *Sprite) Transform() (opts ebiten.DrawImageOptions) { func (s *Sprite) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat( opts.GeoM.Translate(geom.CFloat(

View file

@ -109,29 +109,31 @@ func (aw *Awakeman) realUpdate() error {
bubblePeriod = 6 bubblePeriod = 6
) )
// Add a bubble? if false {
aw.bubbleTimer-- // Add a bubble?
if aw.bubbleTimer <= 0 { aw.bubbleTimer--
aw.bubbleTimer = bubblePeriod if aw.bubbleTimer <= 0 {
bubble := NewBubble(aw.Sprite.Actor.Pos.Add(geom.Pt3(1, -15, -1))) aw.bubbleTimer = bubblePeriod
if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error { bubble := NewBubble(aw.Sprite.Actor.Pos.Add(geom.Pt3(1, -15, -1)))
if p, ok := c.(engine.Loader); ok { if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error {
return p.Load(Assets) if p, ok := c.(engine.Loader); ok {
return p.Load(Assets)
}
return nil
}); err != nil {
return err
} }
return nil aw.game.Register(bubble, aw.game.Parent(aw))
}); err != nil { if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error {
return err if p, ok := c.(engine.Prepper); ok {
} return p.Prepare(aw.game)
aw.game.Register(bubble, aw.game.Parent(aw)) }
if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error { return nil
if p, ok := c.(engine.Prepper); ok { }); err != nil {
return p.Prepare(aw.game) return err
} }
return nil bubble.Sprite.SetAnim(bubble.Sprite.Sheet.NewAnim("bubble"))
}); err != nil {
return err
} }
bubble.Sprite.SetAnim(bubble.Sprite.Sheet.NewAnim("bubble"))
} }
// Fell below some threshold? // Fell below some threshold?
@ -265,3 +267,7 @@ func (aw *Awakeman) Prepare(game *engine.Game) error {
} }
func (aw *Awakeman) Scan() []interface{} { return []interface{}{&aw.Sprite} } func (aw *Awakeman) Scan() []interface{} { return []interface{}{&aw.Sprite} }
func (aw *Awakeman) String() string {
return fmt.Sprintf("Awakeman@%v", aw.Sprite.Actor.Pos)
}

View file

@ -1,6 +1,7 @@
package game package game
import ( import (
"fmt"
"image" "image"
"math/rand" "math/rand"
@ -52,6 +53,10 @@ func (b *Bubble) Scan() []interface{} {
return []interface{}{&b.Sprite} return []interface{}{&b.Sprite}
} }
func (b *Bubble) String() string {
return fmt.Sprintf("Bubble@%v", b.Sprite.Actor.Pos)
}
func (b *Bubble) Prepare(g *engine.Game) error { func (b *Bubble) Prepare(g *engine.Game) error {
b.game = g b.game = g
return nil return nil