Я пытаюсь перенести свой ум вокруг лучшего способа реализовать вложенные изменения состояния на единственном потоковом языке программирования (Actionscript). Скажите, что у меня есть структура как это дерево поведения:
Теперь предположите, что каждая вершина является пунктом назначения на веб-сайте, как изображение в галерее или комментарий, вложенный в представлении сообщения, вложенном в просмотре страницы... И цель состоит в том, чтобы смочь выполнить анимированные переходы от вершины до вершины путем анимации предыдущего дерева (от нижней части до вершины) и анимации в текущем дереве (сверху донизу).
Так, если бы мы были в нижней левой больше всего вершине, и мы хотели перейти к нижней правой больше всего вершине, то мы имели бы к:
Мой вопрос:
Если Вы воображаете каждый из этих узлов как режимы просмотра HTML (где листы являются 'partials', одалживая термин у направляющих), или представления MXML, где Вы - вложение sub компоненты, и Вы не обязательно знаете уровни вложенного множества от корневого каталога приложения, что лучший способ состоит в том, чтобы анимировать переход, как описано выше?
Один путь состоит в том, чтобы сохранить все возможные пути глобально, и затем сказать "Приложение, переход этот путь, переход в этом пути". Это работает, если приложение очень просто. Это - то, как Gaia делает это, платформа Actionscript. Но если Вы хотите, чтобы это смогло перейти в / произвольно вложенных путях, Вы не можете сохранить это глобально потому что:
Таким образом, этот вопрос может быть перефразирован как, как Вы анимируете left-most-leaf узел, и это - родители, начинающие с листа, и анимационный в right-most-leaf узле, начиная с корня? Где та информация хранится (что перейти в и)?
Другое возможное решение состояло бы в том, чтобы просто сказать "Приложение, переход предыдущий дочерний узел, и когда это завершено, переход в текущем дочернем узле", где "дочерний узел" является прямым ребенком корневого каталога приложения. Затем крайний левый ребенок корневого каталога приложения (который имеет два дочерних узла, которые у каждого есть два дочерних узла), проверил бы, находится ли это в правильном состоянии (если это - дети, ' переходятся'). В противном случае это звонило бы "transitionOut ()" на них... Тем путем все полностью инкапсулировалось бы. Но кажется, что это было бы симпатичным интенсивным процессором.
Что Вы думаете? У Вас есть какие-либо другие альтернативы? Или можете Вы указывать на меня на любые хорошие ресурсы на Деревьях Поведения AI или Иерархических конечных автоматах, которые описывают, как они практически реализуют асинхронные изменения состояния:
Я видел/читал много статей/книг о AI и Конечных автоматах, но я должен все же найти что-то описывающее, как они на самом деле реализуют asychronous/animated переходы в сложном MVC Объектно-ориентированный Проект с 100 с Представлений/Графики, участвующих в дереве поведения.
Я должен назвать переходы от родительского больше всего объекта, или от ребенка?
Вот некоторые вещи, которые я исследовал:
В то время как это - не обязательно проблема AI, нет никаких других ресурсов, описывающих, как применить вложенную архитектуру состояния к веб-сайтам; это самые близкие вещи.
Иначе к слову вопрос: Как Вы широковещательно передаете изменения состояния к приложению? Где Вы сохраняете слушателей события? Как Вы находите, какое представление анимировать, когда оно произвольно вкладывается?
Примечание: Я не пытаюсь создать игру, просто пытаясь создать анимированные веб-сайты.
Я постараюсь упростить проблему, прежде чем предложить возможный подход. Переходы, похоже, связаны с видами, а не моделью. Если бы я был пропустить переходы и перейти прямо к другому узеру листьев, приложение по-прежнему работает, но для пользователей не работает визуальная подсказка. Поэтому я предлагаю вам использовать контроллер просмотра специально для удержания текущей ветви и переходов различных видов.
Это, вероятно, лучший подход к разделению двух типов переходов в своего рода стек, в котором поп-переход должен вернуться к предыдущему узлу, в то время как продвижение переход вперед в иерархии. Apple использует аналогичную технику для управления навигационными приложениями с использованием контроллера навигационного представления . Он в основном поддерживает стопку контроллеров представления, что пользователь должен добраться до определенного узла. Когда пользователь возвращается, верхний элемент выскочит со стека, и пользователь видит предыдущий элемент. Если пользователь проходит глубже в иерархии, новый контроллер представления нажимается на стек.
Вам все равно понадобится глобальный способ представлять иерархии в манере излучения, в то время как стек навигации хранит только видимую ветку до узела листьев.
Если пользователь пошел с одного узла листьев в другой, текущий стек будет выскочен до общего родителя. Затем глобальная структура дерева будет предложена получить путь от этого родительского узела до нового узела листьев. Этот путь узлов выталкивается в текущий стек навигации, и поскольку каждый элемент нажата, показан переход.
В простом алгоритме есть эти две структуры данных и способ получить весь ветвь, который содержит узел листьев:
Изначально:
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);
}
, которые должны обеспечивать достаточную абстракцию, чтобы удержать контроллер навигации внутри глобальной структуры дерева. Чтобы взять его на следующий уровень, используйте впрыск зависимости , поэтому объект дерева вводится в контроллер навигации, улучшая защиту и полностью разрушать соединение дерева.
Я просто угадаю здесь, но вы можете хранить это дерево в настоящем дереве в вашем коде, а затем, когда нажал, вы хотите навигаться, вы называете функцию, называемую, скажем, 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;
}
}
}
Это очень очень абстрактно, имеет гораздо более подробную информацию Это и много оптимизаций, вот что я имею в виду:
Я все еще думаю, что я не доставлял свою идею хорошо, так что попробую это объяснить.
Скажем, вы идете с PIC2 в галерее к проектам в проектах.
PIC2 проверит бы свои дети (если есть), если он найдет цель, которая идет туда, в противном случае он называет его CheckChildren его родитель (галерее), передавающую себя к родителю, не будет проверять ее, и передавать себе к Родитель в массиве, поэтому родитель знает, какой путь был принят.
Родитель проверяет своих детей, если кто-либо из них является целью, если оно добавляет себя и ребенку на массив пути, и это путь.
Если ни один из его прямых детей не является целью, то он называет каждую из своих детей CheckChildren, проходящие добавляя себя в массив пути, чтобы, если каковере его дети найдут цель, которую он добавляет себя и ребенка в массив и У вас есть ваш путь.
Если ни один из детей не находит целевую галерею, называет его родительской (домашней страницей), четкие дети, проходящие в себе и добавляя себя к массиву пути.
Домашняя страница проверяет все свои дети, кроме галереи, используя тот же метод.
В качестве альтернативы вы можете не передавать путь в качестве массива, но вместо этого просто перейти на родительскую страницу, если ни один из детей или детских детей совпадают, потому что вы уверены, что цель не находится под этой страницей.
Я надеюсь, что я понял. Я могу написать CheckChildren для вас, если хотите.
либо я не до конца понимаю вашу проблему, либо вы делаете ее слишком сложной... попытайтесь думать просто, потому что в принципе, все, что вы хотите сделать, это следующее:
ни одна из этих вещей не является сложной. для последней задачи, вы, вероятно, можете использовать одну из лучших 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;
}
}
}
это не идеальная красота, но этого должно быть достаточно, чтобы направить вас в нужное русло. нет необходимости в причудливых государственных машинах, что бы ни случилось... надеюсь, это поможет...