Particles with KineticJS and collision detection

Hello once again, this time I will show a nice technique to create exploding particles with KineticJS.

First of all we setup the stage and the canvas objects.

DEMO:

http://cdpn.io/IwAoc

See the Pen kineticjs collision detection by Michael Dobekidis (@netgfx) on CodePen.

$(document).ready(function(){
 
  stage = new Kinetic.Stage({
        container: 'canvas',
        width: 1200,
        height: 400,
        stroke:"#000000",
        strokeWidth:2
      });
 
  var layer = new Kinetic.Layer();
  //stage.add(layerObj);
 
      var rect = new Kinetic.Rect({
        x: 20,
        y: 75,
        width: 70,
        height: 50,
        fill: 'green',
        stroke: 'black',
        strokeWidth: 4
      });

      // add the shape to the layer
      layer.add(rect);

      // add the layer to the stage
      stage.add(layer);
   
  imgObj = new Image();
  imgObj.width = 50+'px';
  imgObj.height = 50+'px';
  imgObj.onload = function(){
    createParticles(imgObj, 50,50);
   
    anim.start();
  };
 imgObj.src = img;

});

As you see we setup the stage normally, we create a rectangle that we will animate to show the collision, and we load an image.
Now you are probably wondering why I am loading the image and then calling createParticles, this function (createParticles) simply creates tiny bits of the image and places them one next to the other thus forming the original image but this way we don’t have to deal with the tainted canvas
So let’s see this function in action:

function createParticles(imgObj,w, h){
       
        particles = new Array();
         for(var n = 0; n < 10; n++) {
            for(var i = 0; i < 10; i++) {
              var imgX = n * 5;
              var imgY = i * 5;
              particles.push({
                x: imgX,
                y: imgY,
                imgX: imgX,
                imgY: imgY,
                vx: 0,
                vy: 0,
                isRolling: false,
                isLocked: true
              });
            }
          }
 
  createObj(imgObj,700,50);
  createObj(imgObj,200,50);
 
}

function createObj(imgObj, _x, _y){
  var layerObj = new Kinetic.Layer();
  for(var i=0; i<particles.length;i++){
   
    var img = new Kinetic.Image({
          x: particles[i].x,
          y: particles[i].y,
          image: imgObj,
          width: 10,
          height: 10,
          id:"obj_"+i,
          crop: {
        x: particles[i].imgX,
        y: particles[i].imgY,
        width: 10,
        height: 10
            }
        });
   
    layerObj.add(img);
  }
 
  //var grp = new Kinetic.Group();
  layerObj.setX(_x);
  layerObj.setY(_y);
  stage.add(layerObj);
  stage.draw();
  layerArr.push(layerObj);
  explode(layerObj);
}

So after we create an object with the coordinates where the particles will be placed we iterate through that and place the image bits at the corresponding positions.

Now we will create the explode functions and the animation trigger.

function explode(layer){
  var nodes = layer.getChildren();
  var innerArr = new Array();
  for(var i=0;i<nodes.length;i++){
 
     var tween = new Kinetic.Tween({
          node: nodes[i],
          x: getRandom(  200 , -200 ),
          y: getRandom(  200 , -200 ),
          opacity:0,
          duration: 0.5,
          onFinish: function() {
         
          var index = String(this.node.getId()).split("_");
           
          if( Number(index[1]) % 100 == 0){
            isExploding = false;
          }
        }
        });
   
    innerArr.push(tween);
}
 
  tweenArr.push(innerArr);
}

function enableExplode(layer,index){
  isExploding = true;
  var nodes = layer.getChildren();
 
  for(var i=0;i<nodes.length;i++){
   tweenArr[index][i].play();
  }
 
}

Finally we add the animation enabler and some utility functions that will check the collide.

var anim = new Kinetic.Animation(function(frame) {
    rect.setX(frame.time * 0.2);
    for(var i=0;i<layerArr.length;i++){
    var result = doObjectsCollide(rect,layerArr[i]);
   
      if(result == true){
        console.log('exploding...',i,isExploding,result);
        if(isExploding==false){
         
          enableExplode(layerArr[i], i);
        }
        //anim.stop();
        }
    }
  }, layer);

Utility functions:

function doObjectsCollide(a, b) { // a and b are your objects
   return !(
    ((a.getY() + a.getHeight()) < (b.getY())) ||
    (a.getY() > (b.y + b.getHeight())) ||
    ((a.getX() + a.getWidth()) < b.getX()) ||
    (a.getX() > (b.getX() + b.getWidth()))
   );
}

function getRandom(max, min){
    return Math.floor(Math.random() * (1 + max - min) + min);
}
Tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *