Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

This question already has an answer here:

So I am making a simple game like "the impossible game" where the character just moves forward(from a 2D prespective) and the only thing you have to do is press the screen to jump at the correct time to avoid crashing into obstacles.

My record algorithm is quite simple:

   onJump()
   {
       events.append(player.pos.x);
   }

And my replay is:

   onUpdate()
   {
       if(player.x==events[nextevent])
            player.jump();
   }

Everything works O.K but sometimes in extreme situations(the player jumped just before he crash on an obstacle)while the player didn't actually crash, on replay the player crashes. I know this is happening because of the delta time(different delta on record and on replay). How can I fix it without having the need to record my delta time too?

EDIT:it seems that many didn't actually understood my question ,the question is not how to implements a replay system (knight666 answer is full and complete and it deserves the accept but its not what i asked) but how to deal with the changes of delta time.for example ,lets say the player jumps just before he crash ,while he is still in the air he passes 1 pixel away from the obstacle and it doesn't crash, but in the replay cause the delta can happen to be different than the delta while it was recorded the player passes -1 pixel away from the obstacle and it crashes.

share|improve this question
    
just a tip - such genre is called "runner". –  KatShot May 19 '13 at 19:18
    
    
The way to deal with the "changes in delta time" is to design the replay system such that you're not doing calculations like you are and instead recording snapshots of the game world and just playing that back. Just like some of the answers in gamedev.stackexchange.com/questions/6080/… suggest you do. –  Tetrad May 19 '13 at 20:29
add comment

marked as duplicate by Byte56, msell, Anko, bummzack, Josh Petrie May 24 '13 at 14:47

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

2 Answers

up vote 1 down vote accepted

For the specific case in the question I see two options:

  1. Override the time step when you're getting close to a jump location, so that at the end of that time step the player is in the correct position for the jump.

  2. Use a fixed timestep so it can't go wrong in that way.

Note that there's also other ways for it to fail. For example, anything that's controlled by randomness could easily mess up the replay, unless you write code to handle it.

share|improve this answer
add comment

What you want to do is seperate your actual input from your input processing. The game logic shouldn't care about where the event came from, only that it happened.

The easiest thing for you to do is to record the player's input and timestamp it. For example, let's say you store it as JSON:

"InputEvents": [
    "KeyPressed": {
        "Timestamp": 1230,
        "Key": "Space"
    },
    "KeyPressed": {
        "Timestamp": 4492,
        "Key": "Space"
    },
    "KeyPressed": {
        "Timestamp": 12093,
        "Key": "Space"
    }

When you want to replay a level, you load this file and pretend it's live data.

Let's say you have a Keyboard class that handles all keyboard processing:

class Keyboard
{

public:

    void KeyPressed(int a_Key);
    void KeyReleased(int a_Key);

};

Derive a virtual IKeyboard interface from this and make sure your code uses this interface instead:

class IKeyboard
{

public:

    virtual void KeyPressed(int a_Key) = 0;
    virtual void KeyReleased(int a_Key) = 0;

};

class Keyboard
    : public IKeyboard
{

public:

    void KeyPressed(int a_Key);
    void KeyReleased(int a_Key);

};

Now you can derive a second implementation, one that reads from the replay file:

class KeyboardReplay
    : public IKeyboard
{

public:

    void Update(float a_DeltaTime);

    bool LoadReplay(const std::string& a_FilePath);

    void KeyPressed(int a_Key);
    void KeyReleased(int a_Key);

private:

    float m_TimeOffset;

};

Add the Update method to the virtual interface and call it from the main loop. The default keyboard implementation will just stub it out:

void Keyboard::Update(float a_DeltaTime)
{
    // do nothing
}

But the new class will check if an event has occurred:

void KeyboardReplay::Update(float a_DeltaTime)
{
    m_TimeOffset += a_DeltaTime;

    if (m_TimeOffset > m_EventNext->GetTimeOffset())
    {
        m_EventNext->Execute();
        m_EventNext = _GetNextEvent();
    }
}

Now you can record player input to a file, load it and play it back.

However, one thing that is crucial for this to work: the times have to be synchronized. You have to be sure that when it says "+1000 milliseconds" that you don't add 999 or 1001 milliseconds, because errors will stack up and the entire simulation will collapse.

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.