我正在开发Java桌面飞行模拟。我需要记录驾驶舱内发生的所有飞行员动作,例如油门控制,转向,武器部署等,以便我可以在以后查看这些事件(或将它们直播)。
我想在回放事件时添加一个视觉重播功能,这样我就能在视觉上看到驾驶舱,因为我及时向前和向后移动。只要我按照时间顺序播放事件,重放就没有问题,但倒带有点棘手。
您将如何实施快退功能?
答案 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)
您正在寻找的实际上是Command和Memento模式的混合。每个试点操作都应该是您可以记录的命令。如果需要,每个记录的命令都有一个纪念品,记录(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
时获得模拟状态。
答案 5 :(得分:0)
您可以在每个实例中存储状态。状态为1kb(风速,物体速度+方向/控制输入状态,x 30fps x 20 min~36megs。1kb状态可让您记录约16个物体(位置/速度/角速度/方向/和5轴控制/效果)
对您来说可能太多了,但实施起来最容易。根本不需要做任何工作来重建状态(即时acecss),你可以非常容易地在状态之间进行插值(用于更快/更慢的回放)。对于磁盘空间,您可以将其压缩,并且可以在录制时完成,因此在播放时,内存不会被占用。
节省空间的一种快捷方法是对记录文件进行分页,并分别压缩每个bin。即每分钟一个拉链流。这样你只需要解压缩当前的bin,就可以节省一大堆内存,但这取决于你的状态数据的压缩程度。
录制命令并让您的类文件实现多个播放方向需要大量的调试工作。减慢/加速回放也将更加计算密集。你唯一能节省的就是空间。
如果这是一个溢价,还有其他方法可以节省。