文章目录
  1. 1. 添加刚体
    1. 1.1. 创建刚体
    2. 1.2. 添加刚体
    3. 1.3. 绘制刚体
    4. 1.4. 完整代码
    5. 1.5. 返回总目录

本节我们主要讲述在世界中创建形状并添加刚体的过程。

添加刚体


创建刚体

前面我们说过,box2d中创建刚体、关节的过程类似于堆积木,由形状构成刚体,由刚体构成关节,稍微不同的地方是,这里的形状可以多次使用,其过程:
形状 -> 刚体 -> 关节

这里我们首先创建各种形状,然后创建对应的刚体。

  • 创建圆形
1
2
3
4
5
6
7
8
9
10
11
12
function createBall(world, x, y, r) {
// 创建圆形定义
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 || 0,y || 0); // 设置位置
return world.CreateBody(ballBd); // 创建并返回刚体
}
  • 创建矩形
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建矩形刚体
function createBox(world, x, y, width, height, userData) {
var boxSd = new b2BoxDef(); // 创建一个形状Shape,然后设置有关Shape的属性
boxSd.extents.Set(width || 1200, height || 5); // 设置矩形高、宽
boxSd.density = 1.0; // 设置矩形的密度
boxSd.userData = userData; // 传入图片数据
boxSd.restitution = .3; //设置矩形的弹性
boxSd.friction = 1; //设置矩形的摩擦因子,可以设置为0-1之间任意一个数,0表示光滑,1表示强摩擦

var boxBd = new b2BodyDef(); // 创建刚体定义
boxBd.AddShape(boxSd); // 添加形状
boxBd.position.Set(x || 10, y || 10); // 设置位置
return world.CreateBody(boxBd) // 创建并返回刚体
}

添加刚体

利用上面创建刚体的函数,我们可以往世界中添加刚体:

1
2
3
4
var ball1 = createBall(world, 100, 20, 20);
var ball2 = createBall(world, 300, 60, 10);
var box1 = createBox(world, 100, 200, 25, 30, true);
var box2 = createBox(world, 200, 50, 20, 20);

绘制刚体

我们可以通过添加绘制刚体的函数,在绘制世界时调用:

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
// 从draw_world.js里面引用的绘画功能
function drawShape(shape, context) {
context.strokeStyle = '#003300';
context.beginPath();
switch (shape.m_type) {
// 绘制圆
case b2Shape.e_circleShape:
var circle = shape;
var pos = circle.m_position;
var r = circle.m_radius;
var segments = 16.0;
var theta = 0.0;
var dtheta = 2.0 * Math.PI / segments;
// 画圆圈
context.moveTo(pos.x + r, pos.y);
for (var i = 0; i < segments; i++) {
var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta));
var v = b2Math.AddVV(pos, d);
context.lineTo(v.x, v.y);
theta += dtheta;
}
context.lineTo(pos.x + r, pos.y);

// 画半径
context.moveTo(pos.x, pos.y);
var ax = circle.m_R.col1;
var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y);
context.lineTo(pos2.x, pos2.y);
break;
// 绘制多边形
case b2Shape.e_polyShape:
var poly = shape;
var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));
context.moveTo(tV.x, tV.y);
for (var i = 0; i < poly.m_vertexCount; i++) {
var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
context.lineTo(v.x, v.y);
}
context.lineTo(tV.x, tV.y);
break;
}
context.stroke();
}

我们也可以在其中一个刚体里将图片与刚体结合:

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 drawWorld(world, context) {
for (var j = world.m_jointList; j; j = j.m_next) {
// 绘制关节
// drawJoint(j, context);
}
for (var b = world.m_bodyList; b != null; b = b.m_next) {
for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {
if (s.GetUserData() != undefined) {
// 使用数据包括图片
var img = s.GetUserData();

// 图片的长和宽
var x = s.GetPosition().x;
var y = s.GetPosition().y;
var topleftX = - img.clientWidth / 2;
var topleftY = - img.clientHeight / 2;

context.save();
context.translate(x, y);
context.rotate(s.GetBody().GetRotation());
context.drawImage(img, topleftX, topleftY);
context.restore();
}
drawShape(s, context);
}
}
}

完整代码

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
var canvas;
var ctx;
var canvasWidth;
var canvasHeight;

var world;

