bubbles working yay!!!!!!!!! :)
This commit is contained in:
parent
9a9dcd0d40
commit
661a6bbbc0
6 changed files with 71 additions and 84 deletions
|
@ -65,7 +65,7 @@ func (d *DrawDAG) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
|||
// Walk up game tree to find the nearest state in cache.
|
||||
var st state
|
||||
stack := []interface{}{x}
|
||||
for p := d.game.Parent(x); ; p = d.game.Parent(p) {
|
||||
for p := d.game.Parent(x); p != nil; p = d.game.Parent(p) {
|
||||
if s, found := cache[p]; found {
|
||||
st = s
|
||||
break
|
||||
|
@ -236,6 +236,8 @@ func (d *DrawDAG) unregisterOne(x DrawBoxer) {
|
|||
}
|
||||
// Remove from reverse chunk map
|
||||
delete(d.chunksRev, x)
|
||||
// Remove from box cache
|
||||
delete(d.boxCache, x)
|
||||
// Remove from DAG
|
||||
d.dag.removeVertex(x)
|
||||
}
|
||||
|
|
|
@ -65,63 +65,29 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (w, h int) {
|
|||
|
||||
// Update updates everything.
|
||||
func (g *Game) Update() error {
|
||||
if g.Disabled() {
|
||||
return g.updateRecursive(g)
|
||||
}
|
||||
|
||||
// updateRecursive updates everything in a post-order traversal. It terminates recursion
|
||||
// early if the component reports it is Disabled.
|
||||
func (g *Game) updateRecursive(c interface{}) error {
|
||||
if d, ok := c.(Disabler); ok && d.Disabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Need to do a similar trick for Draw: disabling a parent object should
|
||||
// disable the child objects.
|
||||
// cache memoises the disabled state for each component.
|
||||
cache := map[interface{}]bool{
|
||||
g: false,
|
||||
if sc, ok := c.(Scanner); ok {
|
||||
for _, x := range sc.Scan() {
|
||||
if err := g.updateRecursive(x); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update everything that is not disabled.
|
||||
return PostorderWalk(g, func(c, _ interface{}) error {
|
||||
// Skip g (note g satisfies Updater, so this would infinitely recurse)
|
||||
if c == g {
|
||||
return nil
|
||||
}
|
||||
u, ok := c.(Updater)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Is u disabled itself?
|
||||
if d, ok := u.(Disabler); ok && d.Disabled() {
|
||||
cache[u] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Walk up g.par to find the nearest state in accum.
|
||||
var st bool
|
||||
stack := []interface{}{u}
|
||||
for p := g.par[u]; ; p = g.par[p] {
|
||||
if s, found := cache[p]; found {
|
||||
st = s
|
||||
break
|
||||
}
|
||||
stack = append(stack, p)
|
||||
}
|
||||
// Unwind the stack, accumulating state along the way.
|
||||
for len(stack) > 0 {
|
||||
l1 := len(stack) - 1
|
||||
p := stack[l1]
|
||||
stack = stack[:l1]
|
||||
if d, ok := p.(Disabler); ok {
|
||||
st = st || d.Disabled()
|
||||
}
|
||||
cache[p] = st
|
||||
}
|
||||
|
||||
// Skip updating if disabled.
|
||||
if st {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update
|
||||
if u, ok := c.(Updater); ok {
|
||||
return u.Update()
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ident returns "__GAME__".
|
||||
|
@ -145,30 +111,31 @@ func (g *Game) Parent(c interface{}) interface{} {
|
|||
return g.par[c]
|
||||
}
|
||||
|
||||
// WalkUp visits the component, its parent, its parent, ..., and then g.
|
||||
func (g *Game) WalkUp(component interface{}, visit func(interface{}) error) error {
|
||||
for p := component; p != nil; p = g.Parent(p) {
|
||||
if err := visit(p); err != nil {
|
||||
return err
|
||||
func reverse(s []interface{}) {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkDown visits g, the subcomponent of g, ..., and then the component.
|
||||
func (g *Game) WalkDown(component interface{}, visit func(interface{}) error) error {
|
||||
func (g *Game) Path(component interface{}) []interface{} {
|
||||
var stack []interface{}
|
||||
g.dbmu.RLock()
|
||||
for p := component; p != nil; p = g.Parent(p) {
|
||||
stack = append(stack, p)
|
||||
}
|
||||
g.dbmu.RUnlock()
|
||||
for _, p := range stack {
|
||||
if err := visit(p); err != nil {
|
||||
return err
|
||||
reverse(stack)
|
||||
return stack
|
||||
}
|
||||
|
||||
func (g *Game) ReversePath(component interface{}) []interface{} {
|
||||
var stack []interface{}
|
||||
g.dbmu.RLock()
|
||||
for p := component; p != nil; p = g.Parent(p) {
|
||||
stack = append(stack, p)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
g.dbmu.RUnlock()
|
||||
return stack
|
||||
}
|
||||
|
||||
// Query looks for components having both a given ancestor and implementing
|
||||
|
|
|
@ -40,7 +40,7 @@ func (h *Hides) Hide() { *h = true }
|
|||
// Show sets h to false.
|
||||
func (h *Hides) Show() { *h = false }
|
||||
|
||||
// Components implements Scan directly (as a slice of interface{}).
|
||||
// Components implements Scan directly (as itself!)
|
||||
type Components []interface{}
|
||||
|
||||
// Scan returns c.
|
||||
|
|
|
@ -21,6 +21,7 @@ type scener interface {
|
|||
Disabler
|
||||
Hider
|
||||
Identifier
|
||||
Registrar
|
||||
Scanner
|
||||
}
|
||||
|
||||
|
@ -39,6 +40,21 @@ type Scene struct {
|
|||
Hides
|
||||
}
|
||||
|
||||
func (s *Scene) Register(component, parent interface{}) error {
|
||||
if parent == s {
|
||||
s.Components = append(s.Components, component)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Scene) Unregister(component interface{}) {
|
||||
for i, c := range s.Components {
|
||||
if c == component {
|
||||
s.Components[i] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
|
||||
// After Load, Scene is usable.
|
||||
// This is mostly useful for scenes that refer to other scenes, e.g.
|
||||
|
|
12
game/aw.go
12
game/aw.go
|
@ -125,16 +125,16 @@ func (aw *Awakeman) realUpdate() error {
|
|||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Add bubble to same parent as aw
|
||||
par := aw.game.Parent(aw)
|
||||
if err := aw.game.WalkDown(par, func(c interface{}) error {
|
||||
for _, c := range aw.game.Path(par) {
|
||||
if r, ok := c.(engine.Registrar); ok {
|
||||
return r.Register(bubble, par)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
if err := r.Register(bubble, par); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := engine.PreorderWalk(bubble, func(c, _ interface{}) error {
|
||||
}
|
||||
}
|
||||
if err := engine.PostorderWalk(bubble, func(c, _ interface{}) error {
|
||||
if p, ok := c.(engine.Prepper); ok {
|
||||
return p.Prepare(aw.game)
|
||||
}
|
||||
|
|
|
@ -71,22 +71,24 @@ func (b *Bubble) Prepare(g *engine.Game) error {
|
|||
func (b *Bubble) Update() error {
|
||||
b.Life--
|
||||
if b.Life <= 0 {
|
||||
if err := b.game.WalkUp(b, func(c interface{}) error {
|
||||
b.game.Unregister(b)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
for _, c := range b.game.ReversePath(b) {
|
||||
if r, ok := c.(engine.Registrar); ok {
|
||||
r.Unregister(b)
|
||||
}
|
||||
}
|
||||
if false { // not using MoveX/MoveY/... because collisions are unnecessary -
|
||||
// this is an effect particle, if it overlaps a solid, who cares
|
||||
}
|
||||
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(
|
||||
// --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),
|
||||
//lint:ignore SA4000 one random minus another is not always zero...
|
||||
rand.Intn(3)-1, rand.Intn(2)-1, 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)
|
||||
//lint:ignore SA4000 one random minus another is not always zero...
|
||||
b.Sprite.Actor.MoveZ(float64(rand.Intn(2)-rand.Intn(2)), nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue