Saving Game States As Seen In Braid

Started by
5 comments, last by drakostar 15 years, 7 months ago
I am working on a project with two other fellows and we have decided to make an isometric tactical game. The gameplay mechanic involves giving your small squad of soldiers orders in 6 second snapshots of time. During the time you are selecting orders for your units, you will be able to see the AI update their own movements based on your decisions. If you drag a soldier out to walk out towards a bunch of enemies and he ends up getting slaughtered, that's OK! You can rewind time and give him new orders to go elsewhere. Once you are satisfied with all your unit's movements you hit a submit button and move on to the next 6 second round. The short way I describe it to people is Combat Mission with a little Braid. Hopefully you guys can glean the idea of the game from that, now on to my question. What is a sane way to acquire all of the data required to be able to rewind, play, and modify 6 seconds of an environment where dynamic object creation (bullets/grenades), physics (walls exploding), and AI updates are occurring all throughout? I understand I can work with "deltas" as used in network programming so that I do not need to save entire objects, only the things that changed from frame to frame. My bigger question is what would be an easy way to collect all the data required to rewind and play a tactical game like we are trying to make? My thought right now is that a messaging system is the answer but it seems that way too many messages will be being created just so that the "GameState" manager can function properly. Maybe there is no way around it but I don't want to have to send a message every time an AI state machine switches a state. Does anyone else have any ideas? I am in a bit of a rut right now trying to think of a good way to hook this system up without making it a hassle for everyone else writing code.
Advertisement
I was going to say use the delta method :p save everything at 0 seconds and then the diference at 6 seconds. There will likey be a huge amount of data with things like x, y and z positions, bool variables for alive or dead etc. You could probably use XML to save it to a temp file that was over written every 6(?) seconds and loads in the necisary information if the player choses to rewind. This would work best if it's an instant change rather than if you were actually rewinding and viewing each, say, 10th of a second at a time.
Hmm... I'm thinking I might not have been clear enough.

During the actual 6 second increments we want to make sure we have the accuracy of saving every 20 ms of game play during that period. This will allow the player to rewind to any point in time during that six seconds to change orders.

As a simple gameplay example: Say for my 6 second action I just choose to move forward in a straight line. After the simulation plays (before I commit my actions) I see that some enemies will be waiting for me up ahead. Because of this, I decide to rewind 3 seconds and lob a grenade at the enemies. The simulation recalculates the information and plays (before committing my actions yet again). The AI is able to react to the new player choices just as the player was able to previously with the AI choices. Now instead of the enemies waiting for the player to come to them, they run from the grenade and scatter. The player is satisfied with this and commits these actions.

As an aside, I would like to be constantly playing the 6 second window to the player so that they can see what will happen if they commit their moves. Probably with grayed out characters to show that "this could happen".

As I think about it more, maybe all I really need to save are the position of units since that is all that graphics will need to display the moves. Then graphics can interpolate between frames accordingly. The downside to this is that we wanted the player to be able to play back an entire level and watch the action unfold as a movie, as well as being able to jump back in to the game at any point to try other strategies. With saving only positions, this will not be possible as unit health, ammo, AI states, etc. will not be available. This would also force us to recalculate the entire 6 second window each time an action changes.

The current idea for our engine set up is that there will be a "presentation" thread that will run graphics and UI actions. This thread will communicate with the "simulation" thread that controls ai and physics by telling it where the player has decided to move. The simulation thread will churn out a 6 second chunk of data to give to graphics and graphics will display that data to the user. If the user decides to change his orders, a new request will be given to the simulation thread.

I was hoping that we would not need to recalculate the full 6 seconds of data if the player is only changing orders that occur in the last second of the turn. Maybe this isn't possible but it seems like it should be.
you could have it save the state in real time using a collection that only has room for 6 seconds worth of space and then when replaying just use the saved data in an update call
Quote:Original post by mikesobczak
you could have it save the state in real time using a collection that only has room for 6 seconds worth of space and then when replaying just use the saved data in an update call


That's the plan. I've avoided thinking about the subject for the time being since I have an interview tomorrow (today?) to prepare for but I'm trying to nail down more specific details. IE what needs to be saved and how am I going to collect that information without making life hell for everyone that isn't writing the state saving code. For example, I know I need to save physics data but I don't want the physics programmer to fight with my implementation if he would like to do advanced physics.

Thanks for the replies guys.
Without getting too much into details, one solution to your problem is not saving the state but the transformation.
For performance reasons you could make full or delta state snapshots in some intervals.

Reversing time/actions would be a simple matter of loading the last full state and applying all transformations since.
This system has the advantage of being memory efficient and flexible since your transformations will not require a back-transformation. Doing only forward-transformation has also the positive effect of simulating side effects correctly.
Negative is its time complexity when working on large time scales, which doesn't seem the case for you. Also a problem might be when side effects are indeterministic.
Make sure to introduce an absolute game/logic time concept, which is independent from real time and dynamic as in under your control.

[Edited by - kiome on September 21, 2008 11:16:35 AM]
My Blog
Quote:Original post by kiome
Without getting too much into details, one solution to your problem is not saving the state but the transformation.
For performance reasons you could make full or delta state snapshots in some intervals.

Reversing time/actions would be a simple matter of loading the last full state and applying all transformations since.

That seems optimal to me. Save the game state at the beginning of the turn. The player issues a command, which is stored in another data structure with its in-game timestamp. The command is then applied in the game world and time elapses, marking any affected objects dirty. If we want to move back in time, just restore the state of any changed objects and apply the same command, but only let the timer run for the correct amount of time. As with any save/load/replay system, the PRNG seed needs to be considered part of the saved state.

This topic is closed to new replies.

Advertisement