【问题标题】:Best way to implement game playback?实现游戏播放的最佳方式?
【发布时间】:2010-10-22 10:46:27
【问题描述】:

我正在用 Java 创建一个基于网格的游戏,我想实现游戏录制和播放。尽管我考虑了 2 个想法,但我不确定如何执行此操作:

  1. 每秒几次,我会记录整个游戏状态。为了回放它,我编写了一个渲染器来读取状态并尝试创建一个视觉表示。但是,这样一来,我的保存文件可能会很大,并且任何播放尝试都可能会有明显的延迟。

  2. 我还可以将每次按键和鼠标点击写入保存文件。这会给我一个更小的文件,并且可以以更少的延迟播放。但是,游戏开始时最轻微的错误(例如,在 1 毫秒后射击)会导致游戏几分钟后的游戏状态大不相同。

那么,实现游戏播放的最佳方式是什么?

编辑 - 我不确定我的游戏到底有多确定性,所以我不确定整个游戏是否可以通过仅记录击键和鼠标点击来准确拼凑。

【问题讨论】:

    标签: java playback recording


    【解决方案1】:

    一个好的播放机制不是可以简单地添加到游戏中而没有重大困难的东西。最好的办法是在设计游戏基础设施时牢记这一点。 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);
       } 
    }
    

    然后可以在用户按下键盘按钮、移动鼠标​​或没有触发播放机制的情况下将命令推送到执行队列中两者。命令对象可以有一个时间戳值(相对于播放的开始),用于精确播放...

    【讨论】:

    • 这是一种优雅的处理方式。如果实际的游戏玩法和录制是基于相同的时序/帧机制,则应避免由于时序问题而导致的错误。如果您的事件有随机化,您可能还需要记录随机数生成器的起始种子值。这就是 RTS 游戏中的“随机地图”功能如何让您重新生成您喜欢的随机地图。
    • 此模式还可以为您提供撤消/重做功能。
    【解决方案2】:

    Shawn Hargreaves 最近在他的博客上发表了一篇关于他们如何在 MotoGP 中实现回放的帖子。介绍了几种不同的方法及其优缺点。

    http://blogs.msdn.com/shawnhar/archive/2009/03/20/motogp-replays.aspx

    【讨论】:

      【解决方案3】:

      假设您的游戏是确定性的,如果您记录用户的输入(选项 2)可能就足够了。但是,您需要确保识别这些事件的正确且一致的时间,例如服务器识别的时间。我不确定您如何处理网格中的事件。

      我担心的是,如果您没有可以统一引用定时事件的机制,那么您的代码处理分布式用户的方式可能会出现问题。

      以 XBOX 360 上的《光环 3》等游戏为例 - 每个客户端都会记录他对游戏的看法,包括基于服务器的更正。

      【讨论】:

        【解决方案4】:

        为什么不每秒记录几次然后压缩你的输出,或者这样做:

        recordInitialState();
        ...
        runs 30 times a second:
        recordChangeInState(previousState, currentState);
        ...
        

        如果你只用时间戳记录状态的变化(并且每次变化很小,如果没有变化,那么什么都不记录),你应该得到合理的文件大小。

        【讨论】:

          【解决方案5】:

          无需为每一帧保存场景中的所有内容。逐步保存更改并使用一些好的插值技术。我不会真正使用基于命令模式的方法,而是以固定速率对每个游戏对象进行检查,看看它是否改变了任何属性。如果有变化,变化会以某种良好的编码记录下来,那么回放甚至不会变得那么大。

          【讨论】:

            【解决方案6】:

            您如何处理这将很大程度上取决于您用于游戏的语言,但总的来说,有很多方法,具体取决于您是要使用大量存储空间还是要延迟一些时间。如果您能就您愿意做出的牺牲提出一些想法,那将会很有帮助。

            但是,似乎最好的方法可能是只保存用户的输入,如前所述,或者同时存储游戏中所有演员/精灵的位置,这很简单只需保存方向、速度和平铺 x、y,或者,如果一切都可以确定,则忽略演员/精灵,因为您可以获得他们的信息。

            您的游戏的不确定性对于提供更好的建议也很有用。

            如果存在大量动态运动,例如撞车德比,那么您可能希望在每一帧中保存信息,因为您应该以特定帧速率更新玩家/演员。

            【讨论】:

              【解决方案7】:

              我只想说,录制游戏回放的最佳方式完全取决于游戏的性质。基于网格不是问题。问题是状态变化后行为的可预测性如何,系统新输入的频率,是否在任何时候注入随机数据等,您只需依次记录每一步,就可以存储整个国际象棋游戏,但这不适用于没有明确转弯的第一人称射击游戏。您可以通过记录每个输入的确切时间来存储第一人称射击游戏,但这不适用于输入结果可能会被随机掷骰子的结果修改的 RPG。如果重要信息会立即出现并且不会以任何可捕获的形式持续存在,那么即使是尽可能多地拍摄快照这种看似万无一失的想法也不够好。

              有趣的是,这与您遇到的网络问题非常相似。一台计算机如何确保另一台计算机知道游戏状态,而不必以不切实际的高频率发送整个游戏状态?典型的方法最终是事件通知和状态更新的定制混合,这可能是您在这里需要的。

              【讨论】:

                【解决方案8】:

                我曾经通过借鉴视频压缩的一个想法来做到这一点:关键帧和中间帧。基本上,每隔几秒钟,您就会保存世界的完整状态。然后,每次游戏更新一次,您将保存自上次游戏更新以来发生的世界状态的所有更改。细节(你多久保存一次关键帧?究竟什么算作“改变世界状态”?)取决于你需要保存什么样的游戏信息。

                在我们的例子中,世界由很多很多游戏对象组成,其中大部分在任何给定时间都保持静止,因此这种方法为我们节省了大量时间和内存来记录不移动对象的位置.在您的情况下,权衡可能会有所不同。

                【讨论】:

                  猜你喜欢
                  • 2012-03-15
                  • 2011-03-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多