Лучшая практика для Перехода От Вложенного состояния до Вложенного состояния (см. схему),

Я пытаюсь перенести свой ум вокруг лучшего способа реализовать вложенные изменения состояния на единственном потоковом языке программирования (Actionscript). Скажите, что у меня есть структура как это дерево поведения: behavior tree

Теперь предположите, что каждая вершина является пунктом назначения на веб-сайте, как изображение в галерее или комментарий, вложенный в представлении сообщения, вложенном в просмотре страницы... И цель состоит в том, чтобы смочь выполнить анимированные переходы от вершины до вершины путем анимации предыдущего дерева (от нижней части до вершины) и анимации в текущем дереве (сверху донизу).

Так, если бы мы были в нижней левой больше всего вершине, и мы хотели перейти к нижней правой больше всего вершине, то мы имели бы к:

  • переход нижний левый узел
  • на полном (говорят после секунды анимации), переход это - родитель,
  • на полном переход это - родитель
  • на полном, переходе В самом правом родителе
  • на полном, переходе в праве больше всего - ребенок
  • на полном, переходе в листе

Мой вопрос:

Если Вы воображаете каждый из этих узлов как режимы просмотра HTML (где листы являются 'partials', одалживая термин у направляющих), или представления MXML, где Вы - вложение sub компоненты, и Вы не обязательно знаете уровни вложенного множества от корневого каталога приложения, что лучший способ состоит в том, чтобы анимировать переход, как описано выше?

Один путь состоит в том, чтобы сохранить все возможные пути глобально, и затем сказать "Приложение, переход этот путь, переход в этом пути". Это работает, если приложение очень просто. Это - то, как Gaia делает это, платформа Actionscript. Но если Вы хотите, чтобы это смогло перейти в / произвольно вложенных путях, Вы не можете сохранить это глобально потому что:

  1. Actionscript не мог обработать всю ту обработку
  2. Не походит на хорошую инкапсуляцию

Таким образом, этот вопрос может быть перефразирован как, как Вы анимируете left-most-leaf узел, и это - родители, начинающие с листа, и анимационный в right-most-leaf узле, начиная с корня? Где та информация хранится (что перейти в и)?

Другое возможное решение состояло бы в том, чтобы просто сказать "Приложение, переход предыдущий дочерний узел, и когда это завершено, переход в текущем дочернем узле", где "дочерний узел" является прямым ребенком корневого каталога приложения. Затем крайний левый ребенок корневого каталога приложения (который имеет два дочерних узла, которые у каждого есть два дочерних узла), проверил бы, находится ли это в правильном состоянии (если это - дети, ' переходятся'). В противном случае это звонило бы "transitionOut ()" на них... Тем путем все полностью инкапсулировалось бы. Но кажется, что это было бы симпатичным интенсивным процессором.

Что Вы думаете? У Вас есть какие-либо другие альтернативы? Или можете Вы указывать на меня на любые хорошие ресурсы на Деревьях Поведения AI или Иерархических конечных автоматах, которые описывают, как они практически реализуют асинхронные изменения состояния:

  • От того, где они называют "transitionOut" на объекте? От корня или определенного ребенка?
  • Где состояние хранится? Глобально, локально? Что объем определяет что вызовы, "переходящие ()" и "transitionOut ()"?

Я видел/читал много статей/книг о AI и Конечных автоматах, но я должен все же найти что-то описывающее, как они на самом деле реализуют asychronous/animated переходы в сложном MVC Объектно-ориентированный Проект с 100 с Представлений/Графики, участвующих в дереве поведения.

Я должен назвать переходы от родительского больше всего объекта, или от ребенка?

Вот некоторые вещи, которые я исследовал:

В то время как это - не обязательно проблема AI, нет никаких других ресурсов, описывающих, как применить вложенную архитектуру состояния к веб-сайтам; это самые близкие вещи.

Иначе к слову вопрос: Как Вы широковещательно передаете изменения состояния к приложению? Где Вы сохраняете слушателей события? Как Вы находите, какое представление анимировать, когда оно произвольно вкладывается?

Примечание: Я не пытаюсь создать игру, просто пытаясь создать анимированные веб-сайты.

6
задан SashaZd 5 November 2019 в 18:37
поделиться

3 ответа

Я постараюсь упростить проблему, прежде чем предложить возможный подход. Переходы, похоже, связаны с видами, а не моделью. Если бы я был пропустить переходы и перейти прямо к другому узеру листьев, приложение по-прежнему работает, но для пользователей не работает визуальная подсказка. Поэтому я предлагаю вам использовать контроллер просмотра специально для удержания текущей ветви и переходов различных видов.

Это, вероятно, лучший подход к разделению двух типов переходов в своего рода стек, в котором поп-переход должен вернуться к предыдущему узлу, в то время как продвижение переход вперед в иерархии. Apple использует аналогичную технику для управления навигационными приложениями с использованием контроллера навигационного представления . Он в основном поддерживает стопку контроллеров представления, что пользователь должен добраться до определенного узла. Когда пользователь возвращается, верхний элемент выскочит со стека, и пользователь видит предыдущий элемент. Если пользователь проходит глубже в иерархии, новый контроллер представления нажимается на стек.