// 我们将创建世界封装至createWorld函数内
function createWorld() {
// 世界的大小
var worldAABB = new b2AABB();
worldAABB.minVertex.Set(-4000, -4000);
worldAABB.maxVertex.Set(4000, 4000);

//定义重力
var gravity = new b2Vec2(0, 300);

// 是否休眠
var doSleep = false;

// 最终创建世界
var world = new b2World(worldAABB, gravity, doSleep);

return world;
}

//绘画功能
function drawWorld(world, context) {
for (var j = world.m_jointList; j; j = j.m_next) {
// 绘制关节
// drawJoint(j, context);
}
for (var b = world.m_bodyList; b != null; b = b.m_next) {
for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {
if (s.GetUserData() != undefined) {
// 使用数据包括图片
var img = s.GetUserData();

// 图片的长和宽
var x = s.GetPosition().x;
var y = s.GetPosition().y;
var topleftX = -img.clientWidth / 2;
var topleftY = -img.clientHeight / 2;

context.save();
context.translate(x, y);
context.rotate(s.GetBody().GetRotation());
context.drawImage(img, topleftX, topleftY);
context.restore();
}
drawShape(s, context);
}
}
}

// 创建圆形刚体
function createBall(world, x, y, r) {
// 创建圆形定义
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 || 0, y || 0); // 设置位置
return world.CreateBody(ballBd); // 创建并返回刚体
}

// 创建矩形刚体
function createBox(world, x, y, width, height, userData) {
var boxSd = new b2BoxDef(); //创建一个形状Shape,然后设置有关Shape的属性
boxSd.extents.Set(width || 1200, height || 5); //设置矩形高、宽
boxSd.density = 1.0;
boxSd.userData = userData;
boxSd.restitution = .3; //设置矩形的弹性
boxSd.friction = 1; //设置矩形的摩擦因子,可以设置为0-1之间任意一个数,0表示光滑,1表示强摩擦

var boxBd = new b2BodyDef(); // 创建刚体定义
boxBd.AddShape(boxSd); // 添加形状
boxBd.position.Set(x || 10, y || 10); // 设置位置
return world.CreateBody(boxBd) // 创建并返回刚体
}

// 定义step函数,用于游戏的迭代运行
function step() {
// 模拟世界
world.Step(1.0 / 60, 1);
// 清除画布
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// 重新绘制
drawWorld(world, ctx);

// 再次刷新
setTimeout(step, 10);
console.log('step...');
}

// 从draw_world.js里面引用的绘画功能
function drawShape(shape, context) {
context.strokeStyle = '#003300';
context.beginPath();
switch (shape.m_type) {
// 绘制圆
case b2Shape.e_circleShape:
var circle = shape;
var pos = circle.m_position;
var r = circle.m_radius;
var segments = 16.0;
var theta = 0.0;
var dtheta = 2.0 * Math.PI / segments;
// 画圆圈
context.moveTo(pos.x + r, pos.y);
for (var i = 0; i < segments; i++) {
var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta));
var v = b2Math.AddVV(pos, d);
context.lineTo(v.x, v.y);
theta += dtheta;
}
context.lineTo(pos.x + r, pos.y);

// 画半径
context.moveTo(pos.x, pos.y);
var ax = circle.m_R.col1;
var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y);
context.lineTo(pos2.x, pos2.y);
break;
// 绘制多边形
case b2Shape.e_polyShape:
var poly = shape;
var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));
context.moveTo(tV.x, tV.y);
for (var i = 0; i < poly.m_vertexCount; i++) {
var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
context.lineTo(v.x, v.y);
}
context.lineTo(tV.x, tV.y);
break;
}
context.stroke();
}

window.onload = function() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
canvasWidth = parseInt(canvas.width);
canvasHeight = parseInt(canvas.height);
// 启动游戏
world = createWorld();
var ball1 = createBall(world, 100, 20, 20);
var ball2 = createBall(world, 300, 60, 10);
var box1 = createBox(world, 200, 50, 20, 20);
var box2 = createBox(world, 400, 80, 20, 20, document.getElementById('box'));
step();
};

此处查看项目代码(仅包含src部分)
此处查看页面效果

返回总目录

码生艰难,写文不易,给我家猪囤点猫粮了喵~

B站: 被删

查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢

如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢

作者:被删

出处:https://godbasin.github.io

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

文章目录
  1. 1. 添加刚体
    1. 1.1. 创建刚体
    2. 1.2. 添加刚体
    3. 1.3. 绘制刚体
    4. 1.4. 完整代码
    5. 1.5. 返回总目录