今天我们来分享一款很酷的HTML5重力感应动画教程,这款动画可以让你甩动页面中的小球,小球的大小都不同,并且鼠标点击空白区域时又可以生成一定数量的小球。当我们甩动小球时,各个小球之间就会发生互相碰撞的效果,并且在运动过程中模拟了重力感应的物理效果。你可以在DEMO演示中来尝试一下。
HTML代码:
- <div id="canvas"></div>
还是很简单,HTML仅仅是列出了一个canvas容器,今后我们将在这里生成一些列canvas元素,这些小球就在canvas中运动。
另外由于该动画利用了box2d的js脚本库,所以在页面上你也需要引用它:
- <script src="box2d.js"></script>
接下来是Javascript代码,在canvas上动态创建大小和样式不一的小球,并发生碰撞效果。
Javascript代码:
- var canvas;
-
- var delta = [ 0, 0 ];
- var stage = [ window.screenX, window.screenY, window.innerWidth, window.innerHeight ];
- getBrowserDimensions();
-
- var themes = [ [ "#10222B", "#95AB63", "#BDD684", "#E2F0D6", "#F6FFE0" ],
- [ "#362C2A", "#732420", "#BF734C", "#FAD9A0", "#736859" ],
- [ "#0D1114", "#102C2E", "#695F4C", "#EBBC5E", "#FFFBB8" ],
- [ "#2E2F38", "#FFD63E", "#FFB54B", "#E88638", "#8A221C" ],
- [ "#121212", "#E6F2DA", "#C9F24B", "#4D7B85", "#23383D" ],
- [ "#343F40", "#736751", "#F2D7B6", "#BFAC95", "#8C3F3F" ],
- [ "#000000", "#2D2B2A", "#561812", "#B81111", "#FFFFFF" ],
- [ "#333B3A", "#B4BD51", "#543B38", "#61594D", "#B8925A" ] ];
- var theme;
-
- var worldAABB, world, iterations = 1, timeStep = 1 / 15;
-
- var walls = [];
- var wall_thickness = 200;
- var wallsSetted = false;
-
- var bodies, elements, text;
-
- var createMode = false;
- var destroyMode = false;
-
- var isMouseDown = false;
- var mouseJoint;
- var mouse = { x: 0, y: 0 };
- var gravity = { x: 0, y: 1 };
-
- var PI2 = Math.PI * 2;
-
- var timeOfLastTouch = 0;
-
- init();
- play();
-
- function init() {
-
- canvas = document.getElementById( 'canvas' );
-
- document.onmousedown = onDocumentMouseDown;
- document.onmouseup = onDocumentMouseUp;
- document.onmousemove = onDocumentMouseMove;
- document.ondblclick = onDocumentDoubleClick;
-
- document.addEventListener( 'touchstart', onDocumentTouchStart, false );
- document.addEventListener( 'touchmove', onDocumentTouchMove, false );
- document.addEventListener( 'touchend', onDocumentTouchEnd, false );
-
- window.addEventListener( 'deviceorientation', onWindowDeviceOrientation, false );
-
- // init box2d
-
- worldAABB = new b2AABB();
- worldAABB.minVertex.Set( -200, -200 );
- worldAABB.maxVertex.Set( window.innerWidth + 200, window.innerHeight + 200 );
-
- world = new b2World( worldAABB, new b2Vec2( 0, 0 ), true );
-
- setWalls();
- reset();
- }
-
-
- function play() {
-
- setInterval( loop, 1000 / 40 );
- }
-
- function reset() {
-
- var i;
-
- if ( bodies ) {
-
- for ( i = 0; i < bodies.length; i++ ) {
-
- var body = bodies[ i ]
- canvas.removeChild( body.GetUserData().element );
- world.DestroyBody( body );
- body = null;
- }
- }
-
- // color theme
- theme = themes[ Math.random() * themes.length >> 0 ];
- document.body.style[ 'backgroundColor' ] = theme[ 0 ];
-
- bodies = [];
- elements = [];
-
- createInstructions();
-
- for( i = 0; i < 10; i++ ) {
-
- createBall();
-
- }
-
- }
-
- //
-
- function onDocumentMouseDown() {
-
- isMouseDown = true;
- return false;
- }
-
- function onDocumentMouseUp() {
-
- isMouseDown = false;
- return false;
- }
-
- function onDocumentMouseMove( event ) {
-
- mouse.x = event.clientX;
- mouse.y = event.clientY;
- }
-
- function onDocumentDoubleClick() {
-
- reset();
- }
-
- function onDocumentTouchStart( event ) {
-
- if( event.touches.length == 1 ) {
-
- event.preventDefault();
-
- // Faking double click for touch devices
-
- var now = new Date().getTime();
-
- if ( now - timeOfLastTouch < 250 ) {
-
- reset();
- return;
- }
-
- timeOfLastTouch = now;
-
- mouse.x = event.touches[ 0 ].pageX;
- mouse.y = event.touches[ 0 ].pageY;
- isMouseDown = true;
- }
- }
-
- function onDocumentTouchMove( event ) {
-
- if ( event.touches.length == 1 ) {
-
- event.preventDefault();
-
- mouse.x = event.touches[ 0 ].pageX;
- mouse.y = event.touches[ 0 ].pageY;
-
- }
-
- }
-
- function onDocumentTouchEnd( event ) {
-
- if ( event.touches.length == 0 ) {
-
- event.preventDefault();
- isMouseDown = false;
-
- }
-
- }
-
- function onWindowDeviceOrientation( event ) {
-
- if ( event.beta ) {
-
- gravity.x = Math.sin( event.gamma * Math.PI / 180 );
- gravity.y = Math.sin( ( Math.PI / 4 ) + event.beta * Math.PI / 180 );
-
- }
-
- }
-
- //
-
- function createInstructions() {
-
- var size = 250;
-
- var element = document.createElement( 'div' );
- element.width = size;
- element.height = size;
- element.style.position = 'absolute';
- element.style.left = -200 + 'px';
- element.style.top = -200 + 'px';
- element.style.cursor = "default";
-
- canvas.appendChild(element);
- elements.push( element );
-
- var circle = document.createElement( 'canvas' );
- circle.width = size;
- circle.height = size;
-
- var graphics = circle.getContext( '2d' );
-
- graphics.fillStyle = theme[ 3 ];
- graphics.beginPath();
- graphics.arc( size * .5, size * .5, size * .5, 0, PI2, true );
- graphics.closePath();
- graphics.fill();
-
- element.appendChild( circle );
-
- text = document.createElement( 'div' );
- text.onSelectStart = null;
- text.innerHTML = '<span style="color:' + theme[0] + ';font-size:40px;">Hello!</span><br /><br /><span style="font-size:15px;"><strong>This is how it works:</strong><br /><br />1. Drag a ball.<br />2. Click on the background.<br />3. Shake your browser.<br />4. Double click.<br />5. Play!</span>';
- text.style.color = theme[1];
- text.style.position = 'absolute';
- text.style.left = '0px';
- text.style.top = '0px';
- text.style.fontFamily = 'Georgia';
- text.style.textAlign = 'center';
- element.appendChild(text);
-
- text.style.left = ((250 - text.clientWidth) / 2) +'px';
- text.style.top = ((250 - text.clientHeight) / 2) +'px';
-
- var b2body = new b2BodyDef();
-
- var circle = new b2CircleDef();
- circle.radius = size / 2;
- circle.density = 1;
- circle.friction = 0.3;
- circle.restitution = 0.3;
- b2body.AddShape(circle);
- b2body.userData = {element: element};
-
- b2body.position.Set( Math.random() * stage[2], Math.random() * -200 );
- b2body.linearVelocity.Set( Math.random() * 400 - 200, Math.random() * 400 - 200 );
- bodies.push( world.CreateBody(b2body) );
- }
-
- function createBall( x, y ) {
-
- var x = x || Math.random() * stage[2];
- var y = y || Math.random() * -200;
-
- var size = (Math.random() * 100 >> 0) + 20;
-
- var element = document.createElement("canvas");
- element.width = size;
- element.height = size;
- element.style.position = 'absolute';
- element.style.left = -200 + 'px';
- element.style.top = -200 + 'px';
- element.style.WebkitTransform = 'translateZ(0)';
- element.style.MozTransform = 'translateZ(0)';
- element.style.OTransform = 'translateZ(0)';
- element.style.msTransform = 'translateZ(0)';
- element.style.transform = 'translateZ(0)';
-
- var graphics = element.getContext("2d");
-
- var num_circles = Math.random() * 10 >> 0;
-
- for (var i = size; i > 0; i-= (size/num_circles)) {
-
- graphics.fillStyle = theme[ (Math.random() * 4 >> 0) + 1];
- graphics.beginPath();
- graphics.arc(size * .5, size * .5, i * .5, 0, PI2, true);
- graphics.closePath();
- graphics.fill();
- }
-
- canvas.appendChild(element);
-
- elements.push( element );
-
- var b2body = new b2BodyDef();
-
- var circle = new b2CircleDef();
- circle.radius = size >> 1;
- circle.density = 1;
- circle.friction = 0.3;
- circle.restitution = 0.3;
- b2body.AddShape(circle);
- b2body.userData = {element: element};
-
- b2body.position.Set( x, y );
- b2body.linearVelocity.Set( Math.random() * 400 - 200, Math.random() * 400 - 200 );
- bodies.push( world.CreateBody(b2body) );
- }
-
- //
-
- function loop() {
-
- if (getBrowserDimensions()) {
-
- setWalls();
-
- }
-
- delta[0] += (0 - delta[0]) * .5;
- delta[1] += (0 - delta[1]) * .5;
-
- world.m_gravity.x = gravity.x * 350 + delta[0];
- world.m_gravity.y = gravity.y * 350 + delta[1];
-
- mouseDrag();
- world.Step(timeStep, iterations);
-
- for (i = 0; i < bodies.length; i++) {
-
- var body = bodies[i];
- var element = elements[i];
-
- element.style.left = (body.m_position0.x - (element.width >> 1)) + 'px';
- element.style.top = (body.m_position0.y - (element.height >> 1)) + 'px';
-
- if (element.tagName == 'DIV') {
-
- var style = 'rotate(' + (body.m_rotation0 * 57.2957795) + 'deg) translateZ(0)';
- text.style.WebkitTransform = style;
- text.style.MozTransform = style;
- text.style.OTransform = style;
- text.style.msTransform = style;
- text.style.transform = style;
-
- }
-
- }
-
- }
-
-
- // .. BOX2D UTILS
-
- function createBox(world, x, y, width, height, fixed) {
-
- if (typeof(fixed) == 'undefined') {
-
- fixed = true;
-
- }
-
- var boxSd = new b2BoxDef();
-
- if (!fixed) {
-
- boxSd.density = 1.0;
-
- }
-
- boxSd.extents.Set(width, height);
-
- var boxBd = new b2BodyDef();
- boxBd.AddShape(boxSd);
- boxBd.position.Set(x,y);
-
- return world.CreateBody(boxBd);
-
- }
-
- function mouseDrag()
- {
- // mouse press
- if (createMode) {
-
- createBall( mouse.x, mouse.y );
-
- } else if (isMouseDown && !mouseJoint) {
-
- var body = getBodyAtMouse();
-
- if (body) {
-
- var md = new b2MouseJointDef();
- md.body1 = world.m_groundBody;
- md.body2 = body;
- md.target.Set(mouse.x, mouse.y);
- md.maxForce = 30000 * body.m_mass;
- // md.timeStep = timeStep;
- mouseJoint = world.CreateJoint(md);
- body.WakeUp();
-
- } else {
-
- createMode = true;
-
- }
-
- }
-
- // mouse release
- if (!isMouseDown) {
-
- createMode = false;
- destroyMode = false;
-
- if (mouseJoint) {
-
- world.DestroyJoint(mouseJoint);
- mouseJoint = null;
-
- }
-
- }
-
- // mouse move
- if (mouseJoint) {
-
- var p2 = new b2Vec2(mouse.x, mouse.y);
- mouseJoint.SetTarget(p2);
- }
- }
-
- function getBodyAtMouse() {
-
- // Make a small box.
- var mousePVec = new b2Vec2();
- mousePVec.Set(mouse.x, mouse.y);
-
- var aabb = new b2AABB();
- aabb.minVertex.Set(mouse.x - 1, mouse.y - 1);
- aabb.maxVertex.Set(mouse.x + 1, mouse.y + 1);
-
- // Query the world for overlapping shapes.
- var k_maxCount = 10;
- var shapes = new Array();
- var count = world.Query(aabb, shapes, k_maxCount);
- var body = null;
-
- for (var i = 0; i < count; ++i) {
-
- if (shapes[i].m_body.IsStatic() == false) {
-
- if ( shapes[i].TestPoint(mousePVec) ) {
-
- body = shapes[i].m_body;
- break;
-
- }
-
- }
-
- }
-
- return body;
-
- }
-
- function setWalls() {
-
- if (wallsSetted) {
-
- world.DestroyBody(walls[0]);
- world.DestroyBody(walls[1]);
- world.DestroyBody(walls[2]);
- world.DestroyBody(walls[3]);
-
- walls[0] = null;
- walls[1] = null;
- walls[2] = null;
- walls[3] = null;
- }
-
- walls[0] = createBox(world, stage[2] / 2, - wall_thickness, stage[2], wall_thickness);
- walls[1] = createBox(world, stage[2] / 2, stage[3] + wall_thickness, stage[2], wall_thickness);
- walls[2] = createBox(world, - wall_thickness, stage[3] / 2, wall_thickness, stage[3]);
- walls[3] = createBox(world, stage[2] + wall_thickness, stage[3] / 2, wall_thickness, stage[3]);
-
- wallsSetted = true;
-
- }
-
- // BROWSER DIMENSIONS
-
- function getBrowserDimensions() {
-
- var changed = false;
-
- if (stage[0] != window.screenX) {
-
- delta[0] = (window.screenX - stage[0]) * 50;
- stage[0] = window.screenX;
- changed = true;
-
- }
-
- if (stage[1] != window.screenY) {
-
- delta[1] = (window.screenY - stage[1]) * 50;
- stage[1] = window.screenY;
- changed = true;
-
- }
-
- if (stage[2] != window.innerWidth) {
-
- stage[2] = window.innerWidth;
- changed = true;
-
- }
-
- if (stage[3] != window.innerHeight) {
-
- stage[3] = window.innerHeight;
- changed = true;
-
- }
-
- return changed;
-
- }
上面mouseDrag方法就实现了鼠标拖拽甩动小球的功能,这也是该动画最重要的方法。全部代码可以下载源码来研究。