当前位置:嗨网首页>书籍在线阅读

43-处理小球

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

5.7.5 处理小球

在本例中,需要在Canvas上监听一个鼠标点击事件。当用户点击时,创建一个小球,并且小球会在画布上飞向箱子堆。首先需要做的事是为mouseup事件创建一个事件监听器。

theCanvas.addEventListener("mouseup",createBall, false);

接下来,需要创建createBall()函数。首先,从传递给createBall()函数的event对象中获取鼠标点击位置的x轴和y轴坐标。然后运用一些可以跨浏览器运行的代码计算出鼠标指针与Canvas的相对位置。下面的范例代码可以获得鼠标指针在画布上正确的x轴和y轴的坐标。

function createBall(event) {
  var x;
  var y;
  if (event.pageX || event.pageY) {
    x = event.pageX;
    y = event.pageY;
  }
  else {
    x = e.clientX + document.body.scrollLeft +
        document.documentElement.scrollLeft;
    y = e.clientY + document.body.scrollTop +
        document.documentElement.scrollTop;
  }
  x -= theCanvas.offsetLeft;
  y -= theCanvas.offsetTop;
  mouseX=x;
  mouseY=y;

因为捕获的x轴和y轴坐标是相对于Canvas的,所以需要确保HTML页面中的标签的样式中设置了top和left属性。只有这样,offsetLeft和offsetTop的值才正确。例如,如果将Canvas放在一个

标签中(50,50)的位置,但是top和left属性的值却是0,那么点击鼠标时就不能获得正确的位置。

<canvas id="canvasOne" width="450" height="350"
     style="position: absolute; top: 0px; left: 0px;">
 Your browser does not support the HTML5 Canvas.
</canvas>
<canvas id="canvasTwo" width="450" height="350"
     style="position: absolute; top: 0px; left: 451px;">
 Your browser does not support the HTML5 Canvas.
</canvas>

接下来,创建一个刚体对象,将b2BodyDef中的x轴和y轴位置设置为鼠标点击的位置,然后将小球的半径设置为7像素,参考以下代码。

var ballDef = new b2BodyDef;
ballDef.type = b2Body.b2_dynamicBody;
var ypos = mouseY/scaleFactor;
var xpos = mouseX/scaleFactor;
var size = 7/scaleFactor;
ballDef.position.Set(xpos, ypos);

接下来,创建一个fixture,将小球的密度设置为30(比箱子硬一些),friction设置为0.6(运行时的模拟效果更逼真)。然后将restitution设置为0.2,这个值比箱子和墙壁的值稍大,因为希望在撞击时,小球比箱子弹得更高。

var ballFixture = new b2FixtureDef;
ballFixture.density = 30.0;
ballFixture.friction = 0.6;
ballFixture.restitution = .2;
ballFixture.shape = new b2CircleShape(size);
var newBall = world.CreateBody(ballDef)
newBall.CreateFixture(ballFixture);

然后,将小球的x轴方向的线速度设置为15,使小球在创建后可以横向飞过画布:

  var xVelocity = 15;
  var yVelocity = 0;
  newBall.SetLinearVelocity(new b2Vec2(xVelocity,yVelocity))
  balls.push(newBall);
}

最后,需要在drawScreen()函数中渲染小球。除了将小球的颜色设为红色,其他的代码在本质上与示例CH5EX22是一样的。

for (i =0;i <balls.length;i++) {
  var position = balls[i].GetPosition();
  var fixtureList = balls[i].GetFixtureList();
  var shape = fixtureList.GetShape();
  context.fillStyle = "#FF0000";
  context.beginPath();
  context.arc(position.x * scaleFactor , position.y * scaleFactor ,
        shape.GetRadius()
  *scaleFactor ,0,Math.PI*2,true);
  context.closePath();
  context.fill();
}

以上就是对CH5EX23.html叠箱子示例做的所有改造工作。现在说得到了一个互动的示例,用户可以发射小球打翻箱子。读者可以在浏览器中打开本书代码包中的CH5EX24.html查看示例。以下是例5-21的完整代码。