Вам все равно понадобится глобальный способ представлять иерархии в манере излучения, в то время как стек навигации хранит только видимую ветку до узела листьев.

Если пользователь пошел с одного узла листьев в другой, текущий стек будет выскочен до общего родителя. Затем глобальная структура дерева будет предложена получить путь от этого родительского узела до нового узела листьев. Этот путь узлов выталкивается в текущий стек навигации, и поскольку каждый элемент нажата, показан переход.

В простом алгоритме есть эти две структуры данных и способ получить весь ветвь, который содержит узел листьев:

  1. глобальное представление дерева
  2. стопку текущего ветви

Изначально:

stack = []
tree = create-tree()

Алгоритм:

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

Обновление :

Все приложение может иметь один контроллер навигации или несколько таких контроллеров. Навигационный контроллер нужно только знать, что есть дерево, которое подвергает определенные операции. Таким образом, вы можете создать интерфейс с этими операциями и позволить бетонным подклассам реализовать это.

Я могу подумать только о двух операциях, которые нужно будет подвергаться воздействию (Pseudo-Java Syntax):

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

, которые должны обеспечивать достаточную абстракцию, чтобы удержать контроллер навигации внутри глобальной структуры дерева. Чтобы взять его на следующий уровень, используйте впрыск зависимости , поэтому объект дерева вводится в контроллер навигации, улучшая защиту и полностью разрушать соединение дерева.

1
ответ дан 17 December 2019 в 20:32
поделиться
-

Я просто угадаю здесь, но вы можете хранить это дерево в настоящем дереве в вашем коде, а затем, когда нажал, вы хотите навигаться, вы называете функцию, называемую, скажем, FindPath (fromnode, Tonode) Эта функция найдет путь между двумя узлами, одним способом сделать это с помощью этого псевдо-кода:

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

и есть ваш путь.

Обновление:

Другое решение было бы заставить каждую страницу есть что-то вроде этого псевдо-кода - я начинаю на самом деле любить псевдо-код:

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

Это очень очень абстрактно, имеет гораздо более подробную информацию Это и много оптимизаций, вот что я имею в виду:

  • пройти путь, идущий вверх по дереву на функцию, чтобы путь можно найти напрямую, вместо того, чтобы возвращать в функцию вызова.
  • Пройдите текущее призванное ребенку к родителям CheckChildren, чтобы он не решит проверять этого ребенка, чтобы сделать проверку быстрее.

Я все еще думаю, что я не доставлял свою идею хорошо, так что попробую это объяснить.

Скажем, вы идете с PIC2 в галерее к проектам в проектах.

PIC2 проверит бы свои дети (если есть), если он найдет цель, которая идет туда, в противном случае он называет его CheckChildren его родитель (галерее), передавающую себя к родителю, не будет проверять ее, и передавать себе к Родитель в массиве, поэтому родитель знает, какой путь был принят.

Родитель проверяет своих детей, если кто-либо из них является целью, если оно добавляет себя и ребенку на массив пути, и это путь.

Если ни один из его прямых детей не является целью, то он называет каждую из своих детей CheckChildren, проходящие добавляя себя в массив пути, чтобы, если каковере его дети найдут цель, которую он добавляет себя и ребенка в массив и У вас есть ваш путь.

Если ни один из детей не находит целевую галерею, называет его родительской (домашней страницей), четкие дети, проходящие в себе и добавляя себя к массиву пути.

Домашняя страница проверяет все свои дети, кроме галереи, используя тот же метод.

В качестве альтернативы вы можете не передавать путь в качестве массива, но вместо этого просто перейти на родительскую страницу, если ни один из детей или детских детей совпадают, потому что вы уверены, что цель не находится под этой страницей.

Я надеюсь, что я понял. Я могу написать CheckChildren для вас, если хотите.

1
ответ дан 17 December 2019 в 20:32
поделиться

либо я не до конца понимаю вашу проблему, либо вы делаете ее слишком сложной... попытайтесь думать просто, потому что в принципе, все, что вы хотите сделать, это следующее:

  1. получить путь внутри дерева
  2. выполнить несколько анимаций последовательно (по этому самому пути)

ни одна из этих вещей не является сложной. для последней задачи, вы, вероятно, можете использовать одну из лучших AS3-анимационных библиотек. но для понимания, позвольте мне предложить вам легкое решение:

ваша проблема заключается в последовательном выполнении асинхронных задач. получить саму последовательность не так уж и сложно. однако, вы должны учитывать, что не каждый путь проходит через корень (например, от одного листа до его сиблинга). в мире flash единственный способ последовательного выполнения асинхронных задач - это обратный вызов. когда одна задача заканчивается, она перезванивает, и оттуда вы решаете, что делать дальше.

так что вот код:

сначала давайте определим интерфейс для всех ваших листьев/узлов... следующее должно помочь:

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

теперь следующий класс сможет делать переходы, как вы указали на деревьях 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;
  }
 }

}

это не идеальная красота, но этого должно быть достаточно, чтобы направить вас в нужное русло. нет необходимости в причудливых государственных машинах, что бы ни случилось... надеюсь, это поможет...

0
ответ дан 17 December 2019 в 20:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: