Implementing "Rewind Time", like in the Prince of Persia - Sands of time series

Started by
14 comments, last by Bacterius 12 years, 2 months ago

I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.


You would still need to store states for every frame.
1. The user is typically allowed to cancel rewind at any point in the recording.
2. During recording, you can't throw away state, since a recorded frame T[n] must be saved until T[n+historyLength]
Advertisement

[quote name='AlysiumX' timestamp='1327078691' post='4904615']
I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.


You would still need to store states for every frame.
1. The user is typically allowed to cancel rewind at any point in the recording.
2. During recording, you can't throw away state, since a recorded frame T[n] must be saved until T[n+historyLength]
[/quote]

To add to the list:
3. That will significantly slow the application because writing a screenshot of each frame to disk is slow
4. You'll need to compress each image (png maybe?) or else you'll end up with gigabytes of screenshots (and compressing/decompressing each frame would be another bottleneck)
5. If you don't write to disk, but instead keep the screenshots in memory, you'll use about a gigabyte of memory for 5 seconds of screenshots at 30 fps and 1080p resolution (uncompressed, but even compressed will be quite large), which will probably kill cache performance in some areas of the program
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.



[quote name='Nypyren' timestamp='1327082462' post='4904635']

I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.


You would still need to store states for every frame.
1. The user is typically allowed to cancel rewind at any point in the recording.
2. During recording, you can't throw away state, since a recorded frame T[n] must be saved until T[n+historyLength]
[/quote]

What he said. For example, if you just picked up a power-up, then died, when you rewind 3 seconds, you will go back to before you had the power-up, so saving screens/frames isn't enough. You could store the event of "Acquired Power-up" at x time, then, when reversing, at that time, you remove that power-up, etc.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


[quote name='AlysiumX' timestamp='1327078691' post='4904615']
I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.




[quote name='AlysiumX' timestamp='1327078691' post='4904615']
I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.


You would still need to store states for every frame.
1. The user is typically allowed to cancel rewind at any point in the recording.
2. During recording, you can't throw away state, since a recorded frame T[n] must be saved until T[n+historyLength]
[/quote]

What he said. For example, if you just picked up a power-up, then died, when you rewind 3 seconds, you will go back to before you had the power-up, so saving screens/frames isn't enough. You could store the event of "Acquired Power-up" at x time, then, when reversing, at that time, you remove that power-up, etc.
[/quote]

Well it seems like a terrific shortcut lol. Ya so basically what I originally said.

If you're curious enough to spend $3.95, you can get Jonathan Blow's GDC 2010 talk on the Implementation of Rewind in Braid. There's an interesting thread about it here, as well.


I think Braid is a really brilliant game and the time rewind thing was a main point game mechanic of it. If I remember correctly it had a some stuff going backward in time, some is going forward (at the same real world time), or depending on which direction the player is moving (while the player is moving forward in time) other objects may move either backward or forward in time.

For my game I think Braid's implementation would be overkill.
I would like to implement something simple, only covering my needs for rewinding time in case the player screwed up to have a second shot at it. The core game itself would not rely in time manipulation puzzles.


I just thought of a terrific short cut for this. Just capture a screenshot of every frame and store them in an array, do the pop off of the first and add onto the back operation describe above. Then just run through the array backwards displaying each screen for a rewind and restore the players state at the end of it. Your grabbing 1 screen shot per frame, no huge object array, no calcuations, no hassles.


Let's say taking 60 raw screenshots/second doesn't take an insane amount of memory and processing power.
I try to fight off 3 enemies, I kill two in the process, they explode, but I took too much damage, my health decreased to a minimum, I want to reverse the whole encounter.
Rewind everything.
How will the 2 enemies I killed come back to life, how will my health grow back, how will my position revert back?
That doesn't seem like the way to go.



I guess we can all agree that the current state at a given frame need to be captured of all objects.
For some objects that move constantly in a predictable way, like particles or scrolling stars, the current state can be calculated, this way saving memory and possibly processing power (in contrast to saving all variables for 500 particles and stars / frame)

For more complex AI driven objects I could only imagine that (almost) every variable they which is not constant must be saved for every frame. There are not that high numbers of these objects at any given moment, so that shouldn't be too expensive.


For me the obvious way would be that each objects before its state updated pushes its current variable on top of the corresponding variable's memory stack. On rewind the values are popped from the memory stack to the current.

EDIT:
Another important thing that I just thought of:
In my current implementation of the game, in every frame all objects are polled to see if their alive flag is turned off, because if it is, they have to be erased from their vector container. (All particles, stars, enemies are stored inside vectors, a new one spawned is push_back() -d on it, dead ones are erased.)
This needs to be adjusted so after the object is not alive, it should not be drawn anymore, and it should not perform any logic anymore (other than keep updating the memory stack of its variables), but it should not be erased until enough time has passed that even after a full (3 seconds -> 180 frames) of rewind, it would not come back to life. So it can only be erased 180 game loop iterations after it died.
/EDIT

My concern/question now:
Some of you are saying that there should be a separate class that dynamically handles/creates all the memory variables of each object, in contrast to having each object care about its own stuff.

To me having a separate object that has access to all variables of all other objects, and dynamically creates them for each by polling them every frame (lets say a new enemy spawns, after that this time manager object scans through all enemies, recognizes that there is a new one, in response to that it will dynamically allocate memory for all variables of that enemy, gets all values then stores it there) seems unnecessary complicated.

Is there any benefit of having a time state manager object doing all this, instead of having each object doing it for itself? Wouldn't it only over-complicate things?
Well it seems like a terrific shortcut lol. Ya so basically what I originally said.[/quote]
It's not a shortcut, it's impractical. Constantly recording the X last seconds would consume a lot of CPU time, would saturate the PCI-E bus, would consume an immense amount of memory, and it would be fundamentally very limiting (you wouldn't be able to add visual features, etc...), and it wouldn't be scalable (resolution-dependent, among others).

The correct way to do it (or at least a better way) is to store the state of every relevant object in the game. Also you probably don't need to store state information for every single frame. If you are rewinding say 5 seconds over a duration of 2 seconds, you only need to store states for 2 frames out of 5, instead of all 5. Also you can probably get away with storing states for once every 10 frames and interpolating, it shouldn't be noticeable.

And yes, some items' states don't need to be stored, such as simple physics objects for which the position can be calculated by simply knowing the current time (like particles).

I would probably get a time state manager object to do it, it's just simpler (and once everything is working you can always change it - it's easier to change something that works than to implement the hard way from scratch).

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

This topic is closed to new replies.

Advertisement