例5-21 Box2dWeb打箱子

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CH5EX24: Box2dWeb Box Battle</title>
<script src="modernizr.js"></script>
<script type="text/javascript" src="Box2dWeb-2.1.a.3.js"></script>
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded() {
   canvasApp();
}
function canvasSupport () {
   return Modernizr.canvas;
}
function canvasApp() {
 if (!canvasSupport()) {
      return;
   }
 function drawScreen () {
    world.Step(1 / 60, 10, 10);
    world.DrawDebugData();
    world.ClearForces();
    context.strokeStyle = '#000000';
    context.fillStyle = '#EEEEEE';
    context.fillRect(0, 0, theCanvas.width, theCanvas.height);
    //Box
    context.fillStyle = '#000000';
    context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
   for (i =0;i <boxes.length;i++) {
      var position = boxes[i].GetPosition();
      var fixtureList = boxes[i].GetFixtureList();
      var shape = fixtureList.GetShape();
      var userData = boxes[i].GetUserData();
      context.save();
      context.setTransform(1,0,0,1,0,0);
      context.translate(position.x * scaleFactor,position.y *
            scaleFactor);
      context.rotate(boxes[i].GetAngle());
      context.fillRect(0-(userData.width*scaleFactor/2) ,
         0-(userData.height*scaleFactor/2), userData.width * scaleFactor,
            userData.height
       * scaleFactor);
     context.restore();
  }
  for (i =0;i <balls.length;i++) {
    var position = balls[i].GetPosition();
    var fixtureList = balls[i].GetFixtureList();
    var shape = fixtureList.GetShape();
    context.fillStyle = "#FF0000";
    context.beginPath();
    context.arc(position.x * scaleFactor , position.y * scaleFactor ,
          shape.GetRadius()
       *scaleFactor ,0,Math.PI*2,true);
    context.closePath();
    context.fill();
  }
 }
 function createBall(event) {
   var x;
   var y;
   if (event.pageX || event.pageY) {
      x = event.pageX;
      y = event.pageY;
   }
   else {
      x = e.clientX + document.body.scrollLeft +
     document.documentElement.scrollLeft;
      y = e.clientY + document.body.scrollTop +
     document.documentElement.scrollTop;
   }
   x -= theCanvas.offsetLeft;
   y -= theCanvas.offsetTop;
   mouseX=x;
   mouseY=y;
   var ballDef = new b2BodyDef;
   ballDef.type = b2Body.b2_dynamicBody;
   var ypos = mouseY/scaleFactor;
   var xpos = mouseX/scaleFactor;
   var size = 7/scaleFactor;
   ballDef.position.Set(xpos, ypos);
   var ballFixture = new b2FixtureDef;
   ballFixture.density = 30.0;
   ballFixture.friction = 0.6;
   ballFixture.restitution = .2;
   ballFixture.shape = new b2CircleShape(size);
   var newBall = world.CreateBody(ballDef)
   newBall.CreateFixture(ballFixture);
   var xVelocity = 15;
   var yVelocity = 0;
   newBall.SetLinearVelocity(new b2Vec2(xVelocity,yVelocity))
   balls.push(newBall);
 }
 var theCanvas = document.getElementById('canvasOne');
 var context = theCanvas.getContext('2d');
 var theCanvasTwo = document.getElementById('canvasTwo');
 var context2 = theCanvasTwo.getContext('2d');
 theCanvas.addEventListener("mouseup",createBall, false);
 var scaleFactor = 30;
 var   b2Vec2 = Box2D.Common.Math.b2Vec2
     , b2BodyDef = Box2D.Dynamics.b2BodyDef
     , b2Body = Box2D.Dynamics.b2Body
     , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
     , b2World = Box2D.Dynamics.b2World
     , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
     , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
     , b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
 var world = new b2World(new b2Vec2(0,20), true);
 var numBoxes = 8;
 var boxes = new Array();
 var balls = new Array();
 var boxHeight = 25;
 var boxWidth = 25;
 var startX = (theCanvas.width-100);
 var startY = (theCanvas.height-boxHeight)-100
 for (var i=0; i < numBoxes; i++) {
   var boxDef = new b2BodyDef;
   boxDef.type = b2Body.b2_dynamicBody;
   var ypos = (startY-(i*boxHeight))/scaleFactor;
   var xpos = (startX)/scaleFactor;
   boxDef.position.Set(xpos, ypos);
   var newBox = world.CreateBody(boxDef)
   var boxFixture = new b2FixtureDef;
   boxFixture.density = 20.0;
   boxFixture.friction = .5;
   boxFixture.restitution = .1;
   boxFixture.shape = new b2PolygonShape;
   boxFixture.shape.SetAsBox((boxWidth/scaleFactor)/2,
       (boxHeight/scaleFactor)/2);
   newBox.CreateFixture(boxFixture);
   newBox.SetUserData({width:boxWidth/scaleFactor,
       height:boxHeight/scaleFactor})
   boxes.push(newBox);
 }
 var wallDefs = new Array(
     {x:theCanvas.width,y:0,w:theCanvas.width ,h:1},//top
     {x:theCanvas.width,y:theCanvas.height,w:theCanvas.width ,h:1},//bottom
     {x:0,y:theCanvas.height,w:1 ,h:theCanvas.height}, //left
     {x:theCanvas.width,y:theCanvas.height,w:1 ,h:theCanvas.height} ); //right
 var walls = new Array();
 for (var i = 0; i <wallDefs.length; i++) {
   var wallDef = new b2BodyDef;
   wallDef.type = b2Body.b2_staticBody;
   wallDef.position.Set(wallDefs[i].x/scaleFactor, wallDefs[i].y/scaleFactor);
   var newWall = world.CreateBody(wallDef)
   var wallFixture = new b2FixtureDef;
   wallFixture.density = 10.0;
   wallFixture.friction = 0.5;
   wallFixture.restitution = .5;
   wallFixture.shape = new b2PolygonShape;
   wallFixture.shape.SetAsBox(wallDefs[i].w/scaleFactor,
        wallDefs[i].h/scaleFactor);
   newWall.CreateFixture(wallFixture);
   walls.push(newWall);
 }
  var debugDraw = new b2DebugDraw();
 debugDraw.SetSprite (context2);
 debugDraw.SetDrawScale(scaleFactor); //define scale
 debugDraw.SetFillAlpha(0.3); //define transparency
 debugDraw.SetLineThickness(1.0);
 debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
 world.SetDebugDraw(debugDraw);
 function gameLoop() {
     window.setTimeout(gameLoop, 20);
     drawScreen()
   }
 gameLoop();
}
</script>
</head>
<body>
<canvas id="canvasOne" width="450" height="350" style="position: absolute;
   top: 0px; left: 0px;">
 Your browser does not support the HTML 5 Canvas.
</canvas>
<canvas id="canvasTwo" width="450" height="350" style="position: absolute;
   top: 0px; left: 451px;">
 Your browser does not support the HTML 5 Canvas.
</canvas>
</body>
</html>