如何倒退申请状态?

时间:2009-07-07 13:25:17

标签: java state

我正在开发Java桌面飞行模拟。我需要记录驾驶舱内发生的所有飞行员动作,例如油门控制,转向,武器部署等,以便我可以在以后查看这些事件(或将它们直播)。

我想在回放事件时添加一个视觉重播功能,这样我就能在视觉上看到驾驶舱,因为我及时向前和向后移动。只要我按照时间顺序播放事件,重放就没有问题,但倒带有点棘手。

您将如何实施快退功能?

6 个答案:

答案 0 :(得分:3)

我会使用修改后的Memento pattern

不同之处在于我会让Memento对象存储所有试点行动的清单。

Memento模式通常用于回滚(撤消),但在您的情况下,我也可以看到它也适用。您还需要将试点操作设置为可存储状态。

答案 1 :(得分:2)

您可以使用Command Pattern的变体,让每个试点操作都执行撤消操作。

例如,如果你的飞行员让行动转向左(简单,我知道),它的反向将是正确的。

public interface IPilotAction {
    void doAction(CockpitState state);
    void undoAction(CockpitState state);
}

public class ThrottleControl implement IPilotAction {

     private boolean increase;
     private int speedAmount;

     public ThrottleControl(boolean increase, int speedAmount) {
         this.increase = increase;
         this.speedAmount = speedAmount;
     }

     public void doAction(CockpitState state) {
         if (increase) {
            state.speed += speedAmount;
         } else {
            state.speed -= speedAmount;
         }
     }

     public void undoAction(CockpitState state) {
         if (increase {
             state.speed -= speedAmount;
         } else {
             state.speed += speedAmount;
         }
}

答案 2 :(得分:1)

您正在寻找的实际上是CommandMemento模式的混合。每个试点操作都应该是您可以记录的命令。如果需要,每个记录的命令都有一个纪念品,记录(A)不在命令中的任何附加状态,并且(B)不能可靠地重建。 “B”很重要,在很多任何非平凡的领域都有一些这种状态。需要存储它以恢复准确的重建。

如果您合并这些概念,基本上将纪念品附加到每个命令,您将拥有完整记录的一系列确定性事件。

我在different answer中详细讨论了这个问题。不要害怕根据您的具体需求大幅调整设计模式。 :)

RE性能问题:

如果您希望跳过几分钟成为常见情况,并且在实施后您表明这是一个不可行的性能瓶颈,我建议实施偶尔的“快照”以及日志记录机制。基本上每隔几分钟保存一次整个应用程序状态,以最大限度地减少您需要执行的日志滚动量。然后,您可以从最近保存的状态访问所需的时间范围。这类似于动画和媒体中的key frames

答案 3 :(得分:0)

不是直接的答案,但请查看有关实施撤消的讨论。大多数情况下,它们都是关于文本编辑器的,但应该适用相同的原则。

如果您更喜欢不变性,这会有所帮助。撤消复杂的更改很困难。即使是自动化系统也存在性能问题(软件事务内存,STM)。

答案 4 :(得分:0)

确保以模拟“状态”为函数的方式实现模拟。也就是时间的函数。

鉴于T0时的初始状态,您应该能够在任何Tn的时间n构建模拟框架。例如,初始静止状态和没有事件(尚未)可能等同于身份函数,因此Tn == Tn+1

Ta时间举行一些试点活动事件时,您应该能够为任何Ta+n构建一个n帧。因此,您将事件视为修改一个以时间值作为参数的函数,并返回该时间的模拟框架。

我将事件历史实现为表示模拟控制状态的Zipper(时间,函数)对。 “当前”状态将成为焦点,右侧是未来状态列表,左侧是过去状态。像这样:

([past], present, [future])

每次模拟状态发生变化时,都会在future中记录新的状态函数。然后运行模拟就变成了从future列表中取出函数并将当前时间传递给它们的问题。向后运行完全相同,只是您将事件从past列表中取出。

因此,如果您正好赶上Tn,并希望快退到时间Tn-1,请查看past列表,了解time属性较少的最新状态比n-1。将n-1传递到其function属性,您就可以在Tn-1时获得模拟状态。

I've implemented a Zipper datastructure in Java, here.

答案 5 :(得分:0)

您可以在每个实例中存储状态。状态为1kb(风速,物体速度+方向/控制输入状态,x 30fps x 20 min~36megs。1kb状态可让您记录约16个物体(位置/速度/角速度/方向/和5轴控制/效果)

对您来说可能太多了,但实施起来最容易。根本不需要做任何工作来重建状态(即时acecss),你可以非常容易地在状态之间进行插值(用于更快/更慢的回放)。对于磁盘空间,您可以将其压缩,并且可以在录制时完成,因此在播放时,内存不会被占用。

节省空间的一种快捷方法是对记录文件进行分页,并分别压缩每个bin。即每分钟一个拉链流。这样你只需要解压缩当前的bin,就可以节省一大堆内存,但这取决于你的状态数据的压缩程度。

录制命令并让您的类文件实现多个播放方向需要大量的调试工作。减慢/加速回放也将更加计算密集。你唯一能节省的就是空间。

如果这是一个溢价,还有其他方法可以节省。