从嵌套状态转换到嵌套状态的最佳实践(参见图表)

Lan*_*ard 6 optimization actionscript state-machine hsm behavior-tree

我试图围绕在单线程编程语言(Actionscript)中实现嵌套状态转换的最佳方法.假设我有一个像这个行为树的结构:行为树

现在想象每个叶子节点是网站上的目标点,如图库中的图像,或嵌套在页面视图中嵌套的帖子视图中的注释......目标是能够从叶子运行动画过渡节点到叶节点,通过设置前一个树的动画(从下到上),并在当前树中设置动画(从上到下).

因此,如果我们位于最左下方的叶节点,并且我们想要转到最右下方的叶节点,我们必须:

  • 转换出左下方节点
  • 完成后(比如说动画一秒钟之后),转换出它的父级,
  • 完成后,转出它的父母
  • 完成后,转移到最右边的父母
  • 完成,最右边的孩子过渡
  • 完成,叶片过渡

我的问题是:

如果您将这些节点中的每一个想象为HTML视图(其中叶子是'partials',借用rails中的术语),或者MXML视图,那么您将嵌套子组件,并且您不一定知道嵌套级别来自应用程序root,如上所述,为转换设置动画的最佳方法是什么?

一种方法是全局存储所有可能的路径,然后说"应用程序,转换出此路径,在此路径中转换".如果应用程序非常简单,那就行.这就是Gaia如何做到的,一个Actionscript框架.但是,如果您希望它能够转换进/出任意嵌套路径,则无法全局存储,因为:

  1. Actionscript无法处理所有处理
  2. 似乎不是很好的封装

所以这个问题可以改写为,你如何动画最左边的叶子节点和它的父节点,从叶子开始动画,并在最右边的叶子节点中动画,从根开始? 存储的信息在哪里(转入和转出的内容)?

另一种可能的解决方案是只说"应用程序,转换出以前的子节点,以及何时完成,在当前子节点中转换",其中"子节点"是应用程序根的直接子节点.然后,应用程序根目录的最左边的子节点(具有两个子节点,每个子节点有两个子节点)将检查它是否处于正确的状态(如果它的子节点被"转出").如果没有,它会在它们上面调用"transitionOut()"......这样一切都将被完全封装.但似乎这对处理器来说非常密集.

你怎么看?你还有其他选择吗?或者你能指出我在AI行为树或分层状态机上的任何好资源,它们描述了它们实际上如何实现异步状态转换:

  • 他们从哪里在一个物体上称为"transitionOut"?从根或特定的孩子?
  • 国家存储在哪里?在全球范围内,在当地?什么是定义调用"transitionIn()"和"transitionOut()"的范围?

我已经看过/阅读过很多关于人工智能和状态机的文章/书籍,但我还没有找到描述他们如何在一个复杂的MVC面向对象项目中实现异步/动画过渡的方法,其中100个视图/图形参与了行为树.

我应该从最父对象或孩子那里调用转换吗?

以下是我检查过的一些事情:

虽然这不一定是人工智能问题,但没有其他资源描述如何将嵌套状态架构应用于网站; 这些是最接近的东西.

提出问题的另一种方式:如何向应用程序广播状态更改?你在哪里保留事件听众?如何在任意嵌套时找到动画视图?

注意:我不是想构建一个游戏,而是试图建立一个动画网站.

Anu*_*rag 1

在提出可能的方法之前,我会尝试简化问题。转换似乎与视图相关,而不是模型。如果我跳过转换并直接转到其他叶节点,应用程序仍然可以工作,但用户没有视觉线索。因此,我建议您专门使用视图控制器来保存当前分支和各种视图的转换。

将两种类型的转换拆分为某种堆栈可能是更好的方法,其中弹出转换返回到前一个节点,而推送转换则在层次结构中前进。Apple 使用类似的技术通过导航视图控制器来管理导航应用程序。它基本上维护了一堆视图控制器,用户可以遵循这些视图控制器来到达特定节点。当用户返回时,顶部项目将从堆栈中弹出,并且用户看到前一个项目。如果用户深入层次结构,则会将新的视图控制器推送到堆栈上。

您仍然需要一种全局方法来以享元方式表示层次结构,而导航堆栈仅将当前可见的分支存储到叶节点。

如果用户从一个叶节点转到另一个叶节点,则当前堆栈将弹出到公共父节点。然后全局树结构将被要求获取从父节点到新叶节点的路径。该节点路径被推送到当前导航堆栈中,并且当推送每个项目时,会显示转换。

在一个简单的算法中,有这两个数据结构和一种获取包含叶节点的整个分支的方法:

  1. 树的全局表示
  2. 当前分支的堆栈

最初:

stack = []
tree = create-tree()
Run Code Online (Sandbox Code Playgroud)

算法:

// 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
}
Run Code Online (Sandbox Code Playgroud)

更新

整个应用程序可以有一个导航控制器或多个这样的控制器。导航控制器只需要知道有一棵公开某些操作的树。因此,您可以使用这些操作创建一个接口,并让具体的子类实现它。

我只能想到两个需要公开的操作(伪Java语法):

interface Tree {
    List<Node> getAncestors(node);
    List<Node> findPath(ancestorNode, descendantNode);
}
Run Code Online (Sandbox Code Playgroud)

这应该提供足够的抽象来保持导航控制器在全局树结构中探查。要将其提升到一个新的水平,请使用依赖项注入,以便将树对象注入到导航控制器中,从而提高可测试性并完全中断树连接。