HTML5重力感应小球冲撞动画实现

今天我们来分享一款很酷的HTML5重力感应动画教程,这款动画可以让你甩动页面中的小球,小球的大小都不同,并且鼠标点击空白区域时又可以生成一定数量的小球。当我们甩动小球时,各个小球之间就会发生互相碰撞的效果,并且在运动过程中模拟了重力感应的物理效果。你可以在DEMO演示中来尝试一下。



在线演示




HTML代码:



  1. <div id="canvas"></div>
复制代码


还是很简单,HTML仅仅是列出了一个canvas容器,今后我们将在这里生成一些列canvas元素,这些小球就在canvas中运动。


另外由于该动画利用了box2d的js脚本库,所以在页面上你也需要引用它:


  1. <script src="box2d.js"></script>
复制代码


接下来是Javascript代码,在canvas上动态创建大小和样式不一的小球,并发生碰撞效果。


Javascript代码:



  1. var canvas;

  2. var delta = [ 0, 0 ];
  3. var stage = [ window.screenX, window.screenY, window.innerWidth, window.innerHeight ];
  4. getBrowserDimensions();

  5. var themes = [ [ "#10222B", "#95AB63", "#BDD684", "#E2F0D6", "#F6FFE0" ],
  6.         [ "#362C2A", "#732420", "#BF734C", "#FAD9A0", "#736859" ],
  7.         [ "#0D1114", "#102C2E", "#695F4C", "#EBBC5E", "#FFFBB8" ],
  8.         [ "#2E2F38", "#FFD63E", "#FFB54B", "#E88638", "#8A221C" ],
  9.         [ "#121212", "#E6F2DA", "#C9F24B", "#4D7B85", "#23383D" ],
  10.         [ "#343F40", "#736751", "#F2D7B6", "#BFAC95", "#8C3F3F" ],
  11.         [ "#000000", "#2D2B2A", "#561812", "#B81111", "#FFFFFF" ],
  12.         [ "#333B3A", "#B4BD51", "#543B38", "#61594D", "#B8925A" ] ];
  13. var theme;

  14. var worldAABB, world, iterations = 1, timeStep = 1 / 15;

  15. var walls = [];
  16. var wall_thickness = 200;
  17. var wallsSetted = false;

  18. var bodies, elements, text;

  19. var createMode = false;
  20. var destroyMode = false;

  21. var isMouseDown = false;
  22. var mouseJoint;
  23. var mouse = { x: 0, y: 0 };
  24. var gravity = { x: 0, y: 1 };

  25. var PI2 = Math.PI * 2;

  26. var timeOfLastTouch = 0;

  27. init();
  28. play();

  29. function init() {

  30.     canvas = document.getElementById( 'canvas' );

  31.     document.onmousedown = onDocumentMouseDown;
  32.     document.onmouseup = onDocumentMouseUp;
  33.     document.onmousemove = onDocumentMouseMove;
  34.     document.ondblclick = onDocumentDoubleClick;

  35.     document.addEventListener( 'touchstart', onDocumentTouchStart, false );
  36.     document.addEventListener( 'touchmove', onDocumentTouchMove, false );
  37.     document.addEventListener( 'touchend', onDocumentTouchEnd, false );

  38.     window.addEventListener( 'deviceorientation', onWindowDeviceOrientation, false );

  39.     // init box2d

  40.     worldAABB = new b2AABB();
  41.     worldAABB.minVertex.Set( -200, -200 );
  42.     worldAABB.maxVertex.Set( window.innerWidth + 200, window.innerHeight + 200 );

  43.     world = new b2World( worldAABB, new b2Vec2( 0, 0 ), true );

  44.     setWalls();
  45.     reset();
  46. }


  47. function play() {

  48.     setInterval( loop, 1000 / 40 );
  49. }

  50. function reset() {

  51.     var i;

  52.     if ( bodies ) {

  53.         for ( i = 0; i < bodies.length; i++ ) {

  54.             var body = bodies[ i ]
  55.             canvas.removeChild( body.GetUserData().element );
  56.             world.DestroyBody( body );
  57.             body = null;
  58.         }
  59.     }

  60.     // color theme
  61.     theme = themes[ Math.random() * themes.length >> 0 ];
  62.     document.body.style[ 'backgroundColor' ] = theme[ 0 ];

  63.     bodies = [];
  64.     elements = [];

  65.     createInstructions();

  66.     for( i = 0; i < 10; i++ ) {

  67.         createBall();

  68.     }

  69. }

  70. //

  71. function onDocumentMouseDown() {

  72.     isMouseDown = true;
  73.     return false;
  74. }

  75. function onDocumentMouseUp() {

  76.     isMouseDown = false;
  77.     return false;
  78. }

  79. function onDocumentMouseMove( event ) {

  80.     mouse.x = event.clientX;
  81.     mouse.y = event.clientY;
  82. }

  83. function onDocumentDoubleClick() {

  84.     reset();
  85. }

  86. function onDocumentTouchStart( event ) {

  87.     if( event.touches.length == 1 ) {

  88.         event.preventDefault();

  89.         // Faking double click for touch devices

  90.         var now = new Date().getTime();

  91.         if ( now - timeOfLastTouch  < 250 ) {

  92.             reset();
  93.             return;
  94.         }

  95.         timeOfLastTouch = now;

  96.         mouse.x = event.touches[ 0 ].pageX;
  97.         mouse.y = event.touches[ 0 ].pageY;
  98.         isMouseDown = true;
  99.     }
  100. }

  101. function onDocumentTouchMove( event ) {

  102.     if ( event.touches.length == 1 ) {

  103.         event.preventDefault();

  104.         mouse.x = event.touches[ 0 ].pageX;
  105.         mouse.y = event.touches[ 0 ].pageY;

  106.     }

  107. }

  108. function onDocumentTouchEnd( event ) {

  109.     if ( event.touches.length == 0 ) {

  110.         event.preventDefault();
  111.         isMouseDown = false;

  112.     }

  113. }

  114. function onWindowDeviceOrientation( event ) {

  115.     if ( event.beta ) {

  116.         gravity.x = Math.sin( event.gamma * Math.PI / 180 );
  117.         gravity.y = Math.sin( ( Math.PI / 4 ) + event.beta * Math.PI / 180 );

  118.     }

  119. }

  120. //

  121. function createInstructions() {

  122.     var size = 250;

  123.     var element = document.createElement( 'div' );
  124.     element.width = size;
  125.     element.height = size;    
  126.     element.style.position = 'absolute';
  127.     element.style.left = -200 + 'px';
  128.     element.style.top = -200 + 'px';
  129.     element.style.cursor = "default";

  130.     canvas.appendChild(element);
  131.     elements.push( element );

  132.     var circle = document.createElement( 'canvas' );
  133.     circle.width = size;
  134.     circle.height = size;

  135.     var graphics = circle.getContext( '2d' );

  136.     graphics.fillStyle = theme[ 3 ];
  137.     graphics.beginPath();
  138.     graphics.arc( size * .5, size * .5, size * .5, 0, PI2, true );
  139.     graphics.closePath();
  140.     graphics.fill();

  141.     element.appendChild( circle );

  142.     text = document.createElement( 'div' );
  143.     text.onSelectStart = null;
  144.     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>';
  145.     text.style.color = theme[1];
  146.     text.style.position = 'absolute';
  147.     text.style.left = '0px';
  148.     text.style.top = '0px';
  149.     text.style.fontFamily = 'Georgia';
  150.     text.style.textAlign = 'center';
  151.     element.appendChild(text);

  152.     text.style.left = ((250 - text.clientWidth) / 2) +'px';
  153.     text.style.top = ((250 - text.clientHeight) / 2) +'px';    

  154.     var b2body = new b2BodyDef();

  155.     var circle = new b2CircleDef();
  156.     circle.radius = size / 2;
  157.     circle.density = 1;
  158.     circle.friction = 0.3;
  159.     circle.restitution = 0.3;
  160.     b2body.AddShape(circle);
  161.     b2body.userData = {element: element};

  162.     b2body.position.Set( Math.random() * stage[2], Math.random() * -200 );
  163.     b2body.linearVelocity.Set( Math.random() * 400 - 200, Math.random() * 400 - 200 );
  164.     bodies.push( world.CreateBody(b2body) );    
  165. }

  166. function createBall( x, y ) {

  167.     var x = x || Math.random() * stage[2];
  168.     var y = y || Math.random() * -200;

  169.     var size = (Math.random() * 100 >> 0) + 20;

  170.     var element = document.createElement("canvas");
  171.     element.width = size;
  172.     element.height = size;
  173.     element.style.position = 'absolute';
  174.     element.style.left = -200 + 'px';
  175.     element.style.top = -200 + 'px';
  176.     element.style.WebkitTransform = 'translateZ(0)';
  177.     element.style.MozTransform = 'translateZ(0)';
  178.     element.style.OTransform = 'translateZ(0)';
  179.     element.style.msTransform = 'translateZ(0)';
  180.     element.style.transform = 'translateZ(0)';

  181.     var graphics = element.getContext("2d");

  182.     var num_circles = Math.random() * 10 >> 0;

  183.     for (var i = size; i > 0; i-= (size/num_circles)) {

  184.         graphics.fillStyle = theme[ (Math.random() * 4 >> 0) + 1];
  185.         graphics.beginPath();
  186.         graphics.arc(size * .5, size * .5, i * .5, 0, PI2, true); 
  187.         graphics.closePath();
  188.         graphics.fill();
  189.     }

  190.     canvas.appendChild(element);

  191.     elements.push( element );

  192.     var b2body = new b2BodyDef();

  193.     var circle = new b2CircleDef();
  194.     circle.radius = size >> 1;
  195.     circle.density = 1;
  196.     circle.friction = 0.3;
  197.     circle.restitution = 0.3;
  198.     b2body.AddShape(circle);
  199.     b2body.userData = {element: element};

  200.     b2body.position.Set( x, y );
  201.     b2body.linearVelocity.Set( Math.random() * 400 - 200, Math.random() * 400 - 200 );
  202.     bodies.push( world.CreateBody(b2body) );
  203. }

  204. //

  205. function loop() {

  206.     if (getBrowserDimensions()) {

  207.         setWalls();

  208.     }

  209.     delta[0] += (0 - delta[0]) * .5;
  210.     delta[1] += (0 - delta[1]) * .5;

  211.     world.m_gravity.x = gravity.x * 350 + delta[0];
  212.     world.m_gravity.y = gravity.y * 350 + delta[1];

  213.     mouseDrag();
  214.     world.Step(timeStep, iterations);

  215.     for (i = 0; i < bodies.length; i++) {

  216.         var body = bodies[i];
  217.         var element = elements[i];

  218.         element.style.left = (body.m_position0.x - (element.width >> 1)) + 'px';
  219.         element.style.top = (body.m_position0.y - (element.height >> 1)) + 'px';

  220.         if (element.tagName == 'DIV') {

  221.             var style = 'rotate(' + (body.m_rotation0 * 57.2957795) + 'deg) translateZ(0)';
  222.             text.style.WebkitTransform = style;
  223.             text.style.MozTransform = style;
  224.             text.style.OTransform = style;
  225.             text.style.msTransform = style;
  226.             text.style.transform = style;

  227.         }

  228.     }

  229. }


  230. // .. BOX2D UTILS

  231. function createBox(world, x, y, width, height, fixed) {

  232.     if (typeof(fixed) == 'undefined') {

  233.         fixed = true;

  234.     }

  235.     var boxSd = new b2BoxDef();

  236.     if (!fixed) {

  237.         boxSd.density = 1.0;

  238.     }

  239.     boxSd.extents.Set(width, height);

  240.     var boxBd = new b2BodyDef();
  241.     boxBd.AddShape(boxSd);
  242.     boxBd.position.Set(x,y);

  243.     return world.CreateBody(boxBd);

  244. }

  245. function mouseDrag()
  246. {
  247.     // mouse press
  248.     if (createMode) {

  249.         createBall( mouse.x, mouse.y );

  250.     } else if (isMouseDown && !mouseJoint) {

  251.         var body = getBodyAtMouse();

  252.         if (body) {

  253.             var md = new b2MouseJointDef();
  254.             md.body1 = world.m_groundBody;
  255.             md.body2 = body;
  256.             md.target.Set(mouse.x, mouse.y);
  257.             md.maxForce = 30000 * body.m_mass;
  258.             // md.timeStep = timeStep;
  259.             mouseJoint = world.CreateJoint(md);
  260.             body.WakeUp();

  261.         } else {

  262.             createMode = true;

  263.         }

  264.     }

  265.     // mouse release
  266.     if (!isMouseDown) {

  267.         createMode = false;
  268.         destroyMode = false;

  269.         if (mouseJoint) {

  270.             world.DestroyJoint(mouseJoint);
  271.             mouseJoint = null;

  272.         }

  273.     }

  274.     // mouse move
  275.     if (mouseJoint) {

  276.         var p2 = new b2Vec2(mouse.x, mouse.y);
  277.         mouseJoint.SetTarget(p2);
  278.     }
  279. }

  280. function getBodyAtMouse() {

  281.     // Make a small box.
  282.     var mousePVec = new b2Vec2();
  283.     mousePVec.Set(mouse.x, mouse.y);

  284.     var aabb = new b2AABB();
  285.     aabb.minVertex.Set(mouse.x - 1, mouse.y - 1);
  286.     aabb.maxVertex.Set(mouse.x + 1, mouse.y + 1);

  287.     // Query the world for overlapping shapes.
  288.     var k_maxCount = 10;
  289.     var shapes = new Array();
  290.     var count = world.Query(aabb, shapes, k_maxCount);
  291.     var body = null;

  292.     for (var i = 0; i < count; ++i) {

  293.         if (shapes[i].m_body.IsStatic() == false) {

  294.             if ( shapes[i].TestPoint(mousePVec) ) {

  295.                 body = shapes[i].m_body;
  296.                 break;

  297.             }

  298.         }

  299.     }

  300.     return body;

  301. }

  302. function setWalls() {

  303.     if (wallsSetted) {

  304.         world.DestroyBody(walls[0]);
  305.         world.DestroyBody(walls[1]);
  306.         world.DestroyBody(walls[2]);
  307.         world.DestroyBody(walls[3]);

  308.         walls[0] = null; 
  309.         walls[1] = null;
  310.         walls[2] = null;
  311.         walls[3] = null;
  312.     }

  313.     walls[0] = createBox(world, stage[2] / 2, - wall_thickness, stage[2], wall_thickness);
  314.     walls[1] = createBox(world, stage[2] / 2, stage[3] + wall_thickness, stage[2], wall_thickness);
  315.     walls[2] = createBox(world, - wall_thickness, stage[3] / 2, wall_thickness, stage[3]);
  316.     walls[3] = createBox(world, stage[2] + wall_thickness, stage[3] / 2, wall_thickness, stage[3]);    

  317.     wallsSetted = true;

  318. }

  319. // BROWSER DIMENSIONS

  320. function getBrowserDimensions() {

  321.     var changed = false;

  322.     if (stage[0] != window.screenX) {

  323.         delta[0] = (window.screenX - stage[0]) * 50;
  324.         stage[0] = window.screenX;
  325.         changed = true;

  326.     }

  327.     if (stage[1] != window.screenY) {

  328.         delta[1] = (window.screenY - stage[1]) * 50;
  329.         stage[1] = window.screenY;
  330.         changed = true;

  331.     }

  332.     if (stage[2] != window.innerWidth) {

  333.         stage[2] = window.innerWidth;
  334.         changed = true;

  335.     }

  336.     if (stage[3] != window.innerHeight) {

  337.         stage[3] = window.innerHeight;
  338.         changed = true;

  339.     }

  340.     return changed;

  341. }
复制代码

上面mouseDrag方法就实现了鼠标拖拽甩动小球的功能,这也是该动画最重要的方法。全部代码可以下载源码来研究。

源码下载



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值