topical media & game development

talk show tell print

sample-collect-hush-js-sketch-files-physicsketch.js / js



  b2Settings.b2_maxPolyVertices = 50;
  
  /* demos/demo_base.js */
  function createWorld() {
          var worldAABB = new b2AABB();
          worldAABB.minVertex.Set(-1000, -1000);
          worldAABB.maxVertex.Set(1000, 1000);
          var gravity = new b2Vec2(0, 300);
          var doSleep = true;
          var world = new b2World(worldAABB, gravity, doSleep);
          createGround(world);
          return world;
  }
  
  function createGround(world) {
          var groundSd = new b2BoxDef();
          groundSd.extents.Set(2000, 50);
          groundSd.restitution = 0.2;
          var groundBd = new b2BodyDef();
          groundBd.AddShape(groundSd);
          groundBd.position.Set(-500, 547);
          return world.CreateBody(groundBd)
  }
  
  function createBall(world, x, y) {
          var ballSd = new b2CircleDef();
          ballSd.density = 1.0;
          ballSd.radius = 20;
          ballSd.restitution = 1.0;
          ballSd.friction = 0;
          var ballBd = new b2BodyDef();
          ballBd.AddShape(ballSd);
          ballBd.position.Set(x,y);
          return world.CreateBody(ballBd);
  }
  
  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)
  }
  
  /* physicSketch original part */
  function createBall(world, x, y, rad, fixed) {
          var ballSd = new b2CircleDef();
          if (!fixed) ballSd.density = 1.0;
          ballSd.radius = rad || 10;
          ballSd.restitution = 0.2;
          var ballBd = new b2BodyDef();
          ballBd.AddShape(ballSd);
          ballBd.position.Set(x,y);
          return world.CreateBody(ballBd);
  };
  
  var Stroke = Class.create({
    initialize: function(x, y) {
      this.points = A([[0, 0]]);
      this.baseX = x;
      this.baseY = y;
      this.topIndex = 0;
      this.angles = A();
      this.body = null;
      this.bodyType = null;
      this.selected = false;
      this.draggedPoint = null;
      this.cullPoints = null;
      this.fillStyle = '#FFFFFF';
    },
  
    getFillStyle: function() {
      //return this.selected ? '#EEEEFF' : this.fillStyle;
      return this.fillStyle;
    },
  
    getStrokeStyle: function() {
      // not used
      return this.selected ? '#FF0000' : this.strokeStyle;
    },
  
    addPoint: function(x, y) {
      x -= this.baseX;
      y -= this.baseY;
      this.points.push([x, y]);
      if (this.points[this.topIndex][1] < y) {
        this.topIndex = this.points.length - 1;
      }
    },
  
    becomeBodyIn: function(w) {
      if (this.points.length < 3) return;
      var firstPoint = new b2Vec2(this.points.first()[0], this.points.first()[1]);
      var lastPoint = new b2Vec2(this.points.last()[0], this.points.last()[1]);
      firstPoint.Subtract(lastPoint);
      if (firstPoint.Length() < 30.0) {
        this.drawShape();
      }
      else {
        this.drawLines();
      }
    },
  
    drawShape: function() {
      var ps = A();
      for (var i = 0; i < this.points.length; i++) {
        ps.push(this.points[(this.topIndex + i) % this.points.length]);
      }
      ps.push(this.points[this.topIndex]);
  
      var cw = A();
      var cwAngles = A();
      for (var i = 0; i < ps.length; i++) {
        this.addConvexPoint(cw, ps[i], cwAngles);
      }
      var ccw = A();
      var ccwAngles = A();
      for (var i = ps.length - 1; 0 <= i; i--) {
        this.addConvexPoint(ccw, ps[i], ccwAngles);
      }
      var massPoints;
      if (cw.length < ccw.length) {
        massPoints = ccw;
        this.angles = ccwAngles;
      }
      else {
        massPoints = cw;
        this.angles = cwAngles;
      }
      massPoints.pop();
  
      this.cullPoints = A();
      if (massPoints.length < b2Settings.b2_maxPolyVertices) {
        this.cullPoints = massPoints;
      }
      else {
        for (var i = 0; i < massPoints.length - 1; i++) {
          if (i % Stroke.INTERVAL == 0) {
            this.cullPoints.push(massPoints[i]);
          }
        }
        this.cullPoints.push(massPoints[massPoints.length - 1]);
      }
      if (2 < this.cullPoints.length) {
        this.body = this.createPoly(world, this.baseX, this.baseY, this.cullPoints);
        this.bodyType = 'poly';
      }
    },
  
    addConvexPoint: function(ary, p, angleAry) {
      if (ary.length < 2) {
        ary.push(p);
        return;
      }
      var p1 = ary[ary.length-2];
      var p2 = ary[ary.length-1];
      var p3 = p;
      var v12 = new b2Vec2(p2[0] - p1[0], p2[1] - p1[1]);
      var v13 = new b2Vec2(p3[0] - p1[0], p3[1] - p1[1]);
      if (0 < b2Math.b2CrossVV(v12, v13)) {
        var angle = Math.acos(b2Math.b2CrossVV(v12, v13) / (v13.Length() * v12.Length()));
        angleAry.push(angle);
        ary.push(p);
      }
      else {
        angleAry.pop();
        ary.pop();
        this.addConvexPoint(ary, p, angleAry);
      }
    },
  
    drawLines: function() {
      this.cullPoints = A();
      for (var i = 0; i < this.points.length - 1; i++) {
        //if (i % Stroke.INTERVAL == 0) {
        if (i % 10 == 0) {
          this.cullPoints.push(this.points[i]);
        }
      }
      if (this.cullPoints.last()[0] != this.points.last()[0] || 
          this.cullPoints.last()[1] != this.points.last()[1]) {
        this.cullPoints.push(this.points.last());
      }
      this.body = this.createLines(world, this.baseX, this.baseY, this.cullPoints);
      this.bodyType = 'lines';
    },
  
    createPoly: function(world, x, y, points) {
      var polySd = new b2PolyDef();
      polySd.density = 1.0;
      polySd.vertexCount = points.length;
      for (var i = 0; i < points.length; i++) {
        polySd.vertices[i].Set(points[i][0], points[i][1]);
      }
      var polyBd = new b2BodyDef();
      polyBd.AddShape(polySd);
      polyBd.position.Set(x, y);
      return world.CreateBody(polyBd)
    },
  
    createLines: function(world, x, y, points) {
      var linesBd = new b2BodyDef();
      for (var i = 1; i < points.length; i++) {
        var p1 = points[i-1];
        var p2 = points[i]; 
        var w = new b2Vec2(p2[1] - p1[1], p1[0] - p2[0]);
        w.Normalize();
        w.Multiply(10);
        var lineSd = new b2PolyDef();
        lineSd.density = 1.0;
        lineSd.vertexCount = 4;
        lineSd.vertices[0].Set(p1[0], p1[1]);
        lineSd.vertices[1].Set(p2[0], p2[1]);
        lineSd.vertices[2].Set(p2[0] - w.x, p2[1] - w.y);
        lineSd.vertices[3].Set(p1[0] - w.x, p1[1] - w.y);
        linesBd.AddShape(lineSd);
      }
      linesBd.position.Set(x, y);
      var body = world.CreateBody(linesBd);
      return body;
    },
  
    hasBody: function() {
      return this.body != null;
    }
  });
  Stroke.INTERVAL = 3;
  
  /* demos/demos.js */
  var world = createWorld();
  var ctx;
  var canvasWidth;
  var canvasHeight;
  var canvasTop;
  var canvasLeft;
  var strokes = A();
  var trackingStroke = null;
  var selectedStroke = null;
  var draggingStroke = null;
  var draggedMouseXY = null;
  var clocking = true;
  var bodyVisibility = false;
  var usePin = true;
  
  var trackingStrokeStyle = '#FFFF00';
  var jointStrokeStyle = '#8888FF';
  var strokeStyle = '#A9A9A9';
  var selectedStrokeStyle = '#FF0000';
  
  function getStrokeStyle(selected) {
    return selected ? selectedStrokeStyle : strokeStyle;
  }
  function changeStrokeColor(code) {
    strokeStyle = code;
  }
  function changeSelectedStrokeColor(code) {
    selectedStrokeStyle = code;
  }
  
  function toggleTimer(elm) {
    clocking = !clocking;
    if (clocking) {
      elm.innerHTML = 'stop timer';
    }
    else {
      elm.innerHTML = 'start timer';
    }
  }
  function toggleBodyVisibility(elm) {
    bodyVisibility = !bodyVisibility;
    if (bodyVisibility) {
      elm.innerHTML = 'hide physical body';
    }
    else {
      elm.innerHTML = 'show physical body';
    }
  }
  function showInformation(stroke) {
    var body = stroke.body;
    var position = body.GetCenterPosition();
    $('position-x').innerHTML = Math.floor(position.x);
    $('position-y').innerHTML = Math.floor(position.y);
    //$('angle').innerHTML = Math.floor(body.m_rotation * 180.0 % 360);
    $('angle').innerHTML = Math.floor(body.m_rotation * 60.0 % 360); //TODO: what's 60.0?
    $('body-color').value = stroke.fillStyle;
  }
  function deleteSelectedBody() {
    if (!selectedStroke) return;
    var newStrokes = A();
    for (var i = 0; i < strokes.length; i++) {
      var stroke = strokes[i];
      if (selectedStroke == stroke) {
        world.DestroyBody(stroke.body);
      }
      else {
        newStrokes.push(stroke);
      }
    }
    strokes = newStrokes;
  }
  function togglePin(elm) {
    usePin = !usePin;
    if (usePin) {
      elm.innerHTML = 'Not Use Pin';
    }
    else {
      elm.innerHTML = 'Use Pin';
    }
  }
  function changeFillColor(code) {
    selectedStroke.fillStyle = code;
  }
  function drawStrokes(context) {
    function pointInWorld(stroke, index) {
      var body = stroke.body;
      var shape = body.GetShapeList();
      var point = stroke.points[index];
      var vec = new b2Vec2(point[0], point[1]);
      var baseVec = body.m_center;
      var tmpPoint = b2Math.SubtractVV(vec, baseVec);
            return b2Math.AddVV(body.m_position, b2Math.b2MulMV(body.m_R, tmpPoint));
    }
  
          context.lineWidth = 5;
    for (var i = 0; i < strokes.length; i++) {
      //context.strokeStyle = strokes[i].getStrokeStyle();
      context.strokeStyle = getStrokeStyle(strokes[i].selected);
      context.fillStyle = strokes[i].getFillStyle();
      var point = pointInWorld(strokes[i], 0);
      context.beginPath();
      context.moveTo(point.x, point.y);
      for (var j = 1; j < strokes[i].points.length; j++) {
        point = pointInWorld(strokes[i], j);
        context.lineTo(point.x, point.y);
      }
      if (strokes[i].bodyType == 'poly') {
        point = pointInWorld(strokes[i], 0);
        context.lineTo(point.x, point.y);
        context.fill();
        context.stroke();
      }
      else {
        context.stroke();
      }
    }
  }
  function drawTracking(context) {
    if (!trackingStroke) return;
          context.strokeStyle = trackingStrokeStyle;
          context.lineWidth = 5;
    var points = trackingStroke.points;
    if (points.length < 2) return;
    context.beginPath();
    context.moveTo(trackingStroke.baseX + points[0][0], trackingStroke.baseY + points[0][1]);
    for (var i = 1; i < points.length; i++) {
      context.lineTo(trackingStroke.baseX + points[i][0], trackingStroke.baseY + points[i][1]);
    }
    context.stroke();
  }
  function drawJoints(context) {
          for (var joint = world.m_jointList; joint; joint = joint.m_next) {
      var p = joint.GetAnchor1();
      context.strokeStyle = jointStrokeStyle;
      context.lineWidth = 3;
      context.beginPath();
      context.moveTo(p.x - 5, p.y - 5)
      context.lineTo(p.x + 5, p.y + 5)
      context.stroke();
      context.beginPath();
      context.moveTo(p.x + 5, p.y - 5)
      context.lineTo(p.x - 5, p.y + 5)
      context.stroke();
    }
  }
  function jointStrokesAt(stroke1, stroke2, x, y) {
          var jointDef = new b2RevoluteJointDef();
    jointDef.anchorPoint.Set(x, y);
    jointDef.body1 = stroke1.body;
    jointDef.body2 = stroke2 ? stroke2.body : world.GetGroundBody();
    world.CreateJoint(jointDef);
  }
  function step(cnt) {
    cnt = cnt || 0;
          var stepping = false;
          var timeStep = 1.0/60;
          var iteration = 1;
    if (clocking && !trackingStroke) {
            world.Step(timeStep, iteration);
      $('timer').style.WebkitTransform = 'rotate(' + ((cnt * 2) % 360) + 'deg)';
      cnt++;
    }
          ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    drawStrokes(ctx);
    drawTracking(ctx);
    drawJoints(ctx);
    if (selectedStroke) {
      $('body-inspector').show();
      showInformation(selectedStroke);
    }
    else {
      $('body-inspector').hide();
    }
    if (bodyVisibility) drawWorld(world, ctx);
          setTimeout('step(' + cnt + ')', 1);
  }
  Event.observe(window, 'load', function() {
          ctx = $('canvas').getContext('2d');
          var canvasElm = $('canvas');
          canvasWidth = parseInt(canvasElm.width);
          canvasHeight = parseInt(canvasElm.height);
          canvasTop = parseInt(canvasElm.style.top);
          canvasLeft = parseInt(canvasElm.style.left);
    function getXY(e) {
      return [Event.pointerX(e) - canvasLeft, Event.pointerY(e) - canvasTop];
    }
    function strokesAt(xy) {
      var strokesAtThisPoint = A();
      for (var i = 0; i < strokes.length; i++) {
        if (!strokes[i].body) continue;
        var test = false;
        for (var shape = strokes[i].body.GetShapeList(); shape != null; shape = shape.GetNext()) {
          if (shape.TestPoint(new b2Vec2(xy[0], xy[1]))) {
            test = true;
          }
        }
        if (test) strokesAtThisPoint.push(strokes[i]);
      }
      return strokesAtThisPoint;
    }
    function clearSelectStroke() {
      for (var i = 0; i < strokes.length; i++) {
        if (!strokes[i].body) continue;
        strokes[i].selected = false;
      }
      selectedStroke = null;
    }
    function selectStroke(xy) {
      clearSelectStroke();
      var selectedStrokes = strokesAt(xy);
      if (selectedStrokes.length != 0) {
        selectedStroke = selectedStrokes.last();
        selectedStroke.selected = true;
      }
    }
          Event.observe('canvas', 'mousedown', function(e) {
      var xy = getXY(e);
      var strokesAtThisPoint = strokesAt(xy);
      if (selectedStroke && !clocking && strokesAtThisPoint.length != 0) {
        var clickSelectedStroke = false;
        for (var i = 0; i < strokesAtThisPoint.length; i++) {
          clickSelectedStroke = clickSelectedStroke || (strokesAtThisPoint[i] == selectedStroke);
        }
        if (clickSelectedStroke) {
          draggedMouseXY = xy;
          selectedStroke.draggedPoint = selectedStroke.body.GetCenterPosition().Copy();
        }
        else {
          trackingStroke = new Stroke(xy[0], xy[1]);
        }
      }
      else {
        trackingStroke = new Stroke(xy[0], xy[1]);
      }
          });
          Event.observe('canvas', 'mousemove', function(e) {
      var xy = getXY(e);
      if (selectedStroke && !clocking && draggedMouseXY) {
        if (selectedStroke.draggedPoint) {
          var selectedBody = selectedStroke.body;
          var nextPosition = selectedStroke.draggedPoint.Copy();
          nextPosition.Add(new b2Vec2(xy[0] - draggedMouseXY[0], xy[1] - draggedMouseXY[1]));
          selectedBody.SetCenterPosition(nextPosition, selectedBody.m_rotation);
        }
      }
      else if (trackingStroke) {
        trackingStroke.addPoint(xy[0], xy[1]);
      }
          });
          Event.observe('canvas', 'mouseup', function(e) {
      var xy = getXY(e);
      if (selectedStroke && !clocking && draggedMouseXY) {
        if (draggedMouseXY[0] == xy[0] && draggedMouseXY[1] == xy[1]) {
          if (usePin) {
            var strokesAtThisPoint = strokesAt(xy);
            if (0 < strokesAtThisPoint.length) {
              jointStrokesAt(strokesAtThisPoint[0], strokesAtThisPoint[1], xy[0], xy[1]);
            }
          }
          else {
            selectStroke(xy);
          }
        }
        draggedMouseXY = null;
        selectedStroke.draggedPoint = null;
      }
      else if (trackingStroke) {
        if (trackingStroke.points.length < 2) {
          trackingStroke = null;
          selectStroke(xy);
        }
        else {
          trackingStroke.addPoint(xy[0], xy[1]);
          trackingStroke.becomeBodyIn(world);
          if (trackingStroke.hasBody()) strokes.push(trackingStroke);
          trackingStroke = null;
        }
      }
          });
          step();
  });
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.