11

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

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

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

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

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

4

8 回答 8

14

A good playback mechanism is not something that can be simply added to a game without major difiiculties. The best would be do design the game infrastructure with it in mind. The command pattern can be used to achieve such a game infrastructure.

For example:

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);
   } 
}

And then the command can be pushed in an execution queue both when the user presses a keyboard button, moves the mouse or without a trigger with the playback mechanism. The command object can have a time-stamp value (relative to the beginning of the playback) for precise playback...

于 2009-04-28T22:17:35.447 回答
8

Shawn Hargreaves had a recent post on his blog about how they implemented replay in MotoGP. Goes over several different approaches and their pros and cons.

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

于 2009-04-28T22:45:22.010 回答
3

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

My worry is that if you don't have a mechanism that can uniformly reference timed events, there might be a problem with the way your code handles distributed users.

Consider a game like Halo 3 on the XBOX 360 for example - each client records his view of the game, including server-based corrections.

于 2009-04-28T22:06:31.243 回答
2

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

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

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

于 2009-04-28T22:03:08.570 回答
2

There is no need to save everything in the scene for every frame. Save changes incrementally and use some good interpolation techniques. I would not really use a command pattern based approach, but rather make checks at a fixed rate for every game object and see if it has changed any attribute. If there is a change that change is recorded in some good encoding and the replay won't even become that big.

于 2009-04-28T22:36:22.420 回答
2

How you approach this will depend greatly on the language you are using for your game, but in general terms there are many approaches, depending on if you want to use a lot of storage or want some delay. It would be helpful if you could give some thoughts as to what sacrifices you are willing to make.

But, it would seem the best approach may be to just save the input from the user, as was mentioned, and either store the positions of all the actors/sprites in the game at the same time, which is as simple as just saving direction, velocity and tile x,y, or, if everything can be deterministic then ignore the actors/sprites as you can get their information.

How non-deterministic your game is would also be useful to give a better suggestion.

If there is a great deal of dynamic motion, such as a crash derby, then you may want to save information each frame, as you should be updating the players/actors at a certain framerate.

于 2009-04-28T22:44:41.777 回答
2

I would simply say that the best way to record a replay of a game depends entirely on the nature of the game. Being grid based isn't the issue; the issue is how predictable behaviour is following a state change, how often there are new inputs to the system, whether there is random data being injected at any point, etc, You can store an entire chess game just by recording each move in turn, but that wouldn't work for a first person shooter where there are no clear turns. You could store a first person shooter by noting the exact time of each input, but that won't work for an RPG where the result of an input might be modified by the result of a random dice roll. Even the seemingly foolproof idea of taking a snapshot as often as possible isn't good enough if important information appears instantaneously and doesn't persist in any capturable form.

Interestingly this is very similar to the problem you get with networking. How does one computer ensure that another computer is made aware of the game state, without having to send that entire game state at an impractically high frequency? The typical approach ends up being a bespoke mixture of event notifications and state updates, which is probably what you'll need here.

于 2009-04-28T23:00:06.497 回答
1

I did this once by borrowing an idea from video compression: keyframes and intermediate frames. Basically, every few seconds you save the complete state of the world. Then, once per game update, you save all the changes to the world state that have happened since the last game update. The details (how often do you save keyframes? What exactly counts as a 'change to the world state'?) will depend on what sort of game information you need to preserve.

In our case, the world consisted of many, many game objects, most of which were holding still at any given time, so this approach saved us a lot of time and memory in recording the positions of objects that weren't moving. In yours the tradeoffs might be different.

于 2009-06-11T23:34:44.057 回答