简体   繁体   English

实现游戏播放的最佳方式?

[英]Best way to implement game playback?

I'm creating a grid based game in Java and I want to implement game recording and playback. 我正在用Java创建一个基于网格的游戏,我想实现游戏录制和播放。 I'm not sure how to do this, although I've considered 2 ideas: 我不知道怎么做,虽然我已经考虑了两个想法:

  1. Several times every second, I'd record the entire game state. 每秒几次,我会记录整个游戏状态。 To play it back, I write a renderer to read the states and try to create a visual representation. 为了回放它,我写了一个渲染器来读取状态并尝试创建一个可视化表示。 With this, however, I'd likely have a large save file, and any playback attempts would likely have noticeable lag. 但是,有了这个,我可能会有一个大的保存文件,任何播放尝试都可能会有明显的延迟。

  2. I could also write every key press and mouse click into the save file. 我也可以将每个按键和鼠标点击写入保存文件。 This would give me a smaller file, and could play back with less lag. 这会给我一个较小的文件,并可以减少滞后回放。 However, the slightest error at the start of the game (For example, shooting 1 millisecond later) would result in a vastly different game state several minutes into the game. 然而,游戏开始时的最轻微错误(例如,1毫秒后拍摄)将导致游戏几分钟内完全不同的游戏状态。

What, then, is the best way to implement game playback? 那么,实现游戏播放的最佳方式是什么?

Edit- I'm not sure exactly how deterministic my game is, so I'm not sure the entire game can be pieced together exactly by recording only keystrokes and mouse clicks. 编辑 - 我不确定我的游戏究竟有多确定,所以我不确定整个游戏是否只​​能通过按键和鼠标点击来拼凑。

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... 命令对象可以有一个时间戳值(相对于播放的开始),以便精确播放...

Shawn Hargreaves had a recent post on his blog about how they implemented replay in MotoGP. Shawn Hargreaves最近在他的博客上发表了关于他们如何在MotoGP中实施重播的帖子。 Goes over several different approaches and their pros and cons. 讨论了几种不同的方法及其优缺点。

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

Assuming that your game is deterministic, it might be sufficient if you recorded the inputs of the users (option 2). 假设您的游戏是确定性的,那么如果您记录了用户的输入(选项2)就足够了。 However, you would need to make sure that you are recognizing the correct and consistent times for these events, such as when it was recognized by the server. 但是,您需要确保识别这些事件的正确和一致的时间,例如服务器识别它们的时间。 I'm not sure how you handle events in the grid. 我不确定你是如何处理网格中的事件的。

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. 例如,在XBOX 360上考虑像Halo 3这样的游戏 - 每个客户都记录他对游戏的看法,包括基于服务器的更正。

Why not record several times a second and then compress your output, or perhaps do this: 为什么不记录几次然后压缩输出,或者这样做:

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

If you only record the change in state with a timestamp(and each change is small, and if there is no change, then record nothing), you should end up with reasonable file sizes. 如果您只记录具有时间戳的状态更改(并且每个更改都很小,并且如果没有更改,则不记录任何内容),您应该以合理的文件大小结束。

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. 如果存在更改,则会在某些良好的编码中记录更改,并且重放甚至不会变得那么大。

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. 但是,如上所述,最好的方法似乎是保存用户的输入,并同时存储游戏中所有演员/精灵的位置,这就像保存方向一样简单,速度和瓦片x,y,或者,如果一切都可以确定,那么忽略演员/精灵,因为你可以获得他们的信息。

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. 如果存在大量动态动作,例如崩溃德比,那么您可能希望每帧保存信息,因为您应该以特定帧速率更新玩家/演员。

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. 您可以通过记录每个输入的确切时间来存储第一人称射击游戏,但这对于RPG无效,其中输入的结果可能会被随机骰子滚动的结果修改。 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. 典型的方法最终是事件通知和状态更新的定制混合,这可能是您在这里需要的。

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. 在你的权衡中,权衡可能会有所不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM