WIP: topsort adjustments

This commit is contained in:
Josh Deprez 2021-09-17 12:50:29 +10:00
parent 091d36094b
commit 45d7f32a2a
4 changed files with 69 additions and 46 deletions

View file

@ -1,7 +1,7 @@
package engine
import (
"errors"
"log"
"github.com/hajimehoshi/ebiten/v2"
)
@ -81,52 +81,65 @@ func (d drawList) Swap(i, j int) {
}
// Bad, slow, topological sort
func (d *drawList) topsort() error {
// Count indegrees - O(|V|^2)
indegree := make(map[Drawer]int)
for _, u := range d.list {
indegree[u] += 0
for _, v := range d.list {
if u == v {
func (d *drawList) topsort() {
// Produce edge lists - O(|V|^2)
// Count indegrees - also O(|V|^2)
edges := make([][]int, len(d.list))
indegree := make([]int, len(d.list))
for i, u := range d.list {
if u == (tombstone{}) {
continue
}
for j, v := range d.list {
if i == j {
continue
}
if v == (tombstone{}) {
continue
}
if u.DrawBefore(v) || v.DrawAfter(u) {
indegree[v]++
edges[i] = append(edges[i], j)
indegree[j]++
}
}
}
//log.Printf("indegree: %v", indegree)
// Sort into new list
list := make([]Drawer, 0, len(d.list))
for len(indegree) > 0 {
var bag []Drawer
for v, n := range indegree {
// Start queue with all zero-indegree vertices
var queue []int
for i, n := range indegree {
if d.list[i] == (tombstone{}) {
continue
}
if n == 0 {
bag = append(bag, v)
queue = append(queue, i)
}
}
//log.Printf("zero indegree vertices: %v", bag)
if len(bag) == 0 {
//log.Printf("remaining vertices: %v", indegree)
return errors.New("no vertices with zero indegree")
// Process into new list
list := make([]Drawer, 0, len(d.list))
for len(queue) > 0 {
i := queue[0]
queue = queue[1:]
if false {
d.rev[d.list[i]] = len(list)
}
list = append(list, bag...)
for _, u := range bag {
delete(indegree, u)
}
for _, u := range bag {
for v := range indegree {
if u.DrawBefore(v) || v.DrawAfter(u) {
indegree[v]--
list = append(list, d.list[i])
for _, j := range edges[i] {
indegree[j]--
if indegree[j] <= 0 {
if indegree[j] < 0 {
log.Printf("indegree[%d] = %d (component %v)", j, indegree[j], d.list[j])
}
queue = append(queue, j)
}
}
}
// Replace list
d.list = list
// Update rev
d.rev = make(map[Drawer]int, len(list))
for i, v := range list {
d.rev[v] = i
}
return nil
}

View file

@ -8,6 +8,7 @@ import (
"io/fs"
"log"
"reflect"
"sort"
"sync"
"time"
@ -16,6 +17,8 @@ import (
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
const topologicalDrawSort = true
var _ interface {
Disabler
Hider
@ -182,10 +185,11 @@ func (g *Game) Update() error {
}
// Sort the draw list (on every frame - this isn't as bad as it sounds)
//sort.Stable(g.drawList)
if err := g.drawList.topsort(); err != nil {
return fmt.Errorf("drawList.topsort: %v", err)
}
if topologicalDrawSort {
g.drawList.topsort()
} else {
sort.Stable(g.drawList)
// Truncate tombstones from the end.
for i := g.drawList.Len() - 1; i >= 0; i-- {
if g.drawList.list[i] != (tombstone{}) {
@ -193,6 +197,7 @@ func (g *Game) Update() error {
}
g.drawList.list = g.drawList.list[:i]
}
}
return nil
}

View file

@ -114,7 +114,7 @@ func (aw *Awakeman) realUpdate() error {
aw.bubbleTimer--
if aw.bubbleTimer <= 0 {
aw.bubbleTimer = bubblePeriod
bubble := NewBubble(aw.Sprite.Actor.Pos.Add(geom.Pt3(1, -15, -1)))
bubble := NewBubble(aw.Sprite.Actor.Pos.Add(geom.Pt3(-3, -20, -1)))
if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error {
if p, ok := c.(engine.Loader); ok {
return p.Load(Assets)

View file

@ -67,10 +67,15 @@ func (b *Bubble) Update() error {
if b.Life <= 0 {
b.game.Unregister(b)
}
// not using MoveX/MoveY/... because collisions are unnecessary -
if false { // not using MoveX/MoveY/... because collisions are unnecessary -
// this is an effect particle, if it overlaps a solid, who cares
b.Sprite.Actor.Pos = b.Sprite.Actor.Pos.Add(geom.Pt3(
rand.Intn(3)-1, -1, rand.Intn(2)-1,
// --lint:ignore SA4000 one random minus another is not always zero...
rand.Intn(3)-1, rand.Intn(2)-1, 0, // rand.Intn(2)-rand.Intn(2),
))
} else {
b.Sprite.Actor.MoveX(float64(rand.Intn(3)-1), nil)
b.Sprite.Actor.MoveY(float64(rand.Intn(2)-1), nil)
}
return nil
}