用刚体isSensor属性创建感应区域
转自:http://www.ladeng6666.com/blog/2012/10/28/create-sensor-body-using-issensor/
Box2D是一个强大的2D物理引擎,可以帮我们完美实现2D物理碰撞。前面学习了各种刚体和关节对象,以及它们的检测碰撞,充分证明了Box2D是一个强大而完美的2D物理引擎。
默认情况下,碰撞发生后,Box2D会按照动量守恒定律,自动模拟物理碰撞的反弹或变向运动。但是有时候,根据碰撞后处理方式的不同,碰撞后的动量守恒运动可能并不是我们想要的。比如,当碰撞后改变刚体重力方向,这时候被碰撞的刚体更像是一个感应区域。
如下面的示例,点击舞台空白处,创建矩形刚体,当矩形刚体与大圆发生碰撞后,会变更重力方向,变更后的重力始终指向小圆。
是不是很酷?有点像太空版的愤怒的小鸟的效果吧!哇咔咔!
效果实现的关键部分是,设置刚体的isSensor属性,决定刚体是否参与物理模拟。isSensor是一个boolean值,它的作用是:
- 当isSensor为false时(这也是默认值),在发生碰撞后,由Box2D模拟物理碰撞后的反弹或变向运动。
- 当isSensor是true时,刚体只进行碰撞检测,而不模拟碰撞后的物理运动。此时,我们就可以自定义刚体处理方式了,如示例中的绕小圆运动。
完整的代码和注释如下:
文档类:SensorTest.as
|
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
|
package
{
importBox2D.Collision.Shapes.b2CircleShape;
importBox2D.Common.Math.b2Vec2;
importBox2D.Dynamics.b2Body;
importBox2D.Dynamics.b2BodyDef;
importBox2D.Dynamics.b2FilterData;
importBox2D.Dynamics.b2FixtureDef;
importBox2D.Dynamics.b2World;
importBox2D.Dynamics.Contacts.b2Contact;
importflash.display.Sprite;
importflash.events.Event;
importflash.events.MouseEvent;
/**
* ...
* @author ladeng6666
*/
publicclassSensorTestextendsSprite
{
privatevarworld:b2World;
privatevarsensorBody:b2Body;
publicfunctionSensorTest()
{
//创建Box2D世界
world=LDEasyBox2D.createWorld();
addChild(LDEasyBox2D.createDebug(world));
LDEasyBox2D.stage=stage;
//创建包裹的舞台四周的墙体
LDEasyBox2D.createWrapWall(world,this);
//自定义Box2D碰撞事件侦听器
world.SetContactListener(newMyContactListener());
//创内部的小圆,它不是sensor,可以和刚体模拟物理碰撞
LDEasyBox2D.createCircle(world,275,200,50,true);
//创建sensor大圆形刚体,因为LDEasyBox2D中没有设置isSensor刚体,所以我们从零开始创建刚体。还记得怎么创建吗?
createSensor();
//添加事件侦听器
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);
addEventListener(Event.ENTER_FRAME,loop);
}
//鼠标按下后添加矩形刚体
privatefunctionmouseEventHandler(e:MouseEvent):void
{
//用一个Object对象作为刚体的useData,目的就是给刚体添加一个changeGravity属性
//当矩形刚体与sensor碰撞后,改变它的重力
varbody:b2Body=LDEasyBox2D.createBox(world,mouseX,mouseY,20,20,false,newObject());
body.GetUserData().changeGravity=false;
}
privatefunctioncreateSensor():void{
//创建刚体需求
varbodyRequest:b2BodyDef=newb2BodyDef();
bodyRequest.type=b2Body.b2_staticBody;
bodyRequest.position.Set(275/30,200/30);
//创建刚体形状
varcircleShape:b2CircleShape=newb2CircleShape();
circleShape.SetRadius(170/30);
//创建刚体fixuture,并添加形状
varfixtureRequest:b2FixtureDef=newb2FixtureDef();
//******************************************
//这里是本章的重点
fixtureRequest.isSensor=true;
//******************************************
fixtureRequest.density=3;
fixtureRequest.friction=0.3;
fixtureRequest.restitution=0.3;
fixtureRequest.shape=circleShape;
sensorBody=world.CreateBody(bodyRequest);
sensorBody.CreateFixture(fixtureRequest);
//这里的beginContactHandler是我在b2Body中自定义的一个函数
//具体请参考我的教程:http://www.ladeng6666.com/blog/index.php/2012/09/16/custom-box2d-contact-handler/
sensorBody.beginContactHanlder=contactEventHandler;
}
privatefunctioncontactEventHandler(self:b2Body,contactedBody:b2Body):void
{
//当碰撞发生后,表示矩形刚体的changeGravity为true,这样在loop函数中可以实时更新它的重力,始终指向小圆
contactedBody.GetUserData().changeGravity=true;
}
privatefunctionloop(e:Event):void
{
LDEasyBox2D.updateWorld(world);
varbody:b2Body;
for(body=world.GetBodyList();body;body=body.GetNext()){
if(body.GetUserData()!=null){
///如果跟刚体的GetUserData().changeGravity属性为true,则实时更新它的重力方向
///始终指向小的圆形刚体
if(body.GetUserData().changeGravity){
//下面是一个简单的向量计算
//1.获得矩形刚体与sensor刚体坐标向量的差
varforce:b2Vec2=sensorBody.GetPosition().Copy();
force.Subtract(body.GetPosition());
//2.单位化该向量,只取得它的方向即可
force.Normalize();
//3.改变该向量的长度,生成新的重力
force.Multiply(10);
//重新设置刚体的重力
body.m_customGravity=force;
//为了让刚体慢慢坠落到小的圆形刚体上,用Multiply(0.99)逐渐缩小它的速度
varvelocity:b2Vec2=body.GetLinearVelocity();
velocity.Multiply(0.99);
}
}
}
}
}
}
|
自定义的碰撞事件侦听类MyContactListener.as
|
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
|
package
{
importBox2D.Dynamics.b2Body;
importBox2D.Dynamics.b2ContactListener;
importBox2D.Dynamics.Contacts.b2Contact;
/**
* ...
* @author ladeng6666
*/
publicclassMyContactListenerextendsb2ContactListener
{
//具体详见我的教程http://www.ladeng6666.com/blog/index.php/2012/09/16/custom-box2d-contact-handler/
publicfunctionMyContactListener()
{
}
override publicfunctionBeginContact(contact:b2Contact):void
{
varbodyA:b2Body=contact.GetFixtureA().GetBody();
varbodyB:b2Body=contact.GetFixtureB().GetBody();
if(bodyA.beginContactHanlder!=null)bodyA.beginContactWith(bodyB);
if(bodyB.beginContactHanlder!=null)bodyB.beginContactWith(bodyA);
}
override publicfunctionEndContact(contact:b2Contact):void
{
varbodyA:b2Body=contact.GetFixtureA().GetBody();
varbodyB:b2Body=contact.GetFixtureB().GetBody();
if(bodyA.endContactHanlder!=null)bodyA.endContactWith(bodyB);
if(bodyB.endContactHanlder!=null)bodyB.endContactWith(bodyA);
}
}
}
|
在SensorTest类中
第60~63行:将大圆的isSensor属性设置为false,则它不会进行物理碰撞模拟,只侦听碰撞事件。
第73行:自定义SensorBody的碰撞事件处理函数,我在自定义Box2D刚体碰撞处理函数中讲过这个用法。
第76~80行:当碰撞发生后,标示矩形刚体的changeGravity为true,这样在loop函数中可以实时更新它的重力,始终指向小的圆形刚体
第85~103行:实时更新刚体的自定义重力,这里用到了我在Box2D自定义重力中讲过的知识点。其中还用到了很多向量的只是,我在向量基础里曾经讲过,其实并不难,看看基础就能明白。
在MyContactListener类中
我创建了一个自定义的MyContactListener(b2ContactListener的子类),来侦听并处理碰撞事件。具体用法详见我的教程自定义Box2D刚体碰撞处理函数
posted on 2014-03-23 16:56 shengchang 阅读(198) 评论(0) 收藏 举报
浙公网安备 33010602011771号