PICO-8


Screen Shake Demo



Follow along to learn how to control a screen shake effect!


In making this demo, we learn about controlling the camera.


This lesson focuses on VISUAL EFFECTS!




Challenges!

After following the lesson, take on some of these challenges to test your knowledge and skills!

1. Successfully implement this shake() function into your own game.

2. Set different shake strengths in your game. For example: bigger collisions, bigger shakes.

3. Change the effect to only shake from left to right.

How to Shake the Screen Effect!


[ Video Coming Soon! ]


Explanation of Code!


  • 1. Set up the Variables

      What is a variable?
      function _init()
          --screen shake variables
          intensity = 0
          shake_control = 5
      end

      As usual, we set the variables inside of the main _init() function, or if you are using multiple game states such as a main menu, game play, game over, etc. then you should put these variables inside of the init function for the state that will use this shake effect function.


      There are only 2 variables that we decided to create outside of the shake effect function. Only one is necessary, but you could make more to have more control at customizing different types of shake effects within your game while still using the single shake function below.

      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 intensity to begin the effect. This number can be used to adjust the strength of the shaking when you trigger the intensity.

      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.






  • 2. Screen Shake Function

      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.

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

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


      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.

      If you are adjusting the camera in your game already, for example to follow the player on the map (let's say using global cam_x and cam_y variables), then you can also add a shake like this:

      camera( cam_x+shake_x , cam_y+shake_y )






      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






  • 3. Update the Shake

      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.

      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 the demo 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. This is just an example, nothing is strict.

      Just shaking the screen is cool, but some linked visual feedback to the shaking will really add something special to the gameplay, so get creative!






  • 4. Draw Anything

      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.






  • Full Code!

      This code has been simplified from the demo so it's easier to copy paste into your own game, without the unnecessary draw code. If you do want that, it is still in the demo cart .png above.

      --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
      

  • Play the Game!


font