FilterData让Box2D碰撞分类进行
转自:http://www.ladeng6666.com/blog/2012/11/02/filterdata-to-separate-the-box2d-collision/
上一节课,我们学会了用b2Body的isSensor属性制作一个Box2D感应区域。当刚体的isSensor属性为true是,不会参与物理碰撞模拟,实际上,我们可以用Box2D的另一个特性实现相同的效果,它就是今天我们要学的FilterData类。
Filter是"过滤"的意思,所以FilterData可以简单的理解成用来过滤碰撞刚体(比如接下来哦我么要实现的矩形只与矩形刚体碰撞,圆形只与圆形刚体碰撞)。FilterData有3个属性:groupIndex、categoryBits和maskBits,他们的用法如下:
- groupIndex:表示刚体的分组信息。相同groupIndex属性的刚体属性一个组,groupIndex为正数时,刚体只和同组的刚体发生碰撞。groupIndex为负数时,刚体只和同组之外的刚体进行碰撞。
- categoryBits:表示刚体的分组信息,但不决定要碰撞的分组对象。另外,值得注意的,这个值必须是2的N次方。当然设置成其他值,程序不会报错,但是实际的碰撞分类效果,可能会出现意想不到的差错。
- maskBits:表示刚体要碰撞的那个刚体分组对象。这个值通常是另外一个FilterData对象的categoryBits属性,表示只与该类刚体发生碰撞。如果要对多组刚体进行碰撞,可以设置maskBits为多个categoryBits的加合。如要和categoryBits分别为2和4的刚体组都进行碰撞,可以设置maskBits属性为6。
举个例子,比如,圆形刚体的categoryBits和maskBits分别为2和2,矩形刚体的categoryBits和maskBits分别为4和4。那么圆形与矩形刚体之间不会发生碰撞,只有相同形状刚体之间才会发生碰撞。
FilterData对象可以通过赋值给b2FixtureDef对象filter属性来设置,非常简单吧!
|
1
2
|
varfixtureRequest:b2FixtureDef=newb2FixtureDef();
fixtureRequest.filter=filter;
|
在下面的示例中,我没有在文档类中设置b2Fixture.filter属性,而是直接在LDEasyBox.createBod()中添加了一个filter的可选参数,变更后的createBox()方法如下,重点部分已用黄色标示。
|
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
|
publicstaticfunctioncreateBox(
world:b2World,
posX:Number,
posY:Number,
boxWidth:Number,
boxHeight:Number,
isStatic:Boolean=false,
userData:*=null,
isSensor:Boolean=false,
filter:b2FilterData=null
):b2Body{
//1.创建刚体需求b2BodyDef
varbodyRequest:b2BodyDef=newb2BodyDef();
bodyRequest.type=isStatic?b2Body.b2_staticBody:b2Body.b2_dynamicBody;
bodyRequest.position.Set(posX/pixelPerMeter,posY/pixelPerMeter);//记得米和像素的转换关系
//Ladeng6666是Flash元件库中的一个图片
if(userData!=null){
bodyRequest.userData=userData;
//设定上衣的尺寸
bodyRequest.userData.width=boxWidth;
bodyRequest.userData.height=boxHeight;
//需手动将上衣添加到舞台上
//addChild(bodyRequest.userData);
}
//2.创建形状
varshapeBox:b2PolygonShape=newb2PolygonShape();
shapeBox.SetAsBox(boxWidth/pixelPerMeter/2,boxHeight/pixelPerMeter/2);
//2.Box2D世界工厂更具需求创建createBody()生产刚体
varbox:b2Body=world.CreateBody(bodyRequest);
//3.创建敢提形状需求b2ShapeDef的子类
varfixtureRequest:b2FixtureDef=newb2FixtureDef();
fixtureRequest.density=3;
fixtureRequest.friction=0.3;
fixtureRequest.restitution=0.2;
fixtureRequest.shape=shapeBox;
fixtureRequest.isSensor=isSensor;
if(filter!=null){
fixtureRequest.filter=filter;
}
//4.b2Body刚体工厂根据需求createShape生产形状
box.CreateFixture(fixtureRequest);
returnbox;
}
|
同样createCircle()方法也做出了相同的修改。
说了这么多,让我们看看示例吧!
完整的代码和注释如下:
|
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
|
package
{
importBox2D.Dynamics.b2Body;
importBox2D.Dynamics.b2FilterData;
importBox2D.Dynamics.b2World;
importflash.display.Sprite;
importflash.events.Event;
importflash.events.MouseEvent;
/**
* ...
* @author ladeng6666
*/
publicclassFilterDataTestextendsSprite
{
//创建Box2D世界
privatevarworld:b2World;
privatevarpressedBody:b2Body;
//创建更重Filter数据
privatevarboxFilter:b2FilterData;
privatevarcircleFilter:b2FilterData;
privatevarwallFilter:b2FilterData;
publicfunctionFilterDataTest()
{
//实例化Box2D世界
world=LDEasyBox2D.createWorld();
addChild(LDEasyBox2D.createDebug(world));
LDEasyBox2D.stage=stage;
//实例化刚体Filter对象
createFilter();
//因为要指定包裹墙体的FilterData,所有我修改了createWrapWall方法,把它放到这里了。
createWrapWall();
//创建经过FilterData分类的刚体
createBodies();
//添加事件侦听器
addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);
addEventListener(Event.ENTER_FRAME,loop);
}
privatefunctioncreateFilter():void
{
//创建Box刚体FilterData分类数据,记得只能是2的N次方
boxFilter=newb2FilterData();
//设置刚体分类为2
boxFilter.categoryBits=2
//设置刚体只与分类为10(即类别2矩形刚体+类别8包裹墙体)的刚体进行碰撞
boxFilter.maskBits=10;
//创建Box刚体FilterData分类数据,记得只能是2的N次方
circleFilter=newb2FilterData();
//设置刚体分类为4
circleFilter.categoryBits=4;
//设置刚体只与分类为12(即类别4圆形刚体+类别8包裹墙体)的刚体进行碰撞
circleFilter.maskBits=12;
//设置包裹墙体的分类为8
wallFilter=newb2FilterData();
wallFilter.categoryBits=8;
}
//更新Box2D引擎模拟
privatefunctionloop(e:Event):void
{
LDEasyBox2D.updateWorld(world);
}
privatefunctioncreateBodies():void
{
for(vari:int=0;i<5;i++){
//随机创建5个矩形刚体,并设置它的碰撞分类为boxFilter,即只与矩形刚体和墙体碰撞
LDEasyBox2D.createBox(world,Math.random()*400+50,30,30,30,false,null,false,boxFilter);
//随机创建5个矩形刚体,并设置它的碰撞分类为circleFilter,即只与圆形刚体和墙体碰撞
LDEasyBox2D.createCircle(world,Math.random()*400+50,15,30,false,null,false,circleFilter);
}
//在舞台中间添加一个静态的长条刚体,设置它的碰撞分类是boxFilter,
//这样矩形刚体可以落在这个长条上,而圆形刚体不行
LDEasyBox2D.createBox(world,275,200,350,20,true,null,false,boxFilter);
}
privatefunctioncreateWrapWall():void{
varw:Number=550;
varh:Number=400;
varwallThick:Number=20;//in pixels
//在创建墙体时,设置它的碰撞分类,让它可以同时与矩形和圆形刚体进行碰撞
LDEasyBox2D.createBox(world,w/2,0,w,wallThick,true,null,false,wallFilter);
LDEasyBox2D.createBox(world,w/2,h,w,wallThick,true,null,false,wallFilter);
LDEasyBox2D.createBox(world,0,h/2,wallThick,h,true,null,false,wallFilter);
LDEasyBox2D.createBox(world,w,h/2,wallThick,h,true,null,false,wallFilter);
}
//鼠标拖动刚体
privatefunctionmouseEventHandler(e:MouseEvent):void
{
if(e.type==MouseEvent.MOUSE_DOWN){
pressedBody=LDEasyBox2D.getBodyAtMouse(world);
if(pressedBody!=null){
LDEasyBox2D.startDragBody(world,pressedBody);
}
}elseif(e.type==MouseEvent.MOUSE_UP){
LDEasyBox2D.stopDragBody(world);
}
}
}
}
|
posted on 2014-03-23 17:10 shengchang 阅读(524) 评论(0) 收藏 举报
浙公网安备 33010602011771号