Frage

Ich versuche, meine Gedanken um die beste Art und Weise zu wickeln verschachtelte Zustandsübergänge in einer Single-Threaded-Programmiersprache (Actionscript) zu implementieren. Sagen, dass ich eine Struktur wie dieses Verhalten Baum habe: Verhalten Baum

Nun stell dir vor, dass jeder Blattknoten ein Zielpunkt auf einer Website ist, wie ein Bild in einer Galerie oder einen Kommentar in einer post-Ansicht in einer Seitenansicht verschachtelt verschachtelt ... Und das Ziel ist in der Lage sein, animierte zu laufen Übergänge vom Blattknoten zum Blattknoten, die von dem vorherigen Baum (von unten nach oben) animieren heraus und in dem aktuellen Baum animieren (von oben nach unten).

Wenn wir also in den unteren linken meisten Blattknoten waren, und wollten wir unten rechts am weitesten Blattknoten gehen, würden wir müssen:

  • Übergang aus unteren linken Knoten
  • auf vollständig (sagt nach einer Sekunde der Animation), Übergang aus seinen Eltern,
  • auf vollständigen Übergang aus seinen Eltern
  • auf vollständigen Übergang in der am weitesten rechts stehenden Mutter
  • auf vollständigen Übergang in ganz rechts-Kind
  • auf vollständige, Übergang in Blatt

Meine Frage ist:

Wenn Sie jede dieser Knoten als HTML-Ansichten vorstellen (wo die Blätter sind ‚partials‘, den Begriff von Schienen zu leihen) oder MXML Ansichten, wo Sie nisten Subkomponenten, und Sie müssen das Nest nicht wissen Ebene aus der Anwendung Wurzel, was ist der beste Weg, um den Übergang zu animieren, wie oben beschrieben?

Eine Möglichkeit ist es, alle möglichen Pfade global zu speichern und dann zu sagen: „Anwendung, Übergang aus diesem Pfad Übergang in diesem Pfad“. Das funktioniert, wenn die Anwendung ist sehr einfach. Das ist, wie Gaia tut es, einen Actionscript-Framework. Aber wenn Sie es wollen, um den Übergang zu der Lage sein, in / out beliebig verschachtelt Pfaden, können Sie nicht, dass speichern global, weil:

  1. Action konnte nicht damit umgehen alle, dass die Verarbeitung
  2. scheint nicht wie eine gute Kapselung

So kann diese Frage als umformuliert wird, , wie Sie das am weitesten links stehenden Blattknoten und es Eltern tun animieren aus dem Blatt beginnen und belebter in dem am weitesten rechts-Blattknoten, beginnend mit der Wurzel ? Wo werden diese Informationen gespeichert (was für den Übergang in und out)?

Ein andere mögliche Lösung wäre einfach zu sagen: „Anwendung, Übergang aus früherem Kind-Knoten, und wenn das ist komplett, Übergang im aktuellen Kindknoten“, wo der „Kindknoten“ ist das direkte Kind der Anwendung Wurzel. Dann wird das am weitesten links Kind der Anwendung Wurzel (die zwei Knoten untergeordnet ist, die jeweils zwei Kindknoten haben), würde prüfen, ob es im richtigen Zustand ist (wenn es Kinder sind ‚transitioned out‘). Wenn nicht, würde es nennen „transitionOut ()“ auf ihnen ... Auf diese Weise alles vollständig gekapselt werden würde. Aber es scheint so, dass sein würde ziemlich rechenintensiv.

Was denken Sie? Haben Sie andere Alternativen? Oder können Sie mir zu jedem guten Ressourcen verweisen auf AI Behavior Bäume oder Hierarchical State Machines, die beschreiben, wie sie praktisch asynchrone Zustandsübergänge implementieren:

  • Von wo rufen sie „transitionOut“ auf ein Objekt? Von der Wurzel oder einem bestimmten Kind?
  • Wo ist der Zustand gespeichert? Weltweit vor Ort? Was ist der Umfang zu definieren, was "transitionIn ()" und "transitionOut ()"?
  • ruft

Ich habe viele Artikel / Bücher über AI und State Machines gesehen / gelesen, aber ich habe noch etwas zu finden, die beschreiben, wie sie tatsächlich asychronous / animierte Übergänge in einem komplexen MVC Objekt mit 100s von Ansichten Orientiertes Projekt implementieren / teilnehmenden Graphics in der Verhalten Baum.

nennen sollte ich die Übergänge von der Eltern-Objekt die meisten, oder von dem Kind?

Hier sind einige der Dinge, die ich untersucht habe:

Dies ist zwar nicht unbedingt ein AI Problem ist, gibt es keine andere Ressourcen beschreiben, wie verschachtelten Zustand Architekturen auf Websites anzuwenden; Dies sind die nächsten Dinge.

Eine andere Art und Weise zu Wort die Frage: Wie Sie Statusänderungen an die Anwendung gesendet haben? Wo bewahren Sie die Event-Listener? Wie finden Sie, was zu animieren sehen, wenn es beliebig verschachtelt ist?

. Hinweis: Ich versuche nicht, um ein Spiel zu bauen, nur versucht, animierte Websites erstellen

War es hilfreich?

Lösung

Ich werde versuchen, das Problem zu vereinfachen, bevor ein möglicher Ansatz vorschlagen. Die Übergänge scheinen die Ansichten verwendet und nicht das Modell. Wenn ich die Übergänge überspringen war und gerade zu einem anderen Blattknoten geht, noch die Anwendung funktioniert, aber es gibt keinen visuellen Hinweis für die Benutzer. Also schlage ich vor, würden Sie einen View-Controller verwenden, die speziell den aktuellen Zweig und die Übergänge der verschiedenen Ansichten halten.

Es ist wahrscheinlich ein besserer Ansatz, um die zwei Arten von Übergängen in eine Art Stapel aufzuteilen, wo ein Pop Übergang zu einem vorherigen Knoten zurück zu gehen, während ein Push-Übergang nach vorn in der Hierarchie geht. Apple eine ähnliche Technik verwendet Navigationsanwendungen verwalten mit einem Navigationsansicht Controller . Es unterhält im Grunde einen Stapel von View-Controller, dass der Benutzer zu einem bestimmten Knoten erhalten gefolgt. Wenn ein Benutzer zurück geht, wird das oberste Element aus dem Stapel geholt, und der Benutzer sieht das vorherige Element. Wenn der Benutzer tiefer in der Hierarchie geht, ein neuer View-Controller wird auf den Stapel geschoben.

Sie würden immer noch eine globale Art und Weise müssen die Hierarchien in einer Fliegengewicht Weise darzustellen, während die Navigationsstapel nur den aktuell sichtbaren Zweig speichern bis zu dem Blattknoten.

Wenn ein Benutzer von einem Blattknoten zum anderem geht, wird der aktuelle Stapel bis zu den gemeinsam Eltern werden taucht aus. Dann wird die globale Baumstruktur aufgefordert werden, den Weg bis zu dem neuen Blattknoten von diesem Elternteil zu erhalten. Dieser Pfad von Knoten wird in den aktuellen Navigations Stapel geschoben, und da jedes Element gedrückt wird, wird der Übergang gezeigt.

In einem einfachen Algorithmus, gäbe es diese beiden Datenstrukturen und eine Möglichkeit, die gesamte Branche zu erhalten, den Blattknoten enthält:

  1. eine globale Darstellung des Baumes
  2. ein Stapel des aktuellen Zweiges

am Anfang:

stack = []
tree = create-tree()

Algorithmus:

// empty current branch upto the common ancestor, root node if nothing else
until stack.peek() is in leaf-node.ancestors() {
    stack.pop() // animates the transition-out
}
parent = stack.peek();
// get a path from the parent to leaf-node
path = tree.get-path(parent, leaf-node)
for each node in path {
    stack.push(node) // animates the transition-in
}

