WIP: topsort adjustments
This commit is contained in:
parent
091d36094b
commit
45d7f32a2a
4 changed files with 69 additions and 46 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue