Domanda

Sto cercando di avvolgere la mia mente intorno il modo migliore per attuare le transizioni di stato annidati in un unico linguaggio di programmazione threaded (Actionscript). Dire che ho una struttura come questo albero comportamento: albero di comportamento

Ora immaginate che ogni nodo foglia è un punto di destinazione su un sito web, come un'immagine in una galleria, o di un commento annidato in una visione post annidato in una vista pagina ... E l'obiettivo è quello di essere in grado di eseguire animato transizioni da nodo foglia al nodo foglia, animando l'albero precedente (dal basso verso l'alto), e animare nell'albero corrente (dall'alto verso il basso).

Quindi, se fossimo in basso a più a sinistra nodo foglia, e abbiamo voluto andare fino in fondo, più a destra nodo foglia, avremmo dovuto:

  • transizione fuori inferiore sinistro nodo
  • sul completo (diciamo dopo un secondo di animazione), la transizione fuori è genitore,
  • sul completo, transizione fuori è genitore
  • sul completo, transizione nel più a destra-genitore
  • il completo, la transizione in più a destra-figlio
  • sul completo, di transizione in foglia

La mia domanda è:

Se si immagina ciascuno di questi nodi come vista HTML (dove le foglie sono 'parziali', mutuando il termine da rotaie), o viste MXML, dove si sta nidificano componenti secondari, e non necessariamente conosce il nido livelli dalla radice applicazione, qual è il modo migliore per animare la transizione come descritto in precedenza?

Un modo è quello di memorizzare tutti i percorsi possibili a livello globale, e poi dire "Applicazione, passare questo percorso, la transizione in questo percorso". Che funziona se l'applicazione è molto semplice. Ecco come Gaia fa, un quadro Actionscript. Ma se si vuole che sia in grado di transizione in / out percorsi arbitrariamente nidificate, non è possibile memorizzare che a livello mondiale, perché:

  1. Actionscript non poteva gestire tutto ciò che l'elaborazione
  2. Non sembra buona incapsulamento

Quindi, la questione può essere riformulato come, come si fa a animare il nodo più a sinistra-foglia e genitori, a partire dalla foglia, e animare nel nodo più a destra-foglia, a partire dalla radice ? Dove è che le informazioni memorizzate (cosa per la transizione in e out)?

Un'altra possibile soluzione potrebbe essere quella di dire solo "Applicazione, la transizione dalla precedente nodo figlio, e quando questo è completo, transizione nel nodo figlio corrente", dove il "nodo figlio" è il figlio diretto della radice dell'applicazione. Poi il bambino più a sinistra della radice dell'applicazione (che ha due nodi figli, che hanno ciascuno due nodi figli), si controlla se è in stato di destra (se si tratta di bambini sono 'la transizione fuori'). In caso contrario, si chiamerebbe "transitionOut ()" su di loro ... In questo modo tutto sarebbe completamente incapsulato. Ma sembra che sarebbe abbastanza intensivo del processore.

Cosa ne pensi? Avete altre alternative? Oppure mi puoi puntare a qualsiasi buone risorse su AI Alberi comportamento o gerarchico macchine a stati che descrivono come implementare praticamente transizioni di stato asincrono:

  • Dal punto in cui lo chiamano "transitionOut" su un oggetto? Dalla radice o un bambino specifico?
  • Dove viene memorizzato lo stato? A livello globale, a livello locale? Qual è la portata che definisce ciò che chiama "transitionIn ()" e "transitionOut ()"?

Ho visto / letto molti articoli / libri su intelligenza artificiale e macchine a stati, ma devo ancora trovare qualcosa che descrive il modo in cui in realtà attuano transizioni asincrono / animate in un complesso oggetto MVC Oriented progetto con 100s di Vista / Graphics partecipare alla albero di comportamento.

Devo chiamare le transizioni dal genitore-più oggetto, o dal bambino?

Ecco alcune delle cose che ho esaminato:

Anche se questo non è necessariamente un problema di intelligenza artificiale, non ci sono altre risorse che descrivono come applicare le architetture statali annidati ai siti web; queste sono le cose più vicine.

Un altro modo per parola la domanda: Come si fa a trasmettere i cambiamenti di stato per l'applicazione? Dove tieni i listener di eventi? Come si fa a trovare che cosa vedere per animare quando è arbitrariamente annidato?

Nota: non sto cercando di costruire un gioco, solo cercando di costruire siti web animati

.
È stato utile?

Soluzione

Cercherò di semplificare il problema prima di proporre un possibile approccio. Le transizioni sembrano legati alle viste, e non il modello. Se dovessi saltare le transizioni e andare dritto a qualche altro nodo foglia, l'applicazione ancora funziona, ma non c'è indizio visivo per gli utenti. Quindi io suggerirei di usare un view-controller appositamente per contenere il ramo attuale e le transizioni delle varie viste.

E 'probabilmente un approccio migliore per dividere i due tipi di transizioni in una sorta di pila in cui una transizione pop è di tornare a un nodo precedente, mentre una transizione spinta va avanti nella gerarchia. Apple utilizza una tecnica simile per gestire le applicazioni di navigazione utilizzando un vista Navigation Controller . Mantiene sostanzialmente una pila di controller di vista che l'utente seguiti per arrivare a un particolare nodo. Quando un utente ritorna, il primo elemento viene estratto dallo stack, e l'utente vede la voce precedente. Se l'utente va più in profondità nella gerarchia, un nuovo controller visualizzazione viene inserito nello stack.

Si avrebbe ancora bisogno di un modo globale per rappresentare le gerarchie in maniera peso mosca, mentre lo stack di navigazione memorizza solo il ramo attualmente visibile fino al nodo foglia.

Se un utente è andato da un nodo foglia all'altra, lo stack corrente verrà spuntato fuori fino al genitore comune. Poi la struttura ad albero globale sarà chiesto di ottenere il percorso da quel genitore fino al nuovo nodo foglia. Questo percorso di nodi viene spinto nella pila navigazione corrente, e ogni elemento viene premuto, viene mostrata la transizione.

In un semplice algoritmo, non ci sarebbe queste due strutture di dati e un modo per ottenere l'intero ramo che contiene nodo foglia:

  1. una rappresentazione globale della struttura
  2. una pila del ramo corrente

inizialmente:

stack = []
tree = create-tree()

algoritmo:

// 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
}

Aggiorna :

L'intera applicazione potrebbe avere un unico controller di navigazione, o più di tali controllori. Un controller di navigazione ha solo bisogno di sapere che c'è un albero che espone alcune operazioni. Così si potrebbe creare un'interfaccia con quelle operazioni e lasciare sottoclassi concrete implementano questo.

Posso solo pensare di due operazioni che dovrebbero essere esposti (sintassi pseudo-Java):

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

Questo dovrebbe fornire astrazione sufficiente a mantenere il controller di navigazione frugando all'interno della struttura ad albero globale. Per portarlo al livello successivo, utilizzare dipendenza iniezione così l'oggetto ad albero viene iniettato nella navigazione controllore, migliorando controllabilità e rompendo completamente i collegamento dell'albero.

Altri suggerimenti

Sono solo indovinando qui, ma è possibile memorizzare quell'albero in un albero vero e proprio nel codice e poi, quando si fa clic si desidera navigare si chiama una funzione che si chiama, per esempio, findPath (fromnode, toNode) quella funzione troverà il percorso tra i due nodi, un modo per farlo è con questo codice pseudo:

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);

E c'è il vostro percorso.

UPDATE:

Un'altra soluzione potrebbe essere quella di rendere ogni pagina di avere qualcosa di simile a questo codice pseudo - sto cominciando a davvero l'amore pseudo codice:

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

Questo è molto molto astratta, ha molto di più dettagli ad esso e un sacco di ottimizzazioni, ecco quello che ho in mente:

  • passare il percorso salendo l'albero per la funzione in modo che il percorso può essere trovato direttamente invece di tornare alla funzione di chiamata.
  • Far passare il bambino di chiamata corrente ai genitori checkChildren in modo da non preoccuparsi di verificare quel bambino a fare il controllo più veloce.

Continuo a pensare che non ho consegnato la mia idea e quindi cercherò di spiegarlo.

Diciamo che sta andando dal pic2 nella galleria per progetto3 nei progetti.

pic2 controllerebbe i suoi figli (se del caso), se trova il bersaglio va lì, altrimenti si chiama il suo genitore (galleria) s 'checkChildren si passa al genitore non preoccuparsi controllarlo, e si passa alla genitore in un array in modo che il genitore sa quale strada è stata presa.

Il genitore controlla i suoi figli se qualcuno di loro è l'obiettivo, se è essa stessa e il bambino alla matrice percorso aggiunge e questo è il percorso.

Se nessuno dei suoi figli diretti è il bersaglio allora chiama ciascuno dei dei suoi figli checkChildren passaggio aggiungendosi alla matrice del percorso in modo che se uno dei suoi figli trova il bersaglio se stessa e il bambino alla matrice e aggiunge avete il vostro percorso.

Se nessuno dei bambini centra la porta galleria chiama i suoi genitori (home page) 's bambini Verifica se stessa che passa e la stessa aggiungendo alla matrice del percorso.

La homepage controlli tutti i suoi figli, ad eccezione della galleria utilizzando lo stesso metodo.

In alternativa, è possibile scegliere di non passare il percorso come un array, ma invece solo la transizione alla pagina superiore, se nessuno dei bambini o la partita i figli dei figli perche' siete sicuri il bersaglio non è in questa pagina.

Spero di stato chiaro. Posso scrivere checkChildren per voi, se si desidera.

o non pienamente ti capisco problema, o si stanno facendo è troppo complicato ... prova a pensare semplice, perché in fondo, tutto ciò che si vuole fare, è il seguente:

  1. recuperare un percorso all'interno di un albero
  2. eseguire animazioni multipla sequenziale (lungo quel percorso)

nessuna di queste cose è molto a duro. per quest'ultimo compito, probabilmente si può utilizzare una delle migliori librerie di animazione AS3. ma per il bene di comprensione, mi permetta di offrire una soluzione leggera:

il problema è semplicemente svolgendo compiti asincroni in modo sequenziale. recuperare la sequenza di per sé non è davvero difficile. tuttavia, si dovrebbe prendere in considerazione, che non ogni percorso passa attraverso la radice (ad esempio da una foglia alla sua sibbling). nel mondo flash, l'unico modo per eseguire le attività asincrone in sequenza sono callback. quando un compito finisce, essa richiama, e da lì si decide che cosa fare dopo.

così ecco che arriva un po 'di codice:

Per prima cosa, definiamo un'interfaccia per tutti i tuoi fogli / nodi ... il seguente dovrebbe fare il trucco:

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;
    }
}

ora la seguente classe sarà in grado di fare le transizioni come specificato sugli alberi di ITransitionable:

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;
  }
 }

}

non è una bellezza perfetta, ma dovrebbe essere sufficiente per puntare nella giusta direzione. Non c'è bisogno di macchine a stati di fantasia, che cosa così mai ... Spero che questo aiuti ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top