Aktualisieren :

Die gesamte Anwendung könnte einen einzigen Navigationscontroller hat, oder mehrere solche Steuerungen. Ein Navigationscontroller muss nur wissen, dass es ein Baum ist, die bestimmten Operationen aussetzt. So könnte man eine Schnittstelle mit diesen Operationen erstellen und lassen konkrete Subklassen, dass implementieren.

Ich kann nur von zwei Operationen denkt, die ausgesetzt werden müßte (pseudo-Java-Syntax):

interface Tree {
    List<Node> getAncestors(node);
    List<Node> findPath(ancestorNode, descendantNode);
}

Das sollte genügend Abstraktion bietet die Navigationssteuerung Stossen in der globalen Baumstruktur zu halten. Um es auf die nächste Stufe zu nehmen, verwenden Sie Dependency Injection so das Baumobjekt in die Navigation eingespritzt wird, Controller, die Verbesserung der Testbarkeit und brechen der Baum Verbindung vollständig.

Andere Tipps

ich raten ich gerade hier, aber Sie können speichern diesen Baum in einem tatsächlichen Baum in Ihrem Code und dann, wenn darauf geklickt Sie eine Funktion navigieren möchten aufrufen, die aufgerufen wird, sagen wir, FindPath (fromnode, toNode), die Funktion finden der Weg zwischen den beiden Knoten, eine Möglichkeit, dass mit diesem Pseudo-Code zu tun:

Define array1;
Define array2;

loop while flag is false {
    store fromNode's parent node in array1;
    store toNode's parent node in array2;

    loop through array1 {
        loop through array2 {
            if array1[i] == array2[j] {
             flag = true;
            }
        }
    }
}

path = array1 + reverse(array2);

Und es ist dein Weg.

UPDATE:

Eine andere Lösung würde jede Seite etwas zu machen sein, wie diese Pseudo-Code - ich bin beginnen, um wirklich Liebe Pseudo-Code:

function checkChildren(targetNode) {
    loop through children {
        if children[i] == target {
            return path;
        }
        if children[i].checkChildren == target node {
            return path;
        }
    }
}

Dieses sehr sehr abstrakt ist, ist es viel mehr Details zu ihm hat und viele Optimierungen, hier ist was ich im Sinn haben:

  • Führen Sie den Pfad, den Baum zu der Funktion gehen, so kann der Weg, sondern direkt an die anrufende Funktion der Rückkehr zu finden.
  • Führen Sie das aktuelle rufenden Kind zu den Eltern checkChildren, damit es nicht die Mühe wird das Kind Überprüfung schneller machen zu überprüfen.

Ich denke immer noch, habe ich meine Idee nicht gut geliefert, damit ich es zu erklären, würde es versuchen.

Sagen Sie von pic2 in der Galerie zu project3 in Projekten geht.

pic2 würde seine Kinder (falls vorhanden) überprüfen, wenn es das Ziel findet es dort geht, sonst nennt es seine Eltern (Galerie) 's checkChildren vorbei sich an die Eltern wird überprüft es nicht stören, und vorbei sich die Eltern in einer Reihe, so dass die Eltern wissen, welchen Weg genommen hat.

Die Eltern überprüft seine Kinder, wenn einer von ihnen das Ziel, wenn es es fügt sich und das Kind auf den Pfad-Array und das ist der Weg.

Wenn es keiner seiner direkten Kinder das Ziel dann nennt es jeder seiner Kinder checkChildren Zugabe sich der Pfad zu dem Array übergeben, so dass, wenn einer ihrer Kinder das Ziel findet, es fügt sich und das Kind zu dem Array und Sie haben Ihren Weg.

Galerie ruft seine Eltern (Homepage) 's Scheck Kinder vorbei selbst und die Zugabe von selbst auf das Array des Wegs

Wenn keines der Kinder das Ziel.

