ElasticCollision


Wikipedia: “An elastic collision is a collision in which the total kinetic energy of the colliding bodies after collision is equal to their total kinetic energy before collision.”

In this case ball collision by manipulating DOM elements with CSS animations. This is a basic game mechanic used in many games like Snooker or Hunderds.

Although this tutorial is written in javascript, you should be able to use the same techniques and concepts in almost any development environment. Based on a flash tutorial Managing ball vs ball collision with Flash by Emanuele Feronato.

 

add the balls

In the first function we call, we add the balls to the scene. Just creating some DIV elements, give them some properties and push them to an array to access them later on. We also start the render if the last element is added. To keep the DIV elements in style we set some CSS properties like “border-radius”.

var ballsArray =[];
var maxBalls = 5;

function initBalls()
{
	//ADD maxBalls
	for (var i=0;i<maxBalls;i++)
	{ 
		var ball = document.createElement("div");
		ball.className ="ball";

                //RANDOM START POSITION ON THE SCREEN
		ball.left =Math.round(Math.random()*window.innerWidth-30);
		ball.top = Math.round(Math.random()*390);
		ball.collision = 0;
                ball.mass = 1;

                //RANDOM START SPEED
    	        ball.xspeed = Math.round(Math.random()*8-4);
    	        ball.yspeed = Math.round(Math.random()*8-4);

		document.getElementById('wrapper').appendChild(ball);

		ballsArray.push(ball);

                if(ballsArray.length == maxBalls){tick();}
	}
}

 

 

move the balls

In this function we loop trough the Array which stores the balls an animate them by changing some CSS properties. First we check if any ball reaches the end of the screen. If so we inverse speed for the x and y direction. Next we get the speed value for the actual ball and apply it to the current position. This function is called in the render tick so it is executed on every frame.

function moveBall()
{		
                //for each ball in the array
		for (var i=0;i<maxBalls;i++)
		{ 
                        //Check for a collision with boundaries
			if (ballsArray[i].left<0) {ballsArray[i].left = 0;ballsArray[i].xspeed *= -1;}		// BOUNDRIES Left
			if (ballsArray[i].left>window.innerWidth-30) {ballsArray[i].left = window.innerWidth-30;ballsArray[i].xspeed *= -1;}	// BOUNDRIES Right
			if (ballsArray[i].top<0) {ballsArray[i].top = 0;ballsArray[i].yspeed *= -1;}		// BOUNDRIES Top
			if (ballsArray[i].top>window.innerHeight-30) {ballsArray[i].top = innerHeight-30;ballsArray[i].yspeed *= -1;}	// BOUNDRIES Bottom

			//GET THE NEW POSITION
			ballsArray[i].left += ballsArray[i].xspeed;
			ballsArray[i].top += ballsArray[i].yspeed;

			//APPLY THE NEW POSITION
			//ballsArray[i].style.WebkitTransform = "translate("+ballsArray[i].left+"px,"+ballsArray[i].top+"px)";//2D Transform
			ballsArray[i].style.WebkitTransform = "translate3D("+ballsArray[i].left+"px,"+ballsArray[i].top+"px,0px)";//3D Transform fo better Performance?? -> "testing"
            ballsArray[i].style.MozTransform = "translate3D("+ballsArray[i].left+"px,"+ballsArray[i].top+"px,0px)";
		}
   		//ball.style.WebkitTransform = "translate("+ball.dx+"px,"+ball.dy+"px)";
}

 

 

ball collision

There is a whole lot of math in this function. It gets called every time two balls collide together, ball and ball2. If you want to understand how this works, you could read these articles “The Physics of an Elastic Collision”  also “real-world-physics-problems“.

function manage_bounce(ball, ball2) {
    dx = ball.left-ball2.left;
    dy = ball.top-ball2.top;
    collisionision_angle = Math.atan2(dy, dx);
    magnitude_1 = Math.sqrt(ball.xspeed*ball.xspeed+ball.yspeed*ball.yspeed);
    magnitude_2 = Math.sqrt(ball2.xspeed*ball2.xspeed+ball2.yspeed*ball2.yspeed);
    direction_1 = Math.atan2(ball.yspeed, ball.xspeed);
    direction_2 = Math.atan2(ball2.yspeed, ball2.xspeed);
    new_xspeed_1 = magnitude_1*Math.cos(direction_1-collisionision_angle);
    new_yspeed_1 = magnitude_1*Math.sin(direction_1-collisionision_angle);
    new_xspeed_2 = magnitude_2*Math.cos(direction_2-collisionision_angle);
    new_yspeed_2 = magnitude_2*Math.sin(direction_2-collisionision_angle);
    final_xspeed_1 = ((ball.mass-ball2.mass)*new_xspeed_1+(ball2.mass+ball2.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_xspeed_2 = ((ball.mass+ball.mass)*new_xspeed_1+(ball2.mass-ball.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_yspeed_1 = new_yspeed_1;
    final_yspeed_2 = new_yspeed_2;
    ball.xspeed = Math.cos(collisionision_angle)*final_xspeed_1+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball.yspeed = Math.sin(collisionision_angle)*final_xspeed_1+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball2.xspeed = Math.cos(collisionision_angle)*final_xspeed_2+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_2;
    ball2.yspeed = Math.sin(collisionision_angle)*final_xspeed_2+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_2;
}

 

 

render tick

This function is called every frame to animate all the Objects on the screen. The function check first if the distance between any balls is greater than the diameter. If not it collides, calls the ball collision function and passes the two colliding balls over. We also call the moveBall & tick function to keep the animation running.

function tick()
{

     for (x=0; x<=maxBalls; x++) 
     {
        for (y=x+1; y<maxBalls; y++) 
        {
        	distance_x = Math.abs(ballsArray[x].left-ballsArray[y].left);
        	distance_y = Math.abs(ballsArray[x].top-ballsArray[y].top);
        	distance = Math.sqrt(distance_x*distance_x+distance_y*distance_y);

        	if (distance<=31 && (ballsArray[x].collision == 0 || ballsArray[y].collision == 0)) 
        	{
        		ballsArray[x].collision = 1;
                ballsArray[y].collision = 1;
                manage_bounce(ballsArray[x], ballsArray[y]);
        	}
        	else if (distance>31) 
        	{
                ballsArray[x].collision = 0;
                ballsArray[y].collision = 0;
            }

        	//window.console.log(distance)
        }
     }

    moveBall();

    requestAnimFrame( tick );//RUN THE NEXT TICK
}

 

 

conclusion

If your game mechanic bases on elastic collision this is a great way of doing it. Full control over the code, light weight, fast and simple.