您的位置:首页 > Web前端 > JavaScript

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>





















内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: