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.
|
// Walk up game tree to find the nearest state in cache.
|
||||||
var st state
|
var st state
|
||||||
stack := []interface{}{x}
|
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 {
|
if s, found := cache[p]; found {
|
||||||
st = s
|
st = s
|
||||||
break
|
break
|
||||||
|
@ -236,6 +236,8 @@ func (d *DrawDAG) unregisterOne(x DrawBoxer) {
|
||||||
}
|
}
|
||||||
// Remove from reverse chunk map
|
// Remove from reverse chunk map
|
||||||
delete(d.chunksRev, x)
|
delete(d.chunksRev, x)
|
||||||
|
// Remove from box cache
|
||||||
|
delete(d.boxCache, x)
|
||||||
// Remove from DAG
|
// Remove from DAG
|
||||||
d.dag.removeVertex(x)
|
d.dag.removeVertex(x)
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,63 +65,29 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (w, h int) {
|
||||||
|
|
||||||
// Update updates everything.
|
// Update updates everything.
|
||||||
func (g *Game) Update() error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
if sc, ok := c.(Scanner); ok {
|
||||||
// Need to do a similar trick for Draw: disabling a parent object should
|
for _, x := range sc.Scan() {
|
||||||
// disable the child objects.
|
if err := g.updateRecursive(x); err != nil {
|
||||||
// cache memoises the disabled state for each component.
|
return err
|
||||||
cache := map[interface{}]bool{
|
}
|
||||||
g: false,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
if c == g {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
u, ok := c.(Updater)
|
if u, ok := c.(Updater); ok {
|
||||||
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
|
|
||||||
return u.Update()
|
return u.Update()
|
||||||
})
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ident returns "__GAME__".
|
// Ident returns "__GAME__".
|
||||||
|
@ -145,30 +111,31 @@ func (g *Game) Parent(c interface{}) interface{} {
|
||||||
return g.par[c]
|
return g.par[c]
|
||||||
}
|
}
|
||||||
|
|
||||||
// WalkUp visits the component, its parent, its parent, ..., and then g.
|
func reverse(s []interface{}) {
|
||||||
func (g *Game) WalkUp(component interface{}, visit func(interface{}) error) error {
|
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||||
for p := component; p != nil; p = g.Parent(p) {
|
s[i], s[j] = s[j], s[i]
|
||||||
if err := visit(p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WalkDown visits g, the subcomponent of g, ..., and then the component.
|
func (g *Game) Path(component interface{}) []interface{} {
|
||||||
func (g *Game) WalkDown(component interface{}, visit func(interface{}) error) error {
|
|
||||||
var stack []interface{}
|
var stack []interface{}
|
||||||
g.dbmu.RLock()
|
g.dbmu.RLock()
|
||||||
for p := component; p != nil; p = g.Parent(p) {
|
for p := component; p != nil; p = g.Parent(p) {
|
||||||
stack = append(stack, p)
|
stack = append(stack, p)
|
||||||
}
|
}
|
||||||
g.dbmu.RUnlock()
|
g.dbmu.RUnlock()
|
||||||
for _, p := range stack {
|
reverse(stack)
|
||||||
if err := visit(p); err != nil {
|
return stack
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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.
|
// Show sets h to false.
|
||||||
func (h *Hides) Show() { *h = 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{}
|
type Components []interface{}
|
||||||
|
|
||||||
// Scan returns c.
|
// Scan returns c.
|
||||||
|
|
|
@ -21,6 +21,7 @@ type scener interface {
|
||||||
Disabler
|
Disabler
|
||||||
Hider
|
Hider
|
||||||
Identifier
|
Identifier
|
||||||
|
Registrar
|
||||||
Scanner
|
Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +40,21 @@ type Scene struct {
|
||||||
Hides
|
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.
|
// SceneRef loads a gzipped, gob-encoded Scene from the asset FS.
|
||||||
// After Load, Scene is usable.
|
// After Load, Scene is usable.
|
||||||
// This is mostly useful for scenes that refer to other scenes, e.g.
|
// 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 {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Add bubble to same parent as aw
|
||||||
par := aw.game.Parent(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 {
|
if r, ok := c.(engine.Registrar); ok {
|
||||||
return r.Register(bubble, par)
|
if err := r.Register(bubble, par); err != nil {
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
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 {
|
if p, ok := c.(engine.Prepper); ok {
|
||||||
return p.Prepare(aw.game)
|
return p.Prepare(aw.game)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,22 +71,24 @@ func (b *Bubble) Prepare(g *engine.Game) error {
|
||||||
func (b *Bubble) Update() error {
|
func (b *Bubble) Update() error {
|
||||||
b.Life--
|
b.Life--
|
||||||
if b.Life <= 0 {
|
if b.Life <= 0 {
|
||||||
if err := b.game.WalkUp(b, func(c interface{}) error {
|
for _, c := range b.game.ReversePath(b) {
|
||||||
b.game.Unregister(b)
|
if r, ok := c.(engine.Registrar); ok {
|
||||||
return nil
|
r.Unregister(b)
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(
|
b.Sprite.Actor.Pos = b.Sprite.Actor.Pos.Add(geom.Pt3(
|
||||||
// --lint:ignore SA4000 one random minus another is not always zero...
|
//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),
|
rand.Intn(3)-1, rand.Intn(2)-1, rand.Intn(2)-rand.Intn(2),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
b.Sprite.Actor.MoveX(float64(rand.Intn(3)-1), nil)
|
b.Sprite.Actor.MoveX(float64(rand.Intn(3)-1), nil)
|
||||||
b.Sprite.Actor.MoveY(float64(rand.Intn(2)-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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue