我正在用Java创建一个基于网格的游戏,我想实现游戏录制和播放。我不知道怎么做,虽然我已经考虑了两个想法:
每秒几次,我会记录整个游戏状态。为了回放它,我写了一个渲染器来读取状态并尝试创建一个可视化表示。但是,有了这个,我可能会有一个大的保存文件,任何播放尝试都可能会有明显的延迟。
我还可以将每个按键和鼠标点击写入保存文件。这会给我一个较小的文件,并可以减少滞后回放。但是,游戏开始时的最轻微错误(例如,1毫秒后拍摄)会在游戏进行几分钟后产生截然不同的游戏状态。
那么,实现游戏播放的最佳方式是什么?
编辑 - 我不确定我的游戏究竟有多确定,所以我不确定整个游戏是否只能通过按键和鼠标点击来拼凑。
答案 0 :(得分:14)
良好的播放机制不是可以简单地添加到游戏中而没有重大困难的东西。最好的方法是设计游戏基础设施。 command pattern可以用来实现这样的游戏基础设施。
例如:
public interface Command{
void execute();
}
public class MoveRightCommand implements Command {
private Grid theGrid;
private Player thePlayer;
public MoveRightCommand(Player player, Grid grid){
this.theGrid = grid;
this.thePlayer = player;
}
public void execute(){
player.modifyPosition(0, 1, 0, 0);
}
}
然后,当用户按下键盘按钮,移动鼠标或没有带回放机制的触发器时,可以将命令推入执行队列 。命令对象可以有一个时间戳值(相对于播放的开始),以便精确播放...
答案 1 :(得分:8)
Shawn Hargreaves最近在他的博客上发表了关于他们如何在MotoGP中实施重播的帖子。讨论了几种不同的方法及其优缺点。
http://blogs.msdn.com/shawnhar/archive/2009/03/20/motogp-replays.aspx
答案 2 :(得分:3)
假设您的游戏是确定性的,那么如果您记录了用户的输入(选项2)就足够了。但是,您需要确保识别这些事件的正确和一致的时间,例如服务器识别它们的时间。我不确定你是如何处理网格中的事件的。
我担心的是,如果您没有可以统一引用定时事件的机制,则代码处理分布式用户的方式可能存在问题。
例如,在XBOX 360上考虑像Halo 3这样的游戏 - 每个客户都记录他对游戏的看法,包括基于服务器的更正。
答案 3 :(得分:2)
为什么不记录几次,然后压缩输出,或者这样做:
recordInitialState();
...
runs 30 times a second:
recordChangeInState(previousState, currentState);
...
如果你只记录带有时间戳的状态变化(并且每个变化都很小,如果没有变化,那么什么都不记录),你应该得到合理的文件大小。
答案 4 :(得分:2)
无需为每一帧保存场景中的所有内容。逐步保存更改并使用一些好的插值技术。我不会真正使用基于命令模式的方法,而是以固定的速率为每个游戏对象进行检查,看看它是否已经改变了任何属性。如果存在更改,则会在某些良好的编码中记录更改,并且重放甚至不会变得那么大。
答案 5 :(得分:2)
你如何处理这个问题在很大程度上取决于你对游戏使用的语言,但总的来说,有很多方法,取决于你是想要使用大量存储还是想要一些延迟。如果你能对你愿意做出的牺牲有所了解,将会很有帮助。
但是,如上所述,最好的方法似乎是保存用户的输入,并同时存储游戏中所有演员/精灵的位置,这很简单只需保存方向,速度和平铺x,y,或者,如果一切都可以确定,那么忽略演员/精灵,因为你可以获得他们的信息。
你的游戏不确定性如何提供更好的建议也是有用的。
如果存在大量动态动作,例如崩溃德比,那么您可能希望每帧保存信息,因为您应该以特定帧速率更新玩家/演员。
答案 6 :(得分:2)
我只想说录制游戏重播的最佳方式完全取决于游戏的本质。以网格为基础不是问题;问题在于状态变化后的可预测行为,系统新输入的频率,是否随时注入随机数据等等,您可以通过依次记录每个动作来存储整个国际象棋游戏,但这对于没有明确转弯的第一人称射手来说不适用。您可以通过记录每个输入的确切时间来存储第一人称射击游戏,但这对于RPG无效,其中输入的结果可能会被随机骰子滚动的结果修改。如果重要信息瞬间出现并且不会以任何可捕捉的形式存在,即使是尽可能经常拍摄快照的看似万无一失的想法也不够好。
有趣的是,这与网络问题非常相似。一台计算机如何确保让另一台计算机知道游戏状态,而不必以不切实际的高频率发送整个游戏状态?典型的方法最终是事件通知和状态更新的定制混合,这可能是您在这里需要的。
答案 7 :(得分:1)
我通过借用视频压缩的一个想法来做到这一点:关键帧和中间帧。基本上,每隔几秒就可以保存完整的世界状态。然后,每次游戏更新,您将所有更改保存到自上次游戏更新以来发生的世界状态。详细信息(您多久保存一次关键帧?究竟什么是“改变世界状态”?)将取决于您需要保留哪种类型的游戏信息。
在我们的例子中,世界由许多游戏对象组成,其中大多数都在任何给定时间都保持不变,所以这种方法在记录没有移动的物体的位置时节省了大量的时间和记忆。在你的权衡中,权衡可能会有所不同。