文章目錄
  1. 1. 然后是更多的Box2D元素?
    1. 1.1. 创建矩形物体
    2. 1.2. 创建圆形物体
    3. 1.3. 创建多边形物体
    4. 1.4. 创建多种形状的复杂物体
    5. 1.5. 连接物体的接合点
    6. 1.6. 创建具有自定义属性的物体
  2. 2. 很有用的追踪碰撞与损坏!
    1. 2.1. 接触监听器
    2. 2.2. 绘制角色
  3. 3. 小结

然后是更多的Box2D元素?

创建矩形物体

和创建地面大同小异,修改坐标长宽即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createRectangularBody(){
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody; //动态物体
bodyDef.position.x = 40/scale; //中心x坐标
bodyDef.position.y = 100/scale; //中心y坐标
//特性
var fixtureDef = new b2FixtureDef;
fixtureDef.density = 1.0; //密度
fixtureDef.friction = 0.5; //摩擦
fixtureDef.restitution = 0.3; //弹性
fixtureDef.shape = new b2PolygonShape; //图形模式:矩形
fixtureDef.shape.SetAsBox(30/scale, 50/scale); //30像素宽,50像素高
var body = world.CreateBody(bodyDef);
var fixture = body.CreateFixture(fixtureDef);
}

创建圆形物体

在特性中形状修改为圆,赋予半径即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function createCircularBody(){
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = 130/scale;
bodyDef.position.y = 130/scale;
var fixtureDef = new b2FixtureDef;
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.7;
fixtureDef.shape = new b2CircleShape(30/scale); //图形:圆
var body = world.CreateBody(bodyDef);
var fixture = body.CreateFixture(fixtureDef);
}

创建多边形物体

利用向量数组来提供多边形顶点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function createSimplePolygonBody(){
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = 230/scale;
bodyDef.position.y = 50/scale;
var fixtureDef = new b2FixtureDef;
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.2;
fixtureDef.shape = new b2PolygonShape(); //多边形模式
//按顺时针方向创建一个b2Vec2顶点数组
var points = [
new b2Vec2(0, 0),
new b2Vec2(40/scale, 50/scale),
new b2Vec2(50/scale, 100/scale),
new b2Vec2(-50/scale, 100/scale),
new b2Vec2(-40/scale, 50/scale),
];
// 调用SetAsArray()来使用顶点数组定义形状
fixtureDef.shape.SetAsArray(points, points.length);
var body = world.CreateBody(bodyDef);
var fixture = body.CreateFixture(fixtureDef);
}

创建多种形状的复杂物体

注意当由多个物体拼接时,将添加入世界的物体直接赋予多个特性即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function createComplexBody(){
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = 350/scale;
bodyDef.position.y = 50/scale;
var body = world.CreateBody(bodyDef);
// 创建第一个载具并为物体添加圆形状
var fixtureDef = new b2FixtureDef;
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.7;
fixtureDef.shape = new b2CircleShape(40/scale);
body.CreateFixture(fixtureDef);
// 创建第二个载具并为物体添加多边形形状
fixtureDef.shape = new b2PolygonShape();
var points = [
new b2Vec2(0, 0),
new b2Vec2(40/scale, 50/scale),
new b2Vec2(50/scale, 100/scale),
new b2Vec2(-50/scale, 100/scale),
new b2Vec2(-40/scale, 50/scale),
];
fixtureDef.shape.SetAsArray(points, points.length);
body.CreateFixture(fixtureDef);
}

连接物体的接合点

类似于风车的转轴,需要指定两个物体和结合点的坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function createRevoluteJoint(){
//定义第一个物体
var bodyDef1 = new b2BodyDef;
bodyDef1.type = b2Body.b2_dynamicBody;
bodyDef1.position.x = 480/scale;
bodyDef1.position.y = 50/scale;
var body1 = world.CreateBody(bodyDef1);
// 创建第一个载具并为物体添加圆形状
var fixtureDef1 = new b2FixtureDef;
fixtureDef1.density = 1.0;
fixtureDef1.friction = 0.5;
fixtureDef1.restitution = 0.5;
fixtureDef1.shape = new b2PolygonShape();
fixtureDef1.shape.SetAsBox(50/scale, 10/scale);
body1.CreateFixture(fixtureDef1);
// 定义第二个物体
var bodyDef2 = new b2BodyDef;
bodyDef2.type = b2Body.b2_dynamicBody;
bodyDef2.position.x = 480/scale;
bodyDef2.position.y = 50/scale;
var body2 = world.CreateBody(bodyDef2);
// 创建第二个载具并为物体添加多边形形状
var fixtureDef2 = new b2FixtureDef;
fixtureDef2.shape = new b2PolygonShape();
var points = [
new b2Vec2(0, 0),
new b2Vec2(40/scale, 50/scale),
new b2Vec2(50/scale, 100/scale),
new b2Vec2(-50/scale, 100/scale),
new b2Vec2(-40/scale, 50/scale),
];
fixtureDef2.shape.SetAsArray(points, points.length);
body2.CreateFixture(fixtureDef2);
// 创建接合点连接body1和body2
var jointDef = new b2RevoluteJointDef;
var jointCenter = new b2Vec2(470/scale, 50/scale);
jointDef.Initialize(body1, body2, jointCenter);
world.CreateJoint(jointDef);
}

