Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML Canvas animation which incorporates a 'shaking' effect

I have an animation which is created using canvas. The animation is almost complete and it shows an explosion. I was wondering if there was a way to create a shaking effect which would seem as though the contents of the canvas were shaking for a few seconds when the explosion takes place.

Any help appreciated.

like image 390
Smithy Avatar asked Jan 19 '15 11:01

Smithy


1 Answers

An easy way to shake the screen is to translate the whole context in a random direction before each draw.
You have to save/restore the context to keep it in a 'clean' status.

var ctx=cv.getContext('2d');

function preShake() {
  ctx.save();
  var dx = Math.random()*10;
  var dy = Math.random()*10;
  ctx.translate(dx, dy);  
}

function postShake() {
  ctx.restore();
}

function drawThings() {  
  ctx.fillStyle = '#F00';
  ctx.fillRect(10, 10, 50, 30);
  ctx.fillStyle = '#0F0';
  ctx.fillRect(140, 30, 90, 110);
  ctx.fillStyle = '#00F';
  ctx.fillRect(80, 70, 60, 40);
}

drawThings();

function animate() {
  // keep animation alive
  requestAnimationFrame(animate);
  // erase
  ctx.clearRect(0,0,cv.width, cv.height);
  //
  preShake();
  //
  drawThings();
  //
  postShake();
}

animate();
  <canvas id='cv'></canvas>

Notice you might prefer to use some sin function and some easing to have a smoother effect :

var ctx=cv.getContext('2d');

var shakeDuration = 800;
var shakeStartTime = -1;

function preShake() {
  if (shakeStartTime ==-1) return;
  var dt = Date.now()-shakeStartTime;
  if (dt>shakeDuration) {
      shakeStartTime = -1; 
      return;
  }
  var easingCoef = dt / shakeDuration;
  var easing = Math.pow(easingCoef-1,3) +1;
  ctx.save();  
  var dx = easing*(Math.cos(dt*0.1 ) + Math.cos( dt *0.3115))*15;
  var dy = easing*(Math.sin(dt*0.05) + Math.sin(dt*0.057113))*15;
  ctx.translate(dx, dy);  
}

function postShake() {
  if (shakeStartTime ==-1) return;
  ctx.restore();
}

function startShake() {
   shakeStartTime=Date.now();
}

function drawThings() {  
  ctx.fillStyle = '#F00';
  ctx.fillRect(10, 10, 50, 30);
  ctx.fillStyle = '#0F0';
  ctx.fillRect(140, 30, 90, 110);
  ctx.fillStyle = '#00F';
  ctx.fillRect(80, 70, 60, 40);
}

drawThings();

function animate() {
  // keep animation alive
  requestAnimationFrame(animate);
  // erase
  ctx.clearRect(0,0,cv.width, cv.height);
  //
  preShake();
  //
  drawThings();
  //
  postShake();
}

startShake();
setInterval(startShake,2500);
animate();
  <canvas id='cv'></canvas>
like image 140
GameAlchemist Avatar answered Oct 04 '22 23:10

GameAlchemist