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

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

[2D 物理引擎] 【9RIA—ladeng6666】—【Box2D系列教程 33】用马达关节创建Box2D锁链效果

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

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

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

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


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


今天我们来学习Box2D锁链效果。这个效果并不难,记得我们学过的Box2D 关节——”马达关节” b2RevoluteJoint吗?锁链效果其实就是用多个b2RevolueJoint连接多个刚体,很简单吧!

简单在用多个关节连接多个刚体,难也难在这里。我们还是先来看看效果吧。在下面的效果中我创建了两个锁链,一个是小桥,另一个是连接了一个圆形刚体的锁链。鼠标可以点击并拖动下面的刚体。



看过效果之后,我想你肯定也想到了,要用for循环来创建锁链。要用for循环就要有可以重复执行的过程,仔细想想这个过程并不难。
创建当前的刚体body,指定节点的位置anchor,创建节点为anchor的关节,链接当前刚体body和前一个刚体preBody。如下图所示。图中虚线框内是fox循环要重复执行的过程。anchor1用来连接preBody和Body。相信可能有人会跟我一样,犯下面的错误,把关节点设置为body的中心点。这样旋转后,会出现图中下面的效果。因为preBody和body都是围绕anchor1旋转的嘛,想想风扇效果?!

1.jpg
正确的做法是像下图一样,创建当前刚体时body时,让它偏移anchor1一点,偏移多少呢?最好是刚体的一半,这样节点就移到了刚体的边缘处了。旋转之后就会像图中下面的效果一样自然了。
2.jpg
另外设置刚体的宽度为两个节点之间的间距,这样刚体之间会紧密相连,效果就跟上的SWF示例一样了!
完整的代码和注释如下:

[Actionscript3] 纯文本查看 复制代码
package  
{
        import Box2D.Common.Math.b2Vec2;
        import Box2D.Dynamics.b2Body;
        import Box2D.Dynamics.b2World;
        import Box2D.Dynamics.Joints.b2RevoluteJointDef;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;

        /**
         * ...
         * @author ladeng6666
         */
        public class Bridge extends Sprite 
        {
                private var world:b2World;

                public function Bridge() 
                {
                        //初始化,创建世界,添加事件侦听等等
                        init();
                        //创建小桥锁链
                        createBridge();
                        //创建一个可以拖动的锁链
                        creaetLinkage();
                        //随机创建几个刚体
                        createBodies();
                }

                private function init():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);
                }
                //拖动刚体
                private function mouseEventHandler(e:MouseEvent):void 
                {
                        if (e.type == MouseEvent.MOUSE_DOWN) {
                                var body:b2Body = LDEasyBox2D.getBodyAtMouse(world);
                                if (body != null) {
                                        LDEasyBox2D.startDragBody(world, body);
                                }

                        }else if (e.type == MouseEvent.MOUSE_UP) {
                                LDEasyBox2D.stopDragBody(world);
                        }
                }
                //更新世界
                private function loop(e:Event):void 
                {
                        LDEasyBox2D.updateWorld(world);
                }

                private function createBodies():void 
                {
                        //随机创建刚体
                        for (var i: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);
                                }
                        }
                }
                private function creaetLinkage():void 
                {
                        //设置第一节刚体开始的位置
                        var initx:Number = 150;
                        var inity:Number = 50;
                        //两个节点之间的间距
                        var gapBetweenAnchor:Number = 30;
                        //定义节点
                        var anchor:b2Vec2=new b2Vec2();
                        //当前刚体
                        var body:b2Body;
                        //前一个刚体
                        var preBody:b2Body;
                        //设置前一个刚体是一个圆形刚体,这个刚体不在for循环范围内,
                        //但是要在for循环里引用,所以在这里预先定义好
                        preBody = LDEasyBox2D.createCircle(world, initx, inity, 15);
                        //定义关节
                        var revoluteJoint:b2RevoluteJointDef = new b2RevoluteJointDef();

                        for (var i: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;
                        }
                }                

                private function createBridge():void 
                {
                        //设置第一节刚体开始的位置
                        var initx:Number = 100;
                        var inity:Number = 250;
                                //两个节点之间的间距
                        var gapBetweenAnchor:Number = 50;
                        //定义节点
                        var anchor:b2Vec2=new b2Vec2();
                        //当前刚体
                        var body:b2Body;
                        //前一个刚体
                        var preBody:b2Body;
                        //在for循环之外预先定义第一个刚体,定义成GetGroundBody,固定锁链的起点
                        preBody = world.GetGroundBody();
                        //定义关节
                        var revoluteJoint:b2RevoluteJointDef = new b2RevoluteJointDef();

                        for (var i: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如何固定动态刚体

下载:
OK 2012-11-25 Box2D锁链效果.rar (340.73 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)



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