Game Mechanics:
Screen Shake



Explanation of Code!


function _init()
    --screen shake variables
    intensity = 0
    shake_control = 5
end

As usual, we set the variables we need inside of the  _init() function. There are only 2 variables that we decided to create outside of the shake effect function.

What is a variable?

intensity = a number used for the current amount the screen will shake. It will always decrease back to zero (no shake).

shake_control = a number used for the starting shake intensity that will be added to the intensity variable to begin the effect. This number can be used to adjust the strength of the shaking when you trigger the screen shake to happen.

The necessary global variable (outside of the shake function) is intensity, however, you could create more than one shake_control variable for different strength shakes. Or you could simply add a number directly to intensity without the use of extra variables.


function shake()
    local shake_x=rnd(intensity) - (intensity /2)
    local shake_y=rnd(intensity) - (intensity /2)

    --offset the camera
    camera( shake_x, shake_y )

    --ease shake and return to normal
    intensity *= .9
    if intensity < .3 then intensity = 0 end
end

function shake() = creates a custom function that can be called to run.


We begin by creating two local variables to be used only inside of this function.

shake_x and shake_y will be used to offset the camera by a certain amount in random directions.

The function starts by setting these local variables shake_x and shake_y to different random numbers. The bigger the random numbers, the more chaotic the screen shake will appear.

rnd( intensity ) = will find a random number between 0 and the intensity number.

simple random range visualized

But if we leave it like this, then the camera will only add a positive number to its X and Y position. That means the camera will only shake towards the right and down. What we actually want is a chance of getting positive or negative numbers, so we need to slide the range of the possible random numbers down below zero. To do that, we subtract half of the intensity number after the positive random number is found.

- (intensity/2) = will adjust the range of the random number to be positive or negative.

random range visualized

So we begin this function by setting an X and Y variables to be some number between half intensity in the negative, and half the intensity in the positive. We want the possibility of negative numbers because a negative X will move the camera left, and a negative Y will move the camera upwards. So allowing for a random positive and negative number, allows the camera to move in all 4 directions.






Next we set the camera to those offset X and Y variables.

camera( shake_x, shake_y ) = give camera a new position using the changing variables to cause the shaking look.


In this tutorial, our camera stays at its default position of (0,0) but if you are already moving the camera around in your game, then you probably are using some variables for the camera\'s X and Y position. In that case, you will already have your camera set up like:

camera( cam_x , cam_y )

And to add the shaking variables to that is easy:

moving camera that can also shake






Lastly, this function eases the shaking intensity back down to zero (no shake).

intensity *= .9 = multiplying by a fraction cuts back the intensity number by a certain percentage every time.

You could play around with this number (.9) to change how long it takes the shaking to stop.

Lower the number to make the shaking stop faster. Raise the number to make the shaking last longer. Be careful, if you set it to 1 or more, the shaking will get stronger and never stop. So this number must be a decimal between 0 and 1.


The easing gets slower and slower the closer the intensity gets to zero, so we need to help it get there when it is close enough. We decided that .3 was close enough. So we check if the intensity is less than that and if so, then we force intensity back to zero.

if intensity < .3 then intensity = 0 end


This is the example code you\'ll want to use somewhere in your game update. We have removed the unnecessary code, that is specific to how we set up the demo cart.

function _update()
    --run shake when intensity high
    if intensity > 0 then shake() end

    --up, increase shake
    ...

    --down, decrease shake
    ...

    --x, trigger shake
    if btnp(❎) then intensity += shake_control end

    --change face based on shake intensity
    eye_size = 7+intensity/2
    mouth_size = 2+intensity/2
end

The first thing you\'ll want to put in your update function is the constant running of the shake() function. However we chose to only run the function if intensity is activated.

if intensity > 0 then shake() end = checks if intensity is more than zero, and runs the shake function.

You could remove the check and simply write shake() because when intensity is zero, the screen will not shake anyway.


We skip over how we decided to demo a control of the shake strength with the up and down buttons. So next let\'s look at how we trigger the shake. You may be surprised that we don\'t call the function to trigger it, the function should already be running, or ready to run depending on the intensity variable.

intensity += shake_control = increases the intensity by a certain strength to trigger the shaking effect.

 

We chose to animate the eyes and mouth of our face in this example to demonstrate how you could control objects in your game to react to the amount of shaking that you trigger.

eye_size = 7+intensity/2

Let\'s write that in a more generic way that you could apply to your game:

variable = default_number + intensity/2

So take whatever variable from the game object that you want to change. In this demo, we took the size of the eyes and mouth. Then we set it to it\'s default or minimum size and then add half of the intensity.

You could play around with the math completely. Subtracting would make the default number a maximum and shaking would make the eyes and mouth smaller. Or use the full intensity amount to make larger changes to your game object that is reacting with the shake. 

moving image showing facial reaction to shaking

Just shaking the screen is cool, but some linked visual feedback to the shaking will really add something special to the gameplay! A great time to use screen shake is when your player gets hurt, or an explosion occurs, or falling into water, or even small things like failing to open locked objects.


This is the example code you\'ll want to use somewhere in your draw function. We have removed the unnecessary code, that is specific to how we set up the demo, such as the function used to draw the Nerdy Teacher face and the on screen controls information.

function _draw()
    cls( 12 )
    circfill( 63, 63, 40, 6)

    --below unaffected by shake
    --after we reset the camera
    camera()

    --show demo controls
    ...
end

cls( 12 ) = clear the game screen and set the entire screen color to light blue (#12).

circfill( x, y, radius, color) = draws a sprite at X and Y coordinates on the screen.

camera() = resets the camera position to 0 X and 0 Y.

Anything you draw after resetting the camera will not be affected by the shake effect. However, be careful if your game adjusts the camera to follow the player around the map for example, because you will want to "reset" the camera to its current position rather than resetting it completely back to 0 X and 0 Y.

For example, let\'s say you are adjusting the camera normally using these variables, cam_x and cam_y, then you should reset the camera using only those same variables and not the shake variables:

camera( cam_x, cam_y )


We won\'t explain how we printed the demo controls to the screen, but if you play the demo, you will see an example of keeping some things fixed in position and not shaking, while others are shaking, by just drawing them after resetting the camera.


--screen shake demo
--by nerdy teachers

function _init()
    --screen shake variables
    intensity = 0
    shake_control = 5
end

function _update()
    --run shake when intensity high
    if intensity > 0 then shake() end

    --up, increase shake
    if btnp(⬆️)
    and shake_control < 10 then
        shake_control += 1
    end

    --down, decrease shake
    if btnp(⬇️)
    and shake_control > 0 then
        shake_control -= 1
    end

    --x, trigger shake
    if btnp(❎) then intensity += shake_control end

    --change face based on shake intensity
    eye_size = 7+intensity/2
    mouth_size = 2+intensity/2
end

function _draw()
    cls(12)
    circfill( 63, 63, 40, 6)

    --below unaffected by shake
    --after we reset the camera
    camera()

    --show demo controls
    print("intensity",2,2,7)
    print(intensity,10,9,7)
    print("shake",47,2,0)
    print("❎",53,9,0)
    print("shake_control",75,2,7)
    print("⬆️/⬇️ = "..shake_control,85,9, 7)
end

function shake()
    local shake_x=rnd(intensity) - (intensity /2)
    local shake_y=rnd(intensity) - (intensity /2)

    --offset the camera
    camera( shake_x, shake_y )

    --ease shake and return to normal
    intensity *= .9
    if intensity < .3 then intensity = 0 end
end




1989

14 Oct 2022

Font