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
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"log"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
)
|
)
|
||||||
|
@ -81,52 +81,65 @@ func (d drawList) Swap(i, j int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bad, slow, topological sort
|
// Bad, slow, topological sort
|
||||||
func (d *drawList) topsort() error {
|
func (d *drawList) topsort() {
|
||||||
// Count indegrees - O(|V|^2)
|
// Produce edge lists - O(|V|^2)
|
||||||
indegree := make(map[Drawer]int)
|
// Count indegrees - also O(|V|^2)
|
||||||
for _, u := range d.list {
|
edges := make([][]int, len(d.list))
|
||||||
indegree[u] += 0
|
indegree := make([]int, len(d.list))
|
||||||
for _, v := range d.list {
|
for i, u := range d.list {
|
||||||
if u == v {
|
if u == (tombstone{}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j, v := range d.list {
|
||||||
|
if i == j {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v == (tombstone{}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if u.DrawBefore(v) || v.DrawAfter(u) {
|
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
|
// Start queue with all zero-indegree vertices
|
||||||
|
var queue []int
|
||||||
|
for i, n := range indegree {
|
||||||
|
if d.list[i] == (tombstone{}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
queue = append(queue, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process into new list
|
||||||
list := make([]Drawer, 0, len(d.list))
|
list := make([]Drawer, 0, len(d.list))
|
||||||
for len(indegree) > 0 {
|
for len(queue) > 0 {
|
||||||
var bag []Drawer
|
i := queue[0]
|
||||||
for v, n := range indegree {
|
queue = queue[1:]
|
||||||
if n == 0 {
|
if false {
|
||||||
bag = append(bag, v)
|
d.rev[d.list[i]] = len(list)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//log.Printf("zero indegree vertices: %v", bag)
|
list = append(list, d.list[i])
|
||||||
if len(bag) == 0 {
|
for _, j := range edges[i] {
|
||||||
//log.Printf("remaining vertices: %v", indegree)
|
indegree[j]--
|
||||||
return errors.New("no vertices with zero indegree")
|
if indegree[j] <= 0 {
|
||||||
}
|
if indegree[j] < 0 {
|
||||||
list = append(list, bag...)
|
log.Printf("indegree[%d] = %d (component %v)", j, indegree[j], d.list[j])
|
||||||
for _, u := range bag {
|
|
||||||
delete(indegree, u)
|
|
||||||
}
|
|
||||||
for _, u := range bag {
|
|
||||||
for v := range indegree {
|
|
||||||
if u.DrawBefore(v) || v.DrawAfter(u) {
|
|
||||||
indegree[v]--
|
|
||||||
}
|
}
|
||||||
|
queue = append(queue, j)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace list
|
// Replace list
|
||||||
d.list = list
|
d.list = list
|
||||||
// Update rev
|
// Update rev
|
||||||
|
d.rev = make(map[Drawer]int, len(list))
|
||||||
for i, v := range list {
|
for i, v := range list {
|
||||||
d.rev[v] = i
|
d.rev[v] = i
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ import (
|
||||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const topologicalDrawSort = true
|
||||||
|
|
||||||
var _ interface {
|
var _ interface {
|
||||||
Disabler
|
Disabler
|
||||||
Hider
|
Hider
|
||||||
|
@ -182,16 +185,18 @@ func (g *Game) Update() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the draw list (on every frame - this isn't as bad as it sounds)
|
// Sort the draw list (on every frame - this isn't as bad as it sounds)
|
||||||
//sort.Stable(g.drawList)
|
if topologicalDrawSort {
|
||||||
if err := g.drawList.topsort(); err != nil {
|
g.drawList.topsort()
|
||||||
return fmt.Errorf("drawList.topsort: %v", err)
|
} else {
|
||||||
}
|
sort.Stable(g.drawList)
|
||||||
// Truncate tombstones from the end.
|
|
||||||
for i := g.drawList.Len() - 1; i >= 0; i-- {
|
// Truncate tombstones from the end.
|
||||||
if g.drawList.list[i] != (tombstone{}) {
|
for i := g.drawList.Len() - 1; i >= 0; i-- {
|
||||||
break
|
if g.drawList.list[i] != (tombstone{}) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
g.drawList.list = g.drawList.list[:i]
|
||||||
}
|
}
|
||||||
g.drawList.list = g.drawList.list[:i]
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ func (aw *Awakeman) realUpdate() error {
|
||||||
aw.bubbleTimer--
|
aw.bubbleTimer--
|
||||||
if aw.bubbleTimer <= 0 {
|
if aw.bubbleTimer <= 0 {
|
||||||
aw.bubbleTimer = bubblePeriod
|
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 err := engine.PreorderWalk(bubble, func(c, _ interface{}) error {
|
||||||
if p, ok := c.(engine.Loader); ok {
|
if p, ok := c.(engine.Loader); ok {
|
||||||
return p.Load(Assets)
|
return p.Load(Assets)
|
||||||
|
|
|
@ -67,10 +67,15 @@ func (b *Bubble) Update() error {
|
||||||
if b.Life <= 0 {
|
if b.Life <= 0 {
|
||||||
b.game.Unregister(b)
|
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
|
// this is an effect particle, if it overlaps a solid, who cares
|
||||||
b.Sprite.Actor.Pos = b.Sprite.Actor.Pos.Add(geom.Pt3(
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue