6
\$\begingroup\$

I'm making a platformer built from mini-levels - and I want to create a sort of a replay of all the player tries that the player did for the level.

My question is - what is the best way to record the player's actions in-game, so that I could replay them later when he finishes the level.

I thought about recording only the player's input and replay them later on, each on a clone of the player. The problem I have with this is with dynamic obstacles (that could be moved around) - if one clone moves them, it throws the simulation off for the rest of the clones.

So then I thought about recording every frame the X/Y of the player, and then just replay it - but that seems it could cause a major memory leak and very ineffective.

So - does anyone have any ideas? :)

EDIT: As per the request in the comment, link showing said mechanic

\$\endgroup\$
6
  • \$\begingroup\$ In Super Meat Boy, the effect of inputs is to apply forces on the character, but so do obstacles and the environment. If, for each effort exerted on the character, you save its properties like the instant at which it was exerted, its force vector, its duration, etc, then you can reproduce the kinematics of the character independently of the environment. \$\endgroup\$
    – jrsala
    Dec 19, 2012 at 16:19
  • 3
    \$\begingroup\$ There are a lot of questions here like this. Use the search. Here's one: gamedev.stackexchange.com/questions/32501/… \$\endgroup\$
    – Almo
    Dec 19, 2012 at 16:19
  • 1
    \$\begingroup\$ @Almo Those questions are quite different as SuperMeatBoy is special in one thing, all replays are replayed at the same time. So it's not that you can simply restart the simulation with the same input as the 100 meat boys would affect each other. \$\endgroup\$
    – API-Beast
    Dec 19, 2012 at 16:31
  • 1
    \$\begingroup\$ The way you play them back is a different question. This is about how to record the events. Playing back multiple at the same time isn't a problem, you would just need to disable interactions between the duplicated characters. It's a duplicate. \$\endgroup\$
    – House
    Dec 19, 2012 at 16:47
  • 1
    \$\begingroup\$ @Ron Please rephrase the question, not everyone knows the Replay feature and not everybody can read minds. \$\endgroup\$
    – API-Beast
    Dec 19, 2012 at 16:56

2 Answers 2

3
\$\begingroup\$

I'm not sure why don't you save player position (and maybe it's animation) for every frame, let's do a little bit calculations: each player position is combined of two floating point numbers (aka. 8 bytes), you also need to know which animation the character was showing at that frame and exactly how much which frame of the animation was shown in that specific time (aka. another 8 bytes). I can't think of anything else, but let's assume we need another 8 bytes for reserve. it means total 24 bytes per snapshot.

Now if you are talking about SMB most runs won't be longer than 5 minutes, meaning 300 seconds or 18k frames (60 fps). If you want to show a replay exactly as shown in the first play, you need to store all those 60 frames per second, based on what we calculated before you'll need 18k * 24bytes memory per try (meaning 432kb). If your target market is PC, you won't have any problems storing even 100 replications (43MB) which is even more than what SMB showed after you've finished level.

Now let's see how can we optimize our data storage system to consume less memory:

  1. you really don't need 8 bytes of floating point number for position. Usually you can compress all those data into 3 or 4 bytes of fixed point numbers.
  2. you don't need 8 bytes for animation either, you normally don't have more than 256 different animations for your main character, and non of your animations contain more than 256 different frames, so you can store all the data in 2 bytes at most.
  3. I've put 8 bytes for reserve, so I will expect you to use those 8 bytes wisely (reduce them as much as you can!)
  4. you don't need to save replay at 60fps either, you can easily save 20fps and interpolate all the frames between them. I'm pretty sure user won't notice any difference.
  5. since you are suggesting your game consist of mini-levels I think 5 minutes is really more than a normal run in your game, though I won't reduce that either!

Now let's see how much data we need for this new replay system (4 + 2 + 8) * 20 * 5 * 60 = 84kb per replication, which means you can easily show up to 100 replications in any iOS /Android device!

Do you need to save even more memory? You can try storing only key frames with their time and interpolate all the frames between them. key frames simply mean the frames where player's Velocity changed due to any reason (hitting obstacles, user input change, ...) but it'll result in consuming much more processing power while showing those replays.

\$\endgroup\$
4
  • \$\begingroup\$ My original idea was to record at 60FPS, which is definitely an overkill. Your approach seems very reasonable, simple and failsafe - I'll definitely give it a go! \$\endgroup\$
    – Ron
    Dec 20, 2012 at 1:59
  • 1
    \$\begingroup\$ @Ron I forgot to mention it, but SMB also used another trick. when playing al the replays they don't start at the same time, this is why you can see all those replications. some might start running sooner, and some start running faster than the winning image. \$\endgroup\$
    – Ali1S232
    Dec 20, 2012 at 6:34
  • \$\begingroup\$ To save on the position you can also delta-encode, although that ends up being subsumed under the key-frame approach. \$\endgroup\$ Dec 20, 2012 at 8:39
  • \$\begingroup\$ @PeterTaylor I don't think saving delta-encoded replays will do anything good in this case, simply because we are saving too few parameters to begin with. I mean delta-encoded values won't save any more memory. \$\endgroup\$
    – Ali1S232
    Dec 21, 2012 at 15:21
0
\$\begingroup\$

In the case of something simple like Super Meatboy you could try and log all the input and replay it. Just make sure it's a high enough resolution.

If you want to do anything advanced it's a good idea to look at abandoning basic data types.

For example you can create your own 'property' class. This class can do things such as log changes in it's value over time (such as in this case).

Other features are Network replication. A unique identifier (useful for network replication). Serialization (also useful for network replication and saving). Mark areas of memory as being changed since last game load (allows for almost instant saving/loading). You could also do things like reflection (ie give the property a name, get a list at runtime of all the properties). Script binding and so on.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .