more dag
This commit is contained in:
parent
951b38271f
commit
938fd70921
6 changed files with 42 additions and 53 deletions
|
@ -38,7 +38,8 @@ func (a *Actor) BoundingBox() geom.Box {
|
||||||
// given position (not necessarily a.Pos).
|
// given position (not necessarily a.Pos).
|
||||||
func (a *Actor) CollidesAt(p geom.Int3) bool {
|
func (a *Actor) CollidesAt(p geom.Int3) bool {
|
||||||
bounds := a.Bounds.Add(p)
|
bounds := a.Bounds.Add(p)
|
||||||
for c := range a.game.Query(a.CollisionDomain, ColliderType) {
|
cd := a.game.Component(a.CollisionDomain)
|
||||||
|
for c := range a.game.Query(cd, ColliderType) {
|
||||||
if c.(Collider).CollidesWith(bounds) {
|
if c.(Collider).CollidesWith(bounds) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,15 +95,13 @@ func (d *DrawDAG) Prepare(game *Game) error {
|
||||||
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
||||||
d.game = game
|
d.game = game
|
||||||
|
|
||||||
// Descendants might not be prepared yet, so fill the cache with zero boxes
|
// Because Game.LoadAndPrepare calls Prepare in a post-order walk, all the
|
||||||
// and fill remaining data structures during update
|
// descendants should be prepared, meaning BoundingBox (and Add) is likely
|
||||||
// TODO: work out a how to prepare the descendants first
|
// to be a safe call.
|
||||||
return PreorderWalk(d, func(c, _ interface{}) error {
|
for db := range game.Query(d, DrawBoxerType) {
|
||||||
if db, ok := c.(DrawBoxer); ok {
|
d.Add(db.(DrawBoxer))
|
||||||
d.boxCache[db] = geom.Box{}
|
}
|
||||||
}
|
return nil
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DrawDAG) Scan() []interface{} { return d.Components }
|
func (d *DrawDAG) Scan() []interface{} { return d.Components }
|
||||||
|
@ -284,13 +282,11 @@ func (d *dag) addEdge(u, v Drawer) {
|
||||||
d.out[u][v] = struct{}{}
|
d.out[u][v] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// removeEdge removes the edge u-v in O(1).
|
// removeEdge removes the edge u-v in O(1).
|
||||||
func (d *dag) removeEdge(u, v Drawer) {
|
func (d *dag) removeEdge(u, v Drawer) {
|
||||||
delete(d.in[v], u)
|
delete(d.in[v], u)
|
||||||
delete(d.out[u], v)
|
delete(d.out[u], v)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// addVertex ensures the vertex is present, even if there are no edges.
|
// addVertex ensures the vertex is present, even if there are no edges.
|
||||||
func (d *dag) addVertex(v Drawer) {
|
func (d *dag) addVertex(v Drawer) {
|
||||||
|
@ -300,15 +296,11 @@ func (d *dag) addVertex(v Drawer) {
|
||||||
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
||||||
func (d *dag) removeVertex(v Drawer) {
|
func (d *dag) removeVertex(v Drawer) {
|
||||||
for u := range d.in[v] {
|
for u := range d.in[v] {
|
||||||
// u-v is no longer an edge
|
d.removeEdge(u, v)
|
||||||
delete(d.out[u], v)
|
|
||||||
}
|
}
|
||||||
for w := range d.out[v] {
|
for w := range d.out[v] {
|
||||||
// v-w is no longer an edge
|
d.removeEdge(v, w)
|
||||||
delete(d.in[w], v)
|
|
||||||
}
|
}
|
||||||
delete(d.in, v)
|
|
||||||
delete(d.out, v)
|
|
||||||
delete(d.all, v)
|
delete(d.all, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (g *Game) Update() error {
|
||||||
|
|
||||||
// Update everything that is not disabled.
|
// Update everything that is not disabled.
|
||||||
// TODO: do it in a fixed order? map essentially randomises iteration order
|
// TODO: do it in a fixed order? map essentially randomises iteration order
|
||||||
for u := range g.Query(g.Ident(), UpdaterType) {
|
for u := range g.Query(g, UpdaterType) {
|
||||||
// Skip g (note g satisfies Updater, so this would infinitely recurse)
|
// Skip g (note g satisfies Updater, so this would infinitely recurse)
|
||||||
if u == g {
|
if u == g {
|
||||||
continue
|
continue
|
||||||
|
@ -154,10 +154,10 @@ func (g *Game) Parent(c interface{}) interface{} {
|
||||||
// Query looks for components having both a given ancestor and implementing
|
// Query looks for components having both a given ancestor and implementing
|
||||||
// a given behaviour (see Behaviors in interface.go). This only returns sensible
|
// a given behaviour (see Behaviors in interface.go). This only returns sensible
|
||||||
// values after LoadAndPrepare. Note that every component is its own ancestor.
|
// values after LoadAndPrepare. Note that every component is its own ancestor.
|
||||||
func (g *Game) Query(ancestorID string, behaviour reflect.Type) map[interface{}]struct{} {
|
func (g *Game) Query(ancestor interface{}, behaviour reflect.Type) map[interface{}]struct{} {
|
||||||
g.dbmu.RLock()
|
g.dbmu.RLock()
|
||||||
defer g.dbmu.RUnlock()
|
defer g.dbmu.RUnlock()
|
||||||
return g.byAB[abKey{ancestorID, behaviour}]
|
return g.byAB[abKey{ancestor, behaviour}]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements Scanner.
|
// Scan implements Scanner.
|
||||||
|
@ -198,7 +198,7 @@ func preorderWalk(component, parent interface{}, visit func(component, parent in
|
||||||
// value passed to visit when visiting component will be nil. The children will
|
// value passed to visit when visiting component will be nil. The children will
|
||||||
// be visited before the parent.
|
// be visited before the parent.
|
||||||
func PostorderWalk(component interface{}, visit func(component, parent interface{}) error) error {
|
func PostorderWalk(component interface{}, visit func(component, parent interface{}) error) error {
|
||||||
return preorderWalk(component, nil, visit)
|
return postorderWalk(component, nil, visit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func postorderWalk(component, parent interface{}, visit func(component, parent interface{}) error) error {
|
func postorderWalk(component, parent interface{}, visit func(component, parent interface{}) error) error {
|
||||||
|
@ -223,11 +223,10 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
||||||
// Load all the Loaders.
|
// Load all the Loaders.
|
||||||
startLoad := time.Now()
|
startLoad := time.Now()
|
||||||
if err := PreorderWalk(g, func(c, _ interface{}) error {
|
if err := PreorderWalk(g, func(c, _ interface{}) error {
|
||||||
l, ok := c.(Loader)
|
if l, ok := c.(Loader); ok {
|
||||||
if !ok {
|
return l.Load(assets)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return l.Load(assets)
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -247,11 +246,15 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
||||||
|
|
||||||
// Prepare all the Preppers
|
// Prepare all the Preppers
|
||||||
startPrep := time.Now()
|
startPrep := time.Now()
|
||||||
for p := range g.Query(g.Ident(), PrepperType) {
|
if err := PostorderWalk(g, func(c, _ interface{}) error {
|
||||||
if err := p.(Prepper).Prepare(g); err != nil {
|
if p, ok := c.(Prepper); ok {
|
||||||
return err
|
return p.Prepare(g)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("finished preparing in %v", time.Since(startPrep))
|
log.Printf("finished preparing in %v", time.Since(startPrep))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -270,7 +273,7 @@ func (g *Game) Register(component, parent interface{}) error {
|
||||||
}
|
}
|
||||||
g.dbmu.Lock()
|
g.dbmu.Lock()
|
||||||
defer g.dbmu.Unlock()
|
defer g.dbmu.Unlock()
|
||||||
// walk goes in the right order for registering.
|
// preorderWalk goes in the right order for registering.
|
||||||
return preorderWalk(component, parent, g.register)
|
return preorderWalk(component, parent, g.register)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,11 +301,7 @@ func (g *Game) register(component, parent interface{}) error {
|
||||||
}
|
}
|
||||||
// TODO: better than O(len(path)^2) time and memory?
|
// TODO: better than O(len(path)^2) time and memory?
|
||||||
for p := component; p != nil; p = g.par[p] {
|
for p := component; p != nil; p = g.par[p] {
|
||||||
id, ok := p.(Identifier)
|
k := abKey{p, b}
|
||||||
if !ok || id.Ident() == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
k := abKey{id.Ident(), b}
|
|
||||||
if g.byAB[k] == nil {
|
if g.byAB[k] == nil {
|
||||||
g.byAB[k] = make(map[interface{}]struct{})
|
g.byAB[k] = make(map[interface{}]struct{})
|
||||||
}
|
}
|
||||||
|
@ -320,14 +319,12 @@ func (g *Game) Unregister(component interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.dbmu.Lock()
|
g.dbmu.Lock()
|
||||||
postorderWalk(component, nil, func(c, _ interface{}) error {
|
// postorderWalk goes in the right order for unregistering.
|
||||||
g.unregister(c)
|
postorderWalk(component, nil, g.unregister)
|
||||||
return nil
|
|
||||||
})
|
|
||||||
g.dbmu.Unlock()
|
g.dbmu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) unregister(component interface{}) {
|
func (g *Game) unregister(component, _ interface{}) error {
|
||||||
// unregister from g.byAB, using g.par to trace the path
|
// unregister from g.byAB, using g.par to trace the path
|
||||||
ct := reflect.TypeOf(component)
|
ct := reflect.TypeOf(component)
|
||||||
for _, b := range Behaviours {
|
for _, b := range Behaviours {
|
||||||
|
@ -335,15 +332,9 @@ func (g *Game) unregister(component interface{}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for p := component; p != nil; p = g.par[p] {
|
for p := component; p != nil; p = g.par[p] {
|
||||||
id, ok := p.(Identifier)
|
if k := (abKey{p, b}); g.byAB[k] != nil {
|
||||||
if !ok || id.Ident() == "" {
|
delete(g.byAB[k], component)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
k := abKey{id.Ident(), b}
|
|
||||||
if g.byAB[k] == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
delete(g.byAB[k], component)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,12 +345,13 @@ func (g *Game) unregister(component interface{}) {
|
||||||
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
||||||
delete(g.byID, id.Ident())
|
delete(g.byID, id.Ident())
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------- Helper stuff ---------
|
// --------- Helper stuff ---------
|
||||||
|
|
||||||
type abKey struct {
|
type abKey struct {
|
||||||
ancestor string
|
ancestor interface{}
|
||||||
behaviour reflect.Type
|
behaviour reflect.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ func init() {
|
||||||
gob.Register(&Prism{})
|
gob.Register(&Prism{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrismMap is a generalised 3D tilemap/wallmap/etc.
|
// PrismMap is a generalised 3D tilemap/wallmap/voxelmap etc.
|
||||||
type PrismMap struct {
|
type PrismMap struct {
|
||||||
ID
|
ID
|
||||||
Disables
|
Disables
|
||||||
|
|
|
@ -127,9 +127,13 @@ func (g *Game) cmdQuery(dst io.Writer, argv []string) {
|
||||||
fmt.Fprintf(dst, "Unknown behaviour %q\n", argv[1])
|
fmt.Fprintf(dst, "Unknown behaviour %q\n", argv[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
ancestor := g.Ident()
|
var ancestor interface{} = g
|
||||||
if len(argv) == 3 {
|
if len(argv) == 3 {
|
||||||
ancestor = argv[2]
|
c := g.Component(argv[2])
|
||||||
|
if c == nil {
|
||||||
|
fmt.Fprintf(dst, "Component %q not found\n", argv[2])
|
||||||
|
}
|
||||||
|
ancestor = c
|
||||||
}
|
}
|
||||||
|
|
||||||
x := g.Query(ancestor, behaviour)
|
x := g.Query(ancestor, behaviour)
|
||||||
|
|
|
@ -17,7 +17,7 @@ func Level1() *engine.Scene {
|
||||||
CameraID: "game_camera",
|
CameraID: "game_camera",
|
||||||
Child: &engine.Billboard{
|
Child: &engine.Billboard{
|
||||||
ID: "bg_image",
|
ID: "bg_image",
|
||||||
Pos: geom.Pt3(-160, -120, -1),
|
Pos: geom.Pt3(-160, -20, -100),
|
||||||
Src: engine.ImageRef{Path: "assets/space.png"},
|
Src: engine.ImageRef{Path: "assets/space.png"},
|
||||||
},
|
},
|
||||||
Factor: 0.5,
|
Factor: 0.5,
|
||||||
|
|
Loading…
Reference in a new issue