HTML Canvas Animation with physics
<!DOCTYPE html> <html> <head> <title>Implementing advanced animation</title> <meta charset="utf-8"> /*from ww w . j av a 2 s . c o m*/ <style type="text/css"> * { margin: 0; padding: 0; } html, body { height: 100%; width: 100%; } canvas { display: block; } #myCanvas { background: #001022; } #myButtons { bottom: 20px; left: 20px; position: absolute; } #myButtons button { padding: 5px; } </style> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { var canvas = $("#myCanvas"); var context = canvas.get(0).getContext("2d"); var canvasWidth = canvas.width(); var canvasHeight = canvas.height(); $(window).resize(resizeCanvas); function resizeCanvas() { canvas.attr("width", $(window).get(0).innerWidth); canvas.attr("height", $(window).get(0).innerHeight); canvasWidth = canvas.width(); canvasHeight = canvas.height(); }; resizeCanvas(); var playAnimation = true; var startButton = $("#startAnimation"); var stopButton = $("#stopAnimation"); startButton.hide(); startButton.click(function() { $(this).hide(); stopButton.show(); playAnimation = true; animate(); }); stopButton.click(function() { $(this).hide(); startButton.show(); playAnimation = false; }); // Class that defines new asteroids to draw var Asteroid = function(x, y, radius, mass, vX, vY, aX, aY) { this.x = x; this.y = y; this.radius = radius; this.mass = mass; this.vX = vX; this.vY = vY; this.aX = aX; this.aY = aY; }; // Array that holds all the asteroids to draw var asteroids = new Array(); // Setting up some asteroids for (var i = 0; i < 10; i++) { var x = 20+(Math.random()*(canvasWidth-40)); var y = 20+(Math.random()*(canvasHeight-40)); var radius = 5+Math.random()*10; var mass = radius/2; var vX = Math.random()*4-2; var vY = Math.random()*4-2; //var aX = Math.random()*0.2-0.1; //var aY = Math.random()*0.2-0.1; var aX = 0; var aY = 0; asteroids.push(new Asteroid(x, y, radius, mass, vX, vY, aX, aY)); }; // Animation loop that does all the fun stuff function animate() { // Clear context.clearRect(0, 0, canvasWidth, canvasHeight); context.fillStyle = "rgb(255, 255, 255)"; // Loop through every asteroid var asteroidsLength = asteroids.length; for (var i = 0; i < asteroidsLength; i++) { var tmpAsteroid = asteroids[i]; for (var j = i+1; j < asteroidsLength; j++) { var tmpAsteroidB = asteroids[j]; var dX = tmpAsteroidB.x - tmpAsteroid.x; var dY = tmpAsteroidB.y - tmpAsteroid.y; var distance = Math.sqrt((dX*dX)+(dY*dY)); if (distance < tmpAsteroid.radius + tmpAsteroidB.radius) { var angle = Math.atan2(dY, dX); var sine = Math.sin(angle); var cosine = Math.cos(angle); // Rotate asteroid position var x = 0; var y = 0; // Rotate asteroidB position var xB = dX * cosine + dY * sine; var yB = dY * cosine - dX * sine; // Rotate asteroid velocity var vX = tmpAsteroid.vX * cosine + tmpAsteroid.vY * sine; var vY = tmpAsteroid.vY * cosine - tmpAsteroid.vX * sine; // Rotate asteroidB velocity var vXb = tmpAsteroidB.vX * cosine + tmpAsteroidB.vY * sine; var vYb = tmpAsteroidB.vY * cosine - tmpAsteroidB.vX * sine; // Reverse the velocities //vX *= -1; //vXb *= -1; var vTotal = vX - vXb; vX = ((tmpAsteroid.mass - tmpAsteroidB.mass) * vX + 2 * tmpAsteroidB.mass * vXb) / (tmpAsteroid.mass + tmpAsteroidB.mass); vXb = vTotal + vX; // Move asteroids apart xB = x + (tmpAsteroid.radius + tmpAsteroidB.radius); // Rotate asteroid positions back tmpAsteroid.x = tmpAsteroid.x + (x * cosine - y * sine); tmpAsteroid.y = tmpAsteroid.y + (y * cosine + x * sine); tmpAsteroidB.x = tmpAsteroid.x + (xB * cosine - yB * sine); tmpAsteroidB.y = tmpAsteroid.y + (yB * cosine + xB * sine); // Rotate asteroid velocities back tmpAsteroid.vX = vX * cosine - vY * sine; tmpAsteroid.vY = vY * cosine + vX * sine; tmpAsteroidB.vX = vXb * cosine - vYb * sine; tmpAsteroidB.vY = vYb * cosine + vXb * sine; }; }; // Calculate velocity based on pixels-per-frame tmpAsteroid.x += tmpAsteroid.vX; tmpAsteroid.y += tmpAsteroid.vY; // Add acceleration to velocity if (Math.abs(tmpAsteroid.vX) < 10) { tmpAsteroid.vX += tmpAsteroid.aX; }; if (Math.abs(tmpAsteroid.vY) < 10) { tmpAsteroid.vY += tmpAsteroid.aY; }; // Friction if (Math.abs(tmpAsteroid.vX) > 0.1) { tmpAsteroid.vX *= 0.9; } else { tmpAsteroid.vX = 0; }; if (Math.abs(tmpAsteroid.vY) > 0.1) { tmpAsteroid.vY *= 0.9; } else { tmpAsteroid.vY = 0; }; // Boundary collision checks if (tmpAsteroid.x-tmpAsteroid.radius < 0) { tmpAsteroid.x = tmpAsteroid.radius; // Move away from the edge tmpAsteroid.vX *= -1; tmpAsteroid.aX *= -1; } else if (tmpAsteroid.x+tmpAsteroid.radius > canvasWidth) { tmpAsteroid.x = canvasWidth-tmpAsteroid.radius; // Move away from the edge tmpAsteroid.vX *= -1; tmpAsteroid.aX *= -1; }; if (tmpAsteroid.y-tmpAsteroid.radius < 0) { tmpAsteroid.y = tmpAsteroid.radius; // Move away from the edge tmpAsteroid.vY *= -1; tmpAsteroid.aY *= -1; } else if (tmpAsteroid.y+tmpAsteroid.radius > canvasHeight) { tmpAsteroid.y = canvasHeight-tmpAsteroid.radius; // Move away from the edge tmpAsteroid.vY *= -1; tmpAsteroid.aY *= -1; }; context.beginPath(); context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI*2); context.closePath(); context.fill(); }; if (playAnimation) { // Run the animation loop again in 33 milliseconds setTimeout(animate, 33); }; }; // Start the animation loop animate(); }); </script> </head> <body> <canvas id="myCanvas" width="500" height="500"> <!-- Insert fallback content here --> </canvas> <div id="myButtons"> <button id="startAnimation">Start</button> <button id="stopAnimation">Stop</button> </div> </body> </html>