11RIA 闪客社区 - 最赞 Animate Flash 论坛

搜索
查看: 2110|回复: 0
上一主题 下一主题

[2D 物理引擎] 【9RIA—ladeng6666】—【Box2D系列教程 29】用刚体isSensor属性创建感应区域

[复制链接] TA的其它主题
发表于 2018-2-6 13:14:20 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

转载:9RIA游戏开发者社区(天地会)
作者:ladeng6666(拉登大叔)
作者博客:http://www.ladeng6666.com/blog/


【Box2D系列教程-导航帖】—拉登大叔出品(总贴)



Box2D是一个强大的2D物理引擎,可以帮我们完美实现2D物理碰撞。前面学习了各种刚体和关节对象,以及它们的检测碰撞,充分证明了Box2D是一个强大而完美的2D物理引擎。

默认情况下,碰撞发生后,Box2D会按照动量守恒定律,自动模拟物理碰撞的反弹或变向运动。但是有时候,根据碰撞后处理方式的不同,碰撞后的动量守恒运动可能并不是我们想要的。比如,当碰撞后改变刚体重力方向,这时候被碰撞的刚体更像是一个感应区域。

如下面的示例,点击舞台空白处,创建矩形刚体,当矩形刚体与大圆发生碰撞后,会变更重力方向,变更后的重力始终指向小圆。



是不是很酷?有点像太空版的愤怒的小鸟的效果吧!哇咔咔!
效果实现的关键部分是,设置刚体的isSensor属性,决定刚体是否参与物理模拟。isSensor是一个boolean值,它的作用是:
    当isSensor为false时(这也是默认值),在发生碰撞后,由Box2D模拟物理碰撞后的反弹或变向运动。
    当isSensor是true时,刚体只进行碰撞检测,而不模拟碰撞后的物理运动。此时,我们就可以自定义刚体处理方式了,如示例中的绕小圆运动。
完整的代码和注释如下:
文档类:SensorTest.as

[Actionscript3] 纯文本查看 复制代码
package  
{
        import Box2D.Collision.Shapes.b2CircleShape;
        import Box2D.Common.Math.b2Vec2;
        import Box2D.Dynamics.b2Body;
        import Box2D.Dynamics.b2BodyDef;
        import Box2D.Dynamics.b2FilterData;
        import Box2D.Dynamics.b2FixtureDef;
        import Box2D.Dynamics.b2World;
        import Box2D.Dynamics.Contacts.b2Contact;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        /**
         * ...
         * @author ladeng6666
         */
        public class SensorTest extends Sprite
        {
                private var world:b2World;
                private var sensorBody:b2Body;

                public function SensorTest() 
                {
                        //创建Box2D世界
                        world = LDEasyBox2D.createWorld();
                        addChild(LDEasyBox2D.createDebug(world));
                        LDEasyBox2D.stage = stage;
                        //创建包裹的舞台四周的墙体
                        LDEasyBox2D.createWrapWall(world, this);
                        //自定义Box2D碰撞事件侦听器
                        world.SetContactListener(new MyContactListener());
                        //创内部的小圆,它不是sensor,可以和刚体模拟物理碰撞
                        LDEasyBox2D.createCircle(world, 275, 200, 50, true);
                        //创建sensor大圆形刚体,因为LDEasyBox2D中没有设置isSensor刚体,所以我们从零开始创建刚体。还记得怎么创建吗?
                        createSensor();

                        //添加事件侦听器
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler);
                        addEventListener(Event.ENTER_FRAME, loop);
                }
                //鼠标按下后添加矩形刚体
                private function mouseEventHandler(e:MouseEvent):void 
                {
                        //用一个Object对象作为刚体的useData,目的就是给刚体添加一个changeGravity属性
                        //当矩形刚体与sensor碰撞后,改变它的重力
                        var body:b2Body = LDEasyBox2D.createBox(world, mouseX, mouseY, 20,20,false,new Object());
                        body.GetUserData().changeGravity = false;
                }
                private function createSensor():void {
                        //创建刚体需求
                        var bodyRequest:b2BodyDef = new b2BodyDef();
                        bodyRequest.type = b2Body.b2_staticBody;
                        bodyRequest.position.Set(275/30, 200/30);
                        //创建刚体形状
                        var circleShape:b2CircleShape = new b2CircleShape();
                        circleShape.SetRadius(170 / 30);
                        //创建刚体fixuture,并添加形状
                        var fixtureRequest:b2FixtureDef = new b2FixtureDef();
                        //******************************************
                        //这里是本章的重点
                        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中自定义的一个函数
                        //具体请参考我的教程:[url]http://www.ladeng6666.com/blog/index.php/2012/09/16/custom-box2d-contact-handler/[/url]
                        sensorBody.beginContactHanlder = contactEventHandler;
                }

                private function contactEventHandler(self:b2Body, contactedBody:b2Body):void 
                {
                        //当碰撞发生后,表示矩形刚体的changeGravity为true,这样在loop函数中可以实时更新它的重力,始终指向小圆
                        contactedBody.GetUserData().changeGravity = true;
                }
                private function loop(e:Event):void 
                {
                        LDEasyBox2D.updateWorld(world);
                        var body:b2Body;
                        for (body = world.GetBodyList(); body; body = body.GetNext()) {
                                if (body.GetUserData() != null) {
                                        ///如果跟刚体的GetUserData().changeGravity属性为true,则实时更新它的重力方向
                                        ///始终指向小的圆形刚体
                                        if (body.GetUserData().changeGravity) {
                                                //下面是一个简单的向量计算
                                                //1.获得矩形刚体与sensor刚体坐标向量的差
                                                var force:b2Vec2 = sensorBody.GetPosition().Copy();
                                                force.Subtract(body.GetPosition());
                                                //2.单位化该向量,只取得它的方向即可
                                                force.Normalize();
                                                //3.改变该向量的长度,生成新的重力
                                                force.Multiply(10);
                                                //重新设置刚体的重力
                                                body.m_customGravity = force;

                                                //为了让刚体慢慢坠落到小的圆形刚体上,用Multiply(0.99)逐渐缩小它的速度
                                                var velocity:b2Vec2 = body.GetLinearVelocity();
                                                velocity.Multiply(0.99);
                                        }
                                }
                        }
                }

        }

}


