HTML5重力感应小球冲撞动画实现教程
今天我们来分享一款很酷的HTML5重力感应动画教程,这款动画可以让你甩动页面中的小球,小球的大小都不同,并且鼠标点击空白区域时又可以生成一定数量的小球。当我们甩动小球时,各个小球之间就会发生互相碰撞的效果,并且在运动过程中模拟了重力感应的物理效果。你可以在DEMO演示中来尝试一下。
你也可以在这里查看在线演示
接下来我们来分析一下这款超酷的HTML5重力动画实现的思路及源码,主要由HTML代码和Javascript代码组成。
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方法就实现了鼠标拖拽甩动小球的功能,这也是该动画最重要的方法。全部代码可以下载源码来研究。源码下载>>
HTML5重力感应小球冲撞动画实现教程的更多相关文章
- H5案例分享:html5重力感应事件
html5重力感应事件 一.手机重力感应图形分析 1.设备围绕z轴的旋转角度为α,α角度的取值范围在[0,360). 设备在初始位置,与地球(XYZ)和身体(XYZ)某个位置对齐. 设备围绕z轴的旋转 ...
- html5重力感应事件之DeviceMotionEvent
前言 今天主要介绍一下html5重力感应事件之DeviceMotionEvent,之前我的一篇文章http://www.haorooms.com/post/jquery_jGestures, 介绍了第 ...
- HTML5 重力感应效果,实现摇一摇效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- h5手机摇一摇功能实现:基于html5重力感应DeviceMotionEvent事件监听手机摇晃
DeviceMotionEven是html5提供的一个用来获取设备物理方向及运动的信息(比如陀螺仪.罗盘及加速计)的Dom事件,事件描述如下: deviceorientation:提供设备的物理方向信 ...
- 移动端html5重力感应
下面是测试案例,只测试过itouch,iphone http://06wjin.sinaapp.com/billd/ http://06wjin.sinaapp.com/billd/test. ...
- html5重力感应事件
if (window.DeviceMotionEvent) { window.addEventListener('devicemotion',deviceMotionHandler, false); ...
- 基于野火M3开发板(STM32F103VET6)的迷宫小球(重力感应控制)游戏开发
2013-03-03 这是研一上学期<实时嵌入式系统实验>课程的大作业,是利用野火板的资源,加上一个AHRS(Attitude and Heading Reference System,姿 ...
- HTML5 五彩圆环Loading加载动画实现教程
原文:HTML5 五彩圆环Loading加载动画实现教程 今天我们要来介绍一款效果很特别的HTML5 Loading加载动画,不像其他的Loading动画,这款Loading动画颜色很丰富,并且在转圈 ...
- html5水平方向重力感应
html5图片随手机重力感应而移动 <!DOCTYPE html> <html lang="zh-cn"><head><meta http ...
随机推荐
- 标准JAVA MD5方法
https://blog.csdn.net/wangfei0904306/article/details/71565968 ************************************** ...
- visio直线交叉相交跨线修改
在使用visio画流程图时,经常会遇到两条直线相交.下面讲如何修改使得相交点变成我们想要的方式. 可以设置如下: (1) 全局直线相交,设置跨线标志. (2) 对每条线进行相交跨线设置. (一) ...
- LeetCode: Gas Station 解题报告
Gas Station There are N gas stations along a circular route, where the amount of gas at station i is ...
- 如何通过Fiddler模拟弱网进行测试
[本文出自天外归云的博客园] 弱网测试的目的 弱网测试可以发现一些因为网络问题导致的交互问题,从而更好的完善应用的性能. 弱网的模拟 通过Fiddler可以模拟弱网进行测试,拿手机测试举例,进行手机a ...
- 用Python脚本在豆瓣音乐人小站上下载未开放下载的歌曲
[本文出自天外归云的博客园] 第一步,去你要下载的音乐人小站页面: 第二步,点开要下载的歌,在播放页面F12进入调试模式,在Network视图下可以看到mp3文件所在的url: 第三步,上脚本(需安装 ...
- JAVA-JSP内置对象之pageContext对象取得不同范围属性
相关资料:<21天学通Java Web开发> pageContext对象取得不同范围属性 pageContextDemo.jsp <%@ page language="ja ...
- js 删除数组几种方法
var arr=['a','b','c']; 若要删除其中的'b',有两种方法: 1.delete方法:delete arr[1] 这种方式数组长度不变,此时arr[1]变为undefined了,但是 ...
- [转]PowerDesigner表结构和字段大小写转换
原文地址:https://blog.csdn.net/u010216641/article/details/48712503 ##PowerDesigner去除双引号## 平时经常用PowerDesi ...
- 【转】jdbc:oracle:thin:@192.168.3.98:1521:orcl(详解)
整理自互联网 一. jdbc:oracle:thin:@192.168.3.98:1521:orcljdbc:表示采用jdbc方式连接数据库oracle:表示连接的是oracle数据库thin:表示连 ...
- am335x SPI spi_d0, spi_d1 out, in 模式设定
AM335x SPI DO DI 的模式 参考: https://www.deyisupport.com/question_answer/dsp_arm/sitara_arm/f/25/t/13826 ...