创建具有自定义属性的物体

注意第9行代码,我们利用特有的SetUserData方法可以给物体赋予自定义属性,通过GetUserData获取它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var specialBody;
function createSpecialBody(){
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = 450/scale;
bodyDef.position.y = 0/scale;
specialBody = world.CreateBody(bodyDef);
specialBody.SetUserData({ name:"special",life:250 })
// 创建第一个载具并为物体添加圆形状
var fixtureDef = new b2FixtureDef;
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.5;
fixtureDef.shape = new b2CircleShape(30/scale);
var fixture = specialBody.CreateFixture(fixtureDef);
}

很有用的追踪碰撞与损坏!

接触监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function listenForContact(){
var listener = new Box2D.Dynamics.b2ContactListener;
listener.PostSolve = function(contact, impulse){
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
// 如果接触的两个物体都具有生命值,则减少其生命值
if (body1 == specialBody || body2 == specialBody){
var impulseAlongNormal = impulse.normalImpulses[0];
specialBody.GetUserData().life -= impulseAlongNormal;
console.log("The special body was in a collision with impulse", impulseAlongNormal,
"and its life has now become ", ~~specialBody.GetUserData().life);
}
};
world.SetContactListener(listener);
}

绘制角色

这里我们使用canvas原生绘图,获取暴露的自定义物体的坐标和偏移角度,然后通过“覆盖”的方法将自定义图形通过生命值来绘制特有的表情。
有一个调试技巧,就是在实际的canvas旁边放置一个testCanvas,将world世界里的图像绘制到testCanvas里。然后通过获取到每个图形信息,把对应的图片或者新绘制的图形放置到真canvas里,也就是要实际使用的canvas中,可以方便地实现调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function drawSpecialBody(){
// 获取body的位置和角度
var position = specialBody.GetPosition();
var angle = specialBody.GetAngle();
// 移动并旋转物体
context.translate(position.x*scale, position.y*scale);
context.rotate(angle);
// 绘制实心的圆面
context.fillStyle = "rgb(200,150,250)";
context.beginPath();
context.arc(0, 0, 30, 0, 2*Math.PI, false);
context.fill();
// 绘制两个矩形的眼睛
context.fillStyle = "rgb(255,255,255)";
context.fillRect(-15, -15, 10, 5);
context.fillRect(5, -15, 10, 5);
// 绘制向上或向下的圆弧,根据生命值决定是否微笑
context.strokeStyle = "rgb(255,255,255)";
context.beginPath();
if (specialBody.GetUserData().life > 100) {
context.arc(0, 0, 10, Math.PI, 2*Math.PI, true);
} else {
context.arc(0, 10, 10, Math.PI, 2*Math.PI, false);
}
context.stroke();
// 移动并旋转坐标轴至最初的位置和角度
context.rotate(-angle);
context.translate(-position.x*scale, -position.y*scale);
}

小结

XANA工作室以前做游戏的时候碰撞我使用的是向量模型,来代替简单的x,y的四则运算,通过一系列定义的向量方法造的轮子来做碰撞的检测。当然缺点很明显,第一个就是碰撞的处理不够完善,物体的密度、弹性、摩擦均没有考虑在内。然而Box2D提供了相当成熟的API,虽然它的学习成本不低,理论相当复杂,总之在2D的物体计算方面,Box2D库是相当不错的。

文章目錄
  1. 1. 然后是更多的Box2D元素?
    1. 1.1. 创建矩形物体
    2. 1.2. 创建圆形物体
    3. 1.3. 创建多边形物体
    4. 1.4. 创建多种形状的复杂物体
    5. 1.5. 连接物体的接合点
    6. 1.6. 创建具有自定义属性的物体
  2. 2. 很有用的追踪碰撞与损坏!
    1. 2.1. 接触监听器
    2. 2.2. 绘制角色
  3. 3. 小结