自定义的碰撞事件侦听类MyContactListener.as
[Actionscript3] 纯文本查看 复制代码
package  
{
        import Box2D.Dynamics.b2Body;
        import Box2D.Dynamics.b2ContactListener;
        import Box2D.Dynamics.Contacts.b2Contact;

        /**
         * ...
         * @author ladeng6666
         */
        public class MyContactListener extends b2ContactListener 
        {
                //具体详见我的教程[url]http://www.ladeng6666.com/blog/index.php/2012/09/16/custom-box2d-contact-handler/[/url]
                public function MyContactListener() 
                {

                }
                override public function BeginContact(contact:b2Contact):void 
                {
                        var bodyA:b2Body = contact.GetFixtureA().GetBody();
                        var bodyB:b2Body = contact.GetFixtureB().GetBody();

                        if (bodyA.beginContactHanlder != null) bodyA.beginContactWith(bodyB);
                        if (bodyB.beginContactHanlder != null) bodyB.beginContactWith(bodyA);
                }
                override public function EndContact(contact:b2Contact):void 
                {
                        var bodyA:b2Body = contact.GetFixtureA().GetBody();
                        var bodyB: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刚体碰撞处理函数



下载:
OK 2012-10-28 Box2D 用isSensor属性设置Box2D感应区域.rar (1006.66 KB, 下载次数: 0)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

感谢所有支持论坛的朋友:下面展示最新的5位赞助和充值的朋友……更多赞助和充值朋友的信息,请查看:永远的感谢名单

SGlW(66139)、 anghuo(841)、 whdsyes(255)、 longxia(60904)、 囫囵吞澡(58054)

下面展示总排行榜的前3名(T1-T3)和今年排行榜的前3名的朋友(C1-C3)……更多信息,请查看:总排行榜今年排行榜

T1. fhqu1462(969)、 T2. lwlpluto(14232)、 T3. 1367926921(962)  |  C1. anghuo(147)、 C2. fdisker(27945)、 C3. 囫囵吞澡(58054)



快速回复 返回顶部 返回列表