0
\$\begingroup\$

The camera in my game engine can be modified by following a rectangle properties, that can be scaled, moved and even rotated. I need this effect for the shaking of the screen when a zombie attacks a character.

How should I go about implementing this?

\$\endgroup\$
4
  • \$\begingroup\$ Really, really hard to tell what you're asking here. Modified by a rectangle? Modified how? Also, I think you mean 'shake / shakey'. 'shack' means something completely different. \$\endgroup\$
    – MrCranky
    Jul 10, 2012 at 10:45
  • \$\begingroup\$ @MrCranky Thank you for your notification. I have editted my question. \$\endgroup\$
    – Luke Vo
    Jul 10, 2012 at 10:50
  • 2
    \$\begingroup\$ possible duplicate of Realistic Camera/Screen Shake from Explosion \$\endgroup\$
    – bummzack
    Jul 10, 2012 at 13:18
  • \$\begingroup\$ This GDC talk is an excellent resource about screen shake and the various tradeoffs: youtube.com/watch?v=tu-Qe66AvtY \$\endgroup\$
    – DShook
    Mar 15, 2018 at 23:55

1 Answer 1

6
\$\begingroup\$

Store the logical screen position and the actual screen position in separate containers... The logical screen position is the position, where the screen should be, when no shaking happens... When shaking happens apply some offset to the logical screen position to get the actual screen position.

I made a little example (not tested and not completly implemented, but it should show how you could make the shake effect). Below I have added some thoughts about whats currently missing in my example.

class Viewport
{
    float xOffset = 0;
    float yOffset = 0;
    int shakeTimer = 0;

    public Vector2f actual;
    public Vector2f logical;

    //Shaking will take 200ms
    public final int SHAKE_TIME_MS = 200;

    //The screen will be moved 20 pixels forth and back
    public final int SHAKE_OFFSET = 20; 

    //Indicates the shake move direction
    public boolean shakeDirection = false;

    //Indicates if the screen is currently shaking
    public boolean shaking;

    //delta is the ms passed since last update
    public void update(int delta)
    {
        if(shaking)
        {
            updateShake(delta);
        }
        else
        {           
            actual.x = logical.x;
            actual.y = logical.y;
        }
    }

    private void updateShake(int delta) {
        if(shakeTimer == 0)
        {
            //If its the first run from the current shake, initialise x and y offset to 0
            xOffset = 0;
            yOffset = 0;                
        }

        //Add passed milliseconds to timer... If timer exceeds configuration, shaking ends
        shakeTimer += delta;
        if(shakeTimer > SHAKE_TIME_MS)
        {
            //Shaking ends 
            shakeTimer = 0;
            shaking = false;
            xOffset = 0;
            yOffset = 0;
        }
        else
        {
            applyScreenShake(delta);
        }
    }

    private void applyScreenShake(int delta) {
        //Depending on shake direction, the screen is moved either to the top left, or the bottom right
        if(shakeDirection)
        {
            xOffset -= 1.5f * delta;
            if(xOffset < -SHAKE_OFFSET)
            {
                //SWITCH DIRECTION
                xOffset = -SHAKE_OFFSET;
                shakeDirection = !shakeDirection;
            }
            yOffset = xOffset;
        }
        else
        {
            xOffset += 1.5f * delta;
            if(xOffset > SHAKE_OFFSET)
            {
                //SWITCH DIRECTION
                xOffset = SHAKE_OFFSET;
                shakeDirection = !shakeDirection;
            }
            yOffset = xOffset;                  
        }
        actual.x = logical.x + xOffset;
        actual.y = logical.y + yOffset;
    }
}

I hope this gets you going... Some things you can consider:

  • Currently the screen only shakes linear to the top left and the bottom right... You could make this more interesting, by adding random move directions, as long as the x and y offset stays in a given distance.
  • When the shaking ends, the x and y offset are abruptly set to 0/0... This causes the shake to end abruptly... You could smooth this out by handling the stopped case separately.
  • When you want to scroll on the screen (map etc.) you have to change the logical position of the viewport.
  • Your rendering logic needs to use the actual position and not the logical position as render offset.
\$\endgroup\$
2
  • \$\begingroup\$ Just noticed that I forgot to set the actual screen position in the applyScreenShake method... I corrected the code example... \$\endgroup\$ Jul 10, 2012 at 14:48
  • \$\begingroup\$ See in the link in the comment for the possible duplicate if you want a more advanced (but harder to implement) solution. Basically the principle of keeping a logical and actual viewport would be the same, but the generation of movement is not liniear but more organical, because its based on a noise. But it looks quiet advanced to implement, so if you are a beginner, I would stay with a simpler solution at first. \$\endgroup\$ Jul 12, 2012 at 7:01

You must log in to answer this question.

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