Camera Shake for Corona SDK

I took a look at the forums today and saw an interesting non-technical post “Google Play Account Terminated.” However, since I just did a non-technical article on “Flappy Bird“, I thought perhaps I’d do another short technical article instead.  Maybe, I’ll come back and add my 2-cents on lifetime banning from Google, Apple, and other mobile app stores another day.

The Problem

You’ve got a wonderful game with explosions, or a fighting game with super-moves, or some other game where you’d like to make the effect(s) more visceral.  What you really want is to shake the camera from time-to-time in response to some in game event.

Never fear, it is quite easy.

The Shaking Code

shake()

--
-- The shake code
--
local shakeCount = 0
local xShake = 8
local yShake = 4
local shakePeriod = 2

local function shake()
   if(shakeCount % shakePeriod == 0 ) then
      display.currentStage.x = display.currentStage.x0 + math.random( -xShake, xShake )
      display.currentStage.y = display.currentStage.y0 + math.random( -yShake, yShake )
   end
   shakeCount = shakeCount + 1
end

When called, the above function does the following:

  1. Checks to see if shakeCount % shakePeriod == 0,
    1. If not, the shake is skipped (skip to step 4).
    2. If so, the shake proceeds.
  2. Adds a random value in the range < –xShake, xShake > to the initial x-position (x0) of the current stage.
  3. Adds a random value in the range < –yShake, yShake > to the initial y-position (y0) of the current stage.
  4. Increments shakeCount.

What is shakePeriod?  Well, as you’ll see shortly, shake is set up to be called once every frame.  So, in order to increase or decrease the frequency of shaking, we simply count frames and every time shakeCount modulo shakePeriod is zero, we shake.  Choose a higher period for infrequent shakes, or lower period for more frequent shakes.  The minimum value of 1, for example, tells the code to shake every frame,  2 every other frame, and so on.

Where did <x0,y0> come from?  Those haven’t been set up yet.  We’ll handle that in the next part of the code.

What is the display.currentStage?  This is the top level group that contains all other groups and display objects.  Having this group is what makes shaking the camera so easy.  Because everything else is in this group, we can effectively move all world entities by moving display.currentStage.

startShake()

The next function: startShake(), has the job of initializing the stage starting position (<x0,y0> and of setting up the “enterFrame” event.  It also clears the shake counter, shakeCount.

local function startShake()
   display.currentStage.x0 = display.currentStage.x
   display.currentStage.y0 = display.currentStage.y
   shakeCount = 0
   Runtime:addEventListener( "enterFrame", shake )
end

stopShake()

Lastly, we have a function to stop the shaking: stopShake().   This function simply removes the “enterFrame” listener, and resets display.currentStage to its original position <x0,y0>.

local function stopShake()
   Runtime:removeEventListener( "enterFrame", shake )
   timer.performWithDelay( 50, 
   function() 
      display.currentStage.x = display.currentStage.x0 
      display.currentStage.y = display.currentStage.y0
   end )
end 

Shake It Baby

Using the camera shaker is as simple as two lines of code.   The first starts the shake, the second stops it after a short period of time.

-- Start the shake
startShake()
 
-- Stop it in 1/2 second.
timer.performWithDelay( 500, stopShake )

See It In Action

You can get a full example of the shaking code here.  Please feel free to modify it and use it in your own apps and games.