Java 如何倒带应用程序状态?
我正在开发一个Java桌面飞行模拟。我需要记录驾驶舱中发生的所有飞行员动作,如油门控制、转向、武器部署等,以便我以后可以查看这些事件(或实时流媒体) 我想在事件回放中添加一个可视化回放功能,这样我可以在时间上前后移动时直观地看到驾驶舱。只要我按时间顺序回放事件,回放就没有问题,但是回放有点棘手Java 如何倒带应用程序状态?,java,state,Java,State,我正在开发一个Java桌面飞行模拟。我需要记录驾驶舱中发生的所有飞行员动作,如油门控制、转向、武器部署等,以便我以后可以查看这些事件(或实时流媒体) 我想在事件回放中添加一个可视化回放功能,这样我可以在时间上前后移动时直观地看到驾驶舱。只要我按时间顺序回放事件,回放就没有问题,但是回放有点棘手 如何实现倒带功能?您可以使用的变体,并让每个引导操作实现撤消操作 例如,如果你的飞行员做了向左转向(很简单,我知道)的动作,相反的动作是向右转向 public interface IPilotAction
如何实现倒带功能?您可以使用的变体,并让每个引导操作实现撤消操作 例如,如果你的飞行员做了向左转向(很简单,我知道)的动作,相反的动作是向右转向
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;
}
}
我会用修改过的
不同之处在于,我会让Memento对象存储所有试点行动的列表
Memento模式通常用于回滚(undo),但是在您的情况下,我可以看到它也适用。您还需要使先导操作具有可存储状态。您所寻找的实际上是和模式的混合。每个引导操作都应该是一个可以记录的命令。如果需要,每个记录的命令都有一个记忆体,记录(a)不在命令中,以及(B)无法可靠重建的任何附加状态。“B”很重要,在几乎任何非平凡的领域中都存在这种状态。需要存储它以恢复精确的重建 如果合并这些概念,本质上是在每个命令上附加一个memento,那么将有一系列完整的确定性事件记录 我在一篇文章中更详细地讨论了这个问题。不要害怕根据您的具体需求对设计模式进行实质性调整。:) 重新性能问题:
如果您认为跳转几分钟是一种常见的情况,并且在实现之后您发现这是一个不可行的性能瓶颈,那么我建议在日志机制的同时实现一个偶尔的“快照”。实际上,每隔几分钟保存一次整个应用程序状态,以最大限度地减少需要执行的日志滚动量。然后,您可以从最近保存的状态访问所需的时间范围。这与在动画和媒体中类似。这不是一个直接的答案,但请查看关于实现撤消的讨论。它们主要是关于文本编辑器的,但同样的原则也应该适用
如果你喜欢不变性,它会有帮助。撤销复杂的变化是困难的。即使是自动化系统也存在性能问题(软件事务内存,STM)。确保您以模拟的“状态”是功能的方式实施模拟。也就是说,时间的函数 给定时间
T0
的初始状态,您应该能够在时间Tn
为任何n
构建模拟帧。例如,初始静止状态和无事件(尚未)可能等于标识函数,因此Tn==Tn+1
给定时间Ta
的一些飞行员动作事件,您应该能够为任何n
构建帧Ta+n
。因此,您可以将事件视为修改一个函数,该函数将时间值作为参数,并返回该时间的模拟帧
我将把事件的历史实现为表示模拟控制状态的(时间、函数)对。“当前”状态将成为焦点,右边是未来状态列表,左边是过去状态列表。像这样:
([past], present, [future])
每次模拟状态发生变化时,在未来的中记录一个新的状态函数。然后,运行模拟就变成了从future
列表中取出函数并将当前时间传递给它们的问题。向后运行它完全相同,只是您将事件从pass
列表中取出
因此,如果您在时间Tn
处,并且想要倒回时间Tn-1
,请查看过去的
列表,查找时间
属性小于n-1
的最新状态。将n-1
传递到其函数
属性中,您就拥有了时间Tn-1
的模拟状态
您可以只存储每个实例的状态。1kb的状态(风速、物体速度+方向/控制输入状态,x 30fps x 20 min~36megs。1kb的状态可让您记录大约16个物体(位置/速度/角速度/方向/和5个控制/效果轴)
这可能对您来说太多了,但它将是最容易实现的。重新创建状态(即时acecss)不需要做任何工作,而且您可以非常轻松地在状态之间进行插值(以便更快/更慢地播放).对于磁盘空间,您可以压缩它,这可以在录制时完成,因此在播放时不会占用内存
节省空间的一种快速方法是对记录文件进行分页,并分别压缩每个文件箱。即每分钟压缩一个压缩流。这样,您只需解压缩当前文件箱,节省大量内存,但这取决于状态数据的压缩程度
录制命令和让类文件实现多个方向的播放需要大量调试工作。减慢/加快播放速度也会增加计算量。而唯一节省的是空间
如果这是额外的,还有其他方法可以节省时间。这种方法对飞行sim卡的性能可以接受吗?例如,如果我回放事件20分钟,然后决定跳转到时间2分钟,我必须撤消18分钟的事件。可能有数百个事件要撤消。这取决于。你的数据越多撕扯每一个动作,你会得到更大的回应