用马达关节创建Box2D锁链效果
转自:http://www.ladeng6666.com/blog/2012/11/25/create-box2d-linkage-or-bridge-effect-using-b2joint/
今天我们来学习Box2D锁链效果。这个效果并不难,记得我们学过的Box2D 关节——”马达关节” b2RevoluteJoint吗?锁链效果其实就是用多个b2RevolueJoint连接多个刚体,很简单吧!
简单在用多个关节连接多个刚体,难也难在这里。我们还是先来看看效果吧。在下面的效果中我创建了两个锁链,一个是小桥,另一个是连接了一个圆形刚体的锁链。鼠标可以点击并拖动下面的刚体。
看过效果之后,我想你肯定也想到了,要用for循环来创建锁链。要用for循环就要有可以重复执行的过程,仔细想想这个过程并不难。
创建当前的刚体body,指定节点的位置anchor,创建节点为anchor的关节,链接当前刚体body和前一个刚体preBody。如下图所示。图中虚线框内是fox循环要重复执行的过程。anchor1用来连接preBody和Body。相信可能有人会跟我一样,犯下面的错误,把关节点设置为body的中心点。这样旋转后,会出现图中下面的效果。因为preBody和body都是围绕anchor1旋转的嘛,想想风扇效果?!
正确的做法是像下图一样,创建当前刚体时body时,让它偏移anchor1一点,偏移多少呢?最好是刚体的一半,这样节点就移到了刚体的边缘处了。旋转之后就会像图中下面的效果一样自然了。
另外设置刚体的宽度为两个节点之间的间距,这样刚体之间会紧密相连,效果就跟上的SWF示例一样了!
完整的代码和注释如下:
|
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
|
package
{
importBox2D.Common.Math.b2Vec2;
importBox2D.Dynamics.b2Body;
importBox2D.Dynamics.b2World;
importBox2D.Dynamics.Joints.b2RevoluteJointDef;
importflash.display.Sprite;
importflash.events.Event;
importflash.events.MouseEvent;
/**
* ...
* @author ladeng6666
*/
publicclassBridgeextendsSprite
{
privatevarworld:b2World;
publicfunctionBridge()
{
//初始化,创建世界,添加事件侦听等等
init();
//创建小桥锁链
createBridge();
//创建一个可以拖动的锁链
creaetLinkage();
//随机创建几个刚体
createBodies();
}
privatefunctioninit():void
{
//初始化世界
world=LDEasyBox2D.createWorld();
addChild(LDEasyBox2D.createDebug(world));
LDEasyBox2D.stage=this;
LDEasyBox2D.createWrapWall(world,this);
//添加事件侦听
addEventListener(Event.ENTER_FRAME,loop);
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);
}
//拖动刚体
privatefunctionmouseEventHandler(e:MouseEvent):void
{
if(e.type==MouseEvent.MOUSE_DOWN){
varbody:b2Body=LDEasyBox2D.getBodyAtMouse(world);
if(body!=null){
LDEasyBox2D.startDragBody(world,body);
}
}elseif(e.type==MouseEvent.MOUSE_UP){
LDEasyBox2D.stopDragBody(world);
}
}
//更新世界
privatefunctionloop(e:Event):void
{
LDEasyBox2D.updateWorld(world);
}
privatefunctioncreateBodies():void
{
//随机创建刚体
for(vari:int=0;i<10;i++){
if(Math.random()>0.5){
LDEasyBox2D.createBox(world,Math.random()*300+100,100,Math.random()*20+10,Math.random()*20+10);
}else{
LDEasyBox2D.createCircle(world,Math.random()*300+100,100,Math.random()*10+10);
}
}
}
privatefunctioncreaetLinkage():void
{
//设置第一节刚体开始的位置
varinitx:Number=150;
varinity:Number=50;
//两个节点之间的间距
vargapBetweenAnchor:Number=30;
//定义节点
varanchor:b2Vec2=newb2Vec2();
//当前刚体
varbody:b2Body;
//前一个刚体
varpreBody:b2Body;
//设置前一个刚体是一个圆形刚体,这个刚体不在for循环范围内,
//但是要在for循环里引用,所以在这里预先定义好
preBody=LDEasyBox2D.createCircle(world,initx,inity,15);
//定义关节
varrevoluteJoint:b2RevoluteJointDef=newb2RevoluteJointDef();
for(vari:int=0;i<4;i++){
//循环创建刚体,它们的x坐标都基于节点的位置向右偏移15个像素(也就是刚体的半宽)
body=LDEasyBox2D.createBox(world,initx+i*gapBetweenAnchor+15,inity,gapBetweenAnchor,5);
//设置节点的坐标
anchor.Set((initx+i*gapBetweenAnchor)/30,inity/30);
//初始化关节
revoluteJoint.Initialize(preBody,body,anchor);
world.CreateJoint(revoluteJoint);
//设置preBody引用当前的刚体
preBody=body;
}
}
privatefunctioncreateBridge():void
{
//设置第一节刚体开始的位置
varinitx:Number=100;
varinity:Number=250;
//两个节点之间的间距
vargapBetweenAnchor:Number=50;
//定义节点
varanchor:b2Vec2=newb2Vec2();
//当前刚体
varbody:b2Body;
//前一个刚体
varpreBody:b2Body;
//在for循环之外预先定义第一个刚体,定义成GetGroundBody,固定锁链的起点
preBody=world.GetGroundBody();
//定义关节
varrevoluteJoint:b2RevoluteJointDef=newb2RevoluteJointDef();
for(vari:int=0;i<6;i++){
//循环创建刚体,它们的x坐标都基于节点的位置向右偏移15个像素(也就是刚体的半宽)
body=LDEasyBox2D.createBox(world,initx+i*gapBetweenAnchor+25,inity,gapBetweenAnchor,10);
//设置节点的坐标
anchor.Set((initx+i*gapBetweenAnchor)/30,inity/30);
//初始化关节
revoluteJoint.Initialize(preBody,body,anchor);
world.CreateJoint(revoluteJoint);
//设置preBody引用当前的刚体
preBody=body;
}
//设置最后一个节点
anchor.Set((initx+i*50)/30,inity/30);
//将最后一个节点链接到GetGroundBody,固定锁链的终点
revoluteJoint.Initialize(preBody,world.GetGroundBody(),anchor);
world.CreateJoint(revoluteJoint).GetAnchorB().x;
}
}
}
|
值得注意的是第121行和139行,将关节的起点和终点设置成了GetGroundBody()返回的刚体,用来固定住这两个位置,模拟小桥的效果。关于GetGroundBody()的用法请参考Box2D如何固定动态刚体
源文件下载地址
posted on 2014-03-23 17:27 shengchang 阅读(340) 评论(0) 收藏 举报


浙公网安备 33010602011771号