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).
|
||||
func (a *Actor) CollidesAt(p geom.Int3) bool {
|
||||
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) {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -95,15 +95,13 @@ func (d *DrawDAG) Prepare(game *Game) error {
|
|||
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
||||
d.game = game
|
||||
|
||||
// Descendants might not be prepared yet, so fill the cache with zero boxes
|
||||
// and fill remaining data structures during update
|
||||
// TODO: work out a how to prepare the descendants first
|
||||
return PreorderWalk(d, func(c, _ interface{}) error {
|
||||
if db, ok := c.(DrawBoxer); ok {
|
||||
d.boxCache[db] = geom.Box{}
|
||||
// Because Game.LoadAndPrepare calls Prepare in a post-order walk, all the
|
||||
// descendants should be prepared, meaning BoundingBox (and Add) is likely
|
||||
// to be a safe call.
|
||||
for db := range game.Query(d, DrawBoxerType) {
|
||||
d.Add(db.(DrawBoxer))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (d *DrawDAG) Scan() []interface{} { return d.Components }
|
||||
|
@ -284,13 +282,11 @@ func (d *dag) addEdge(u, v Drawer) {
|
|||
d.out[u][v] = struct{}{}
|
||||
}
|
||||
|
||||
/*
|
||||
// removeEdge removes the edge u-v in O(1).
|
||||
func (d *dag) removeEdge(u, v Drawer) {
|
||||
delete(d.in[v], u)
|
||||
delete(d.out[u], v)
|
||||
}
|
||||
*/
|
||||
|
||||
// addVertex ensures the vertex is present, even if there are no edges.
|
||||
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)).
|
||||
func (d *dag) removeVertex(v Drawer) {
|
||||
for u := range d.in[v] {
|
||||
// u-v is no longer an edge
|
||||
delete(d.out[u], v)
|
||||
d.removeEdge(u, v)
|
||||
}
|
||||
for w := range d.out[v] {
|
||||
// v-w is no longer an edge
|
||||
delete(d.in[w], v)
|
||||
d.removeEdge(v, w)
|
||||
}
|
||||
delete(d.in, v)
|
||||
delete(d.out, v)
|
||||
delete(d.all, v)
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ func (g *Game) Update() error {
|
|||
|
||||
// Update everything that is not disabled.
|
||||
// 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)
|
||||
if u == g {
|
||||
continue
|
||||
|
@ -154,10 +154,10 @@ func (g *Game) Parent(c interface{}) interface{} {
|
|||
// Query looks for components having both a given ancestor and implementing
|
||||
// a given behaviour (see Behaviors in interface.go). This only returns sensible
|
||||
// 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()
|
||||
defer g.dbmu.RUnlock()
|
||||
return g.byAB[abKey{ancestorID, behaviour}]
|
||||
return g.byAB[abKey{ancestor, behaviour}]
|
||||
}
|
||||
|
||||
// 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
|
||||
// be visited before the parent.
|
||||
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 {
|
||||
|
@ -223,11 +223,10 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
|||
// Load all the Loaders.
|
||||
startLoad := time.Now()
|
||||
if err := PreorderWalk(g, func(c, _ interface{}) error {
|
||||
l, ok := c.(Loader)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if l, ok := c.(Loader); ok {
|
||||
return l.Load(assets)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -247,11 +246,15 @@ func (g *Game) LoadAndPrepare(assets fs.FS) error {
|
|||
|
||||
// Prepare all the Preppers
|
||||
startPrep := time.Now()
|
||||
for p := range g.Query(g.Ident(), PrepperType) {
|
||||
if err := p.(Prepper).Prepare(g); err != nil {
|
||||
if err := PostorderWalk(g, func(c, _ interface{}) error {
|
||||
if p, ok := c.(Prepper); ok {
|
||||
return p.Prepare(g)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("finished preparing in %v", time.Since(startPrep))
|
||||
return nil
|
||||
}
|
||||
|
@ -270,7 +273,7 @@ func (g *Game) Register(component, parent interface{}) error {
|
|||
}
|
||||
g.dbmu.Lock()
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -298,11 +301,7 @@ func (g *Game) register(component, parent interface{}) error {
|
|||
}
|
||||
// TODO: better than O(len(path)^2) time and memory?
|
||||
for p := component; p != nil; p = g.par[p] {
|
||||
id, ok := p.(Identifier)
|
||||
if !ok || id.Ident() == "" {
|
||||
continue
|
||||
}
|
||||
k := abKey{id.Ident(), b}
|
||||
k := abKey{p, b}
|
||||
if g.byAB[k] == nil {
|
||||
g.byAB[k] = make(map[interface{}]struct{})
|
||||
}
|
||||
|
@ -320,14 +319,12 @@ func (g *Game) Unregister(component interface{}) {
|
|||
return
|
||||
}
|
||||
g.dbmu.Lock()
|
||||
postorderWalk(component, nil, func(c, _ interface{}) error {
|
||||
g.unregister(c)
|
||||
return nil
|
||||
})
|
||||
// postorderWalk goes in the right order for unregistering.
|
||||
postorderWalk(component, nil, g.unregister)
|
||||
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
|
||||
ct := reflect.TypeOf(component)
|
||||
for _, b := range Behaviours {
|
||||
|
@ -335,17 +332,11 @@ func (g *Game) unregister(component interface{}) {
|
|||
continue
|
||||
}
|
||||
for p := component; p != nil; p = g.par[p] {
|
||||
id, ok := p.(Identifier)
|
||||
if !ok || id.Ident() == "" {
|
||||
continue
|
||||
}
|
||||
k := abKey{id.Ident(), b}
|
||||
if g.byAB[k] == nil {
|
||||
continue
|
||||
}
|
||||
if k := (abKey{p, b}); g.byAB[k] != nil {
|
||||
delete(g.byAB[k], component)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unregister from g.par
|
||||
delete(g.par, component)
|
||||
|
@ -354,12 +345,13 @@ func (g *Game) unregister(component interface{}) {
|
|||
if id, ok := component.(Identifier); ok && id.Ident() != "" {
|
||||
delete(g.byID, id.Ident())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// --------- Helper stuff ---------
|
||||
|
||||
type abKey struct {
|
||||
ancestor string
|
||||
ancestor interface{}
|
||||
behaviour reflect.Type
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ func init() {
|
|||
gob.Register(&Prism{})
|
||||
}
|
||||
|
||||
// PrismMap is a generalised 3D tilemap/wallmap/etc.
|
||||
// PrismMap is a generalised 3D tilemap/wallmap/voxelmap etc.
|
||||
type PrismMap struct {
|
||||
ID
|
||||
Disables
|
||||
|
|
|
@ -127,9 +127,13 @@ func (g *Game) cmdQuery(dst io.Writer, argv []string) {
|
|||
fmt.Fprintf(dst, "Unknown behaviour %q\n", argv[1])
|
||||
}
|
||||
|
||||
ancestor := g.Ident()
|
||||
var ancestor interface{} = g
|
||||
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)
|
||||
|
|
|
@ -17,7 +17,7 @@ func Level1() *engine.Scene {
|
|||
CameraID: "game_camera",
|
||||
Child: &engine.Billboard{
|
||||
ID: "bg_image",
|
||||
Pos: geom.Pt3(-160, -120, -1),
|
||||
Pos: geom.Pt3(-160, -20, -100),
|
||||
Src: engine.ImageRef{Path: "assets/space.png"},
|
||||
},
|
||||
Factor: 0.5,
|
||||
|
|
Loading…
Reference in a new issue