Html5 Canvas+JavaScript物理引擎实例
2015-06-06 12:55
771 查看
Html5 Canvas+JavaScript物理引擎实例 canvas绘制蜘蛛和js物理引擎模拟行为的实现 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>Document</title> <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/146/73fi1rab/objects.js"></script> <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/146/73fi1rab/verlet.js"></script> <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/146/73fi1rab/constraint.js"></script> <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/146/73fi1rab/vec2.js"></script> <canvas id="scratch" style="width: 800px; height: 500px;"></canvas> <style>@font-face { font-family: 'Libre Baskerville'; font-style: normal; font-weight: 400; src: local('Libre Baskerville'), local('LibreBaskerville-Regular'), url(http://themes.googleusercontent.com/static/fonts/librebaskerville/v1/pR0sBQVcY0JZc_ciXjFsK5Rby8KfwQsaipLBqMCVNtM.woff) format('woff'); } @font-face { font-family: 'Libre Baskerville'; font-style: normal; font-weight: 700; src: local('Libre Baskerville Bold'), local('LibreBaskerville-Bold'), url(http://themes.googleusercontent.com/static/fonts/librebaskerville/v1/kH7K4InNTm7mmOXXjrA5vz8SLKRGgamuUl1hIefMyNI.woff) format('woff'); } @font-face { font-family: 'Libre Baskerville'; font-style: italic; font-weight: 400; src: local('Libre Baskerville Italic'), local('LibreBaskerville-Italic'), url(http://themes.googleusercontent.com/static/fonts/librebaskerville/v1/QHIOz1iKF3bIEzRdDFaf5dgliI79_bmRXH6crmREtCo.woff) format('woff'); } body { background: #e4e6e8; background: -moz-linear-gradient(top, #ffffff 0%, #e4e8ee 20%, #e4e8ee 80%, #ffffff 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(20%,#e4e8ee), color-stop(80%,#e4e8ee), color-stop(100%,#ffffff)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #ffffff 0%,#e4e8ee 20%,#e4e8ee 80%,#ffffff 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #ffffff 0%,#e4e8ee 20%,#e4e8ee 80%,#ffffff 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #ffffff 0%,#e4e8ee 20%,#e4e8ee 80%,#ffffff 100%); /* IE10+ */ background: linear-gradient(to bottom, #ffffff 0%,#e4e8ee 20%,#e4e8ee 80%,#ffffff 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */ color: #969ba3; font-family: "Libre Baskerville", sans-serif; font-weight: 400; line-height: 1.2em; } canvas { display: block; margin: 34px auto; background: #fff; box-shadow: 2px 2px 8px 0px rgba(0,0,0,0.1); }</style> <script> VerletJS.prototype.spider = function(origin) { var i; var legSeg1Stiffness = 0.99; var legSeg2Stiffness = 0.99; var legSeg3Stiffness = 0.99; var legSeg4Stiffness = 0.99; var joint1Stiffness = 1; var joint2Stiffness = 0.4; var joint3Stiffness = 0.9; var bodyStiffness = 1; var bodyJointStiffness = 1; var composite = new this.Composite(); composite.legs = []; composite.thorax = new Particle(origin); composite.head = new Particle(origin.add(new Vec2(0,-5))); composite.abdomen = new Particle(origin.add(new Vec2(0,10))); composite.particles.push(composite.thorax); composite.particles.push(composite.head); composite.particles.push(composite.abdomen); composite.constraints.push(new DistanceConstraint(composite.head, composite.thorax, bodyStiffness)); composite.constraints.push(new DistanceConstraint(composite.abdomen, composite.thorax, bodyStiffness)); composite.constraints.push(new AngleConstraint(composite.abdomen, composite.thorax, composite.head, 0.4)); // 蜘蛛腿 for (i=0;i<4;++i) { composite.particles.push(new Particle(composite.particles[0].pos.add(new Vec2(3,(i-1.5)*3)))); composite.particles.push(new Particle(composite.particles[0].pos.add(new Vec2(-3,(i-1.5)*3)))); var len = composite.particles.length; composite.constraints.push(new DistanceConstraint(composite.particles[len-2], composite.thorax, legSeg1Stiffness)); composite.constraints.push(new DistanceConstraint(composite.particles[len-1], composite.thorax, legSeg1Stiffness)); var lenCoef = 1; if (i == 1 || i == 2) lenCoef = 0.7; else if (i == 3) lenCoef = 0.9; composite.particles.push(new Particle(composite.particles[len-2].pos.add((new Vec2(20,(i-1.5)*30)).normal().mutableScale(20*lenCoef)))); composite.particles.push(new Particle(composite.particles[len-1].pos.add((new Vec2(-20,(i-1.5)*30)).normal().mutableScale(20*lenCoef)))); len = composite.particles.length; composite.constraints.push(new DistanceConstraint(composite.particles[len-4], composite.particles[len-2], legSeg2Stiffness)); composite.constraints.push(new DistanceConstraint(composite.particles[len-3], composite.particles[len-1], legSeg2Stiffness)); composite.particles.push(new Particle(composite.particles[len-2].pos.add((new Vec2(20,(i-1.5)*50)).normal().mutableScale(20*lenCoef)))); composite.particles.push(new Particle(composite.particles[len-1].pos.add((new Vec2(-20,(i-1.5)*50)).normal().mutableScale(20*lenCoef)))); len = composite.particles.length; composite.constraints.push(new DistanceConstraint(composite.particles[len-4], composite.particles[len-2], legSeg3Stiffness)); composite.constraints.push(new DistanceConstraint(composite.particles[len-3], composite.particles[len-1], legSeg3Stiffness)); var rightFoot = new Particle(composite.particles[len-2].pos.add((new Vec2(20,(i-1.5)*100)).normal().mutableScale(12*lenCoef))); var leftFoot = new Particle(composite.particles[len-1].pos.add((new Vec2(-20,(i-1.5)*100)).normal().mutableScale(12*lenCoef))) composite.particles.push(rightFoot); composite.particles.push(leftFoot); composite.legs.push(rightFoot); composite.legs.push(leftFoot); len = composite.particles.length; composite.constraints.push(new DistanceConstraint(composite.particles[len-4], composite.particles[len-2], legSeg4Stiffness)); composite.constraints.push(new DistanceConstraint(composite.particles[len-3], composite.particles[len-1], legSeg4Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[len-6], composite.particles[len-4], composite.particles[len-2], joint3Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[len-6+1], composite.particles[len-4+1], composite.particles[len-2+1], joint3Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[len-8], composite.particles[len-6], composite.particles[len-4], joint2Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[len-8+1], composite.particles[len-6+1], composite.particles[len-4+1], joint2Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[0], composite.particles[len-8], composite.particles[len-6], joint1Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[0], composite.particles[len-8+1], composite.particles[len-6+1], joint1Stiffness)); composite.constraints.push(new AngleConstraint(composite.particles[1], composite.particles[0], composite.particles[len-8], bodyJointStiffness)); composite.constraints.push(new AngleConstraint(composite.particles[1], composite.particles[0], composite.particles[len-8+1], bodyJointStiffness)); } this.composites.push(composite); return composite; } VerletJS.prototype.spiderweb = function(origin, radius, segments, depth) { var stiffness = 0.6; var tensor = 0.3; var stride = (2*Math.PI)/segments; var n = segments*depth; var radiusStride = radius/n; var i, c; var composite = new this.Composite(); // 粒子系统 for (i=0;i<n;++i) { var theta = i*stride + Math.cos(i*0.4)*0.05 + Math.cos(i*0.05)*0.2; var shrinkingRadius = radius - radiusStride*i + Math.cos(i*0.1)*20; var offy = Math.cos(theta*2.1)*(radius/depth)*0.2; composite.particles.push(new Particle(new Vec2(origin.x + Math.cos(theta)*shrinkingRadius, origin.y + Math.sin(theta)*shrinkingRadius + offy))); } for (i=0;i<segments;i+=4) composite.pin(i); // 约束 for (i=0;i<n-1;++i) { // 邻接 composite.constraints.push(new DistanceConstraint(composite.particles[i], composite.particles[i+1], stiffness)); // 跨环 var off = i + segments; if (off < n-1) composite.constraints.push(new DistanceConstraint(composite.particles[i], composite.particles[off], stiffness)); else composite.constraints.push(new DistanceConstraint(composite.particles[i], composite.particles[n-1], stiffness)); } composite.constraints.push(new DistanceConstraint(composite.particles[0], composite.particles[segments-1], stiffness)); for (c in composite.constraints) composite.constraints[c].distance *= tensor; this.composites.push(composite); return composite; } function shuffle(o) { for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); return o; } VerletJS.prototype.crawl = function(leg) { var stepRadius = 100; var minStepRadius = 35; var spiderweb = this.composites[0]; var spider = this.composites[1]; var theta = spider.particles[0].pos.angle2(spider.particles[0].pos.add(new Vec2(1,0)), spider.particles[1].pos); var boundry1 = (new Vec2(Math.cos(theta), Math.sin(theta))); var boundry2 = (new Vec2(Math.cos(theta+Math.PI/2), Math.sin(theta+Math.PI/2))); var flag1 = leg < 4 ? 1 : -1; var flag2 = leg%2 == 0 ? 1 : 0; var paths = []; var i; for (i in spiderweb.particles) { if ( spiderweb.particles[i].pos.sub(spider.particles[0].pos).dot(boundry1)*flag1 >= 0 && spiderweb.particles[i].pos.sub(spider.particles[0].pos).dot(boundry2)*flag2 >= 0 ) { var d2 = spiderweb.particles[i].pos.dist2(spider.particles[0].pos); if (!(d2 >= minStepRadius*minStepRadius && d2 <= stepRadius*stepRadius)) continue; var leftFoot = false; var j; for (j in spider.constraints) { var k; for (k=0;k<8;++k) { if ( spider.constraints[j] instanceof DistanceConstraint && spider.constraints[j].a == spider.legs[k] && spider.constraints[j].b == spiderweb.particles[i]) { leftFoot = true; } } } if (!leftFoot) paths.push(spiderweb.particles[i]); } } for (i in spider.constraints) { if (spider.constraints[i] instanceof DistanceConstraint && spider.constraints[i].a == spider.legs[leg]) { spider.constraints.splice(i, 1); break; } } if (paths.length > 0) { shuffle(paths); spider.constraints.push(new DistanceConstraint(spider.legs[leg], paths[0], 1, 0)); } } window.onload = function() { var canvas = document.getElementById("scratch"); // canvas var width = parseInt(canvas.style.width); var height = parseInt(canvas.style.height); // 视网膜 var dpr = window.devicePixelRatio || 1; canvas.width = width*dpr; canvas.height = height*dpr; canvas.getContext("2d").scale(dpr, dpr); // 模拟 var sim = new VerletJS(width, height, canvas); // 实体 var spiderweb = sim.spiderweb(new Vec2(width/2,height/2), Math.min(width, height)/2, 20, 7); var spider = sim.spider(new Vec2(width/2,-300)); spiderweb.drawParticles = function(ctx, composite) { var i; for (i in composite.particles) { var point = composite.particles[i]; ctx.beginPath(); ctx.arc(point.pos.x, point.pos.y, 1.3, 0, 2*Math.PI); ctx.fillStyle = "#2dad8f"; ctx.fill(); } } spider.drawConstraints = function(ctx, composite) { var i; ctx.beginPath(); ctx.arc(spider.head.pos.x, spider.head.pos.y, 4, 0, 2*Math.PI); ctx.fillStyle = "#000"; ctx.fill(); ctx.beginPath(); ctx.arc(spider.thorax.pos.x, spider.thorax.pos.y, 4, 0, 2*Math.PI); ctx.fill(); ctx.beginPath(); ctx.arc(spider.abdomen.pos.x, spider.abdomen.pos.y, 8, 0, 2*Math.PI); ctx.fill(); for (i=3;i<composite.constraints.length;++i) { var constraint = composite.constraints[i]; if (constraint instanceof DistanceConstraint) { ctx.beginPath(); ctx.moveTo(constraint.a.pos.x, constraint.a.pos.y); ctx.lineTo(constraint.b.pos.x, constraint.b.pos.y); // 把腿 if ( (i >= 2 && i <= 4) || (i >= (2*9)+1 && i <= (2*9)+2) || (i >= (2*17)+1 && i <= (2*17)+2) || (i >= (2*25)+1 && i <= (2*25)+2) ) { ctx.save(); constraint.draw(ctx); ctx.strokeStyle = "#000"; ctx.lineWidth = 3; ctx.stroke(); ctx.restore(); } else if ( (i >= 4 && i <= 6) || (i >= (2*9)+3 && i <= (2*9)+4) || (i >= (2*17)+3 && i <= (2*17)+4) || (i >= (2*25)+3 && i <= (2*25)+4) ) { ctx.save(); constraint.draw(ctx); ctx.strokeStyle = "#000"; ctx.lineWidth = 2; ctx.stroke(); ctx.restore(); } else if ( (i >= 6 && i <= 8) || (i >= (2*9)+5 && i <= (2*9)+6) || (i >= (2*17)+5 && i <= (2*17)+6) || (i >= (2*25)+5 && i <= (2*25)+6) ) { ctx.save(); ctx.strokeStyle = "#000"; ctx.lineWidth = 1.5; ctx.stroke(); ctx.restore(); } else { ctx.strokeStyle = "#000"; ctx.stroke(); } } } } spider.drawParticles = function(ctx, composite) { } // 循环动画 var legIndex = 0; var loop = function() { if (Math.floor(Math.random()*4) == 0) { sim.crawl(((legIndex++)*3)%8); } sim.frame(16); sim.draw(); requestAnimFrame(loop); }; loop(); };</script> </head> <body> </body> </html> |
相关文章推荐
- JavaScript 中的内置对象
- js--DOM(事件处理)
- Javascript的setTimeOut和setInterval的定时器用法
- JavaScript的模块化:继承(原型)、封装(闭包)、多态
- js中的this、new关键字、作用域和作用域链
- javascript递归、循环、迭代、遍历和枚举概念
- Console命令调试js代码详解
- JS原型+构造函数创建对象
- Javascript匿名函数以及闭包的特性
- js切换搜索引擎效果
- Javascript模块化和命名空间管理
- javascript事件冒泡详解和捕获、阻止方法
- javascript展开滑块特效
- 原生js粒子时钟
- Javascript笔记
- JavaScript中的toLocaleLowerCase()方法使用详解
- JavaScript语言基础知识8
- javascript实战第一讲:聊天窗口
- JavaScript中的substr()方法使用详解
- Emberjs之Observer