Die Homepage überprüft alle seine Kinder außer Galerie mit der gleichen Methode.

Alternativ können Sie den Pfad nicht als Array übergeben, sondern nur Übergang zur Elternseite, wenn keines der Kinder oder die Kinder Kinder passen führt, dass Sie sicher sind, dass das Ziel nicht unter dieser Seite.

Ich hoffe, dass ich mich klar ausgedrückt. Ich kann checkChildren für Sie schreiben, wenn Sie wollen.

entweder ich nicht ganz verstehen Sie Problem, oder Sie machen es viel zu kompliziert ... versuchen einfach zu denken, denn im Grunde alles, was Sie tun wollen, ist die folgende:

  1. abrufen einen Pfad in einem Baum
  2. nacheinander mehrere Animationen ausführen (entlang dieser sehr Pfad)

keines dieser Dinge ist viel zu hart. für letztere Aufgabe kann wahrscheinlich, Sie eines der besseren AS3 Animation Bibliotheken. aber aus Gründen des Verständnisses, lassen Sie mich Ihnen eine leichte Lösung:

Ihr Problem einfach sequentiell asynchrone Aufgaben ausführt. die Sequenz Abrufen selbst ist nicht wirklich schwer. Sie sollten jedoch bedenken, dass nicht jeder Weg durch die Wurzel geht (zum Beispiel von einem Blatt auf seine sibbling). in der Flash-Welt, die einzige Möglichkeit, asynchrone Aufgaben ausführen sequentiell Rückrufe sind. wenn eine Aufgabe abgeschlossen ist, ruft sie zurück und von dort entscheiden, was als nächstes zu tun.

so kommt hier einige Code:

lassen Sie uns zuerst definieren eine Schnittstelle für alle Ihre Blätter / Knoten ... Folgendes sollte es tun:

package  {
    public interface ITransitionable {
     //implementors are to call callback when the show/hide transition is complete
     function show(callback:Function):void;
     function hide(callback:Function):void;
     function get parent():ITransitionable;
    }
}

nun die folgende Klasse in der Lage, Übergänge zu tun, wie Sie auf den Bäumen von ITransitionable angegeben:

package  {
 public class Transition {
  ///Array of animation starting functions
  private var funcs:Array;
  ///Function to call at the end of the transition
  private var callback:Function;
  public function Transition(from:ITransitionable, to:ITransitionable, callback:Function) {
   this.callback = callback;
   this.funcs = [];
   var pFrom:Array = path(from).reverse();
   var pTo:Array = path(to).reverse();
   while ((pFrom[0] == pTo[0]) && (pTo[0] != null)) {//eliminate common path to root
    pFrom.shift();
    pTo.shift();
   }
   pFrom.reverse();//bring this one back into the right order
   //fill the function array:
   var t:ITransitionable;
   for each (t in pFrom) this.funcs.push(hider(t));
   for each (t in pFrom) this.funcs.push(shower(t));
   this.next();
  }
  ///cancels the overall transition
  public function cancel():void {
   this.funcs = [];
  }
  ///creates a function that will start a hiding transition on the given ITransitionable.
  private function hider(t:ITransitionable):Function {
   return function ():void {
    t.hide(this.next());
   }
  }
  ///@see hider
  private function shower(t:ITransitionable):Function {
   return function ():void {
    t.show(this.next());
   }
  }
  ///this function serves as simple callback to start the next animation function
  private function next(...args):void {
   if (this.funcs.length > 0) this.funcs.shift()();
   else this.callback();
  }
  ///returns the path from a node to the root
  private function path(node:ITransitionable):Array {
   var ret:Array = [];
   while (node != null) {
    ret.push(node);
    node = node.parent;
   }
   return ret;
  }
 }

}

es ist keine perfekte Schönheit, aber es sollte Sie in die richtige Richtung weisen ausreichen. keine Notwendigkeit für Phantasie-State-Maschinen, was so überhaupt ... hoffe, das hilft ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top