9RIA-ladeng6666 发表于 2018-2-5 16:41:33

【9RIA—ladeng6666】—【Box2D系列教程 12】创建圆形Box2D边界

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


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


在让刚体听我的——ApplyForce、ApplyImpulse、SetLinearVelocity一节中,来自天地会的sxl001问道如何创建圆形的边界,好吧,我用这个教程来回答他。

实际上Box2D中没有专门创建圆弧的API (b2CircleDef创建的是实体圆形不是圆弧),所以试图寻找这样一个API的同学就放弃吧。结束了?坑爹啊!

哈哈,既然没有圆弧API,我就想其他的方法嘛。还记得Box2D多边形刚体的创建方法嘛?我们可以利用组合法,把多个形状组合起来形成一个这你的形状,当然也可以包括圆弧,下面的图可以更好的解释这一点。


图中我用12个线段组合起来模拟一个圆形,当然你可以用24个、36个线段等等。线段数越多,圆形就越标准,同时也越消耗CPU,所以能模拟出圆形效果就可以了,不用追求完美。现在,你应该有思路了吧:
    1.定义线段的个数,12、24、36随你便,但不要太多。
    2.for循环遍历创建线段,根据线段索引i和圆形边界半径radius计算线段的坐标、角度
    3.利用Box2D多边形刚体的组合法在线段的坐标位置创建与之角度相同的矩形刚体
效果如下:

attach://790.swf

我在下面的代码中做了详细的注释并highlight,我就不再讲解了,大家看代码吧!
package
{
    import Box2D.Collision.b2AABB;
    import Box2D.Collision.Shapes.b2CircleDef;
    import Box2D.Collision.Shapes.b2PolygonDef;
    import Box2D.Collision.Shapes.b2ShapeDef;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.b2Body;
    import Box2D.Dynamics.b2BodyDef;
    import Box2D.Dynamics.b2DebugDraw;
    import Box2D.Dynamics.b2World;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;

    /**
   * http://www.ladeng6666.com
   * @author ladeng6666
   */
    public class Main extends Sprite
    {
      private var world:b2World;
      private var body:b2Body;

      public function Main()
      {
            //创建box2D世界
            createWorld();
            //创建box2D调试图
            createDebug();
            //创建刚体
            createStuff(stage.stageWidth / 2, 0);
            //创建圆形边界
            createCircleGround();
            //侦听事件
            addEventListener(Event.ENTER_FRAME, loop);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
      }

      private function onStageMouseDown(e:MouseEvent):void
      {
            //在鼠标位置随机创建一个圆形或矩形刚体
            createStuff(mouseX,mouseY,Math.random()>0.5);
      }

      private function loop(e:Event):void
      {
            world.Step(1/30, 10);
      }

      private function createWorld():void
      {
            //1.创建一个环境
            var environment:b2AABB = new b2AABB();
            environment.lowerBound = new b2Vec2( -100, -100);
            environment.upperBound = new b2Vec2(100, 100);
            //2.声明重力
            var gravity:b2Vec2 = new b2Vec2(0, 10);
            //3.睡着的对象是否模拟
            var doSleep:Boolean = true;
            //4.创建b2World世界
            world = new b2World(environment, gravity, doSleep);
      }

      private function createDebug():void
      {
            var debugSprite:Sprite = new Sprite();
            addChild(debugSprite);

            var debugDraw:b2DebugDraw = new b2DebugDraw();
            debugDraw.m_sprite = debugSprite;
            debugDraw.m_drawScale = 30.0;
            debugDraw.m_fillAlpha = 0.5;
            debugDraw.m_lineThickness = 1.0;
            debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;

            world.SetDebugDraw(debugDraw);
      }
      private function createStuff(posX:Number,posY:Number,isBox:Boolean=true):void
      {
            //1.创建刚体需求b2BodyDef
            var bodyRequest:b2BodyDef = new b2BodyDef();
            bodyRequest.position.Set(posX / 30, posY / 30);//记得米和像素的转换关系
            //2.Box2D世界工厂更具需求创建createBody()生产刚体
            body=world.CreateBody(bodyRequest);
            //3.创建敢提形状需求b2ShapeDef的子类
            if ( isBox) {
                //创建矩形刚体形状需求
                var shapeBoxRequest:b2PolygonDef = new b2PolygonDef();
                shapeBoxRequest.density = 3;
                shapeBoxRequest.friction = 0.3;
                shapeBoxRequest.restitution = 0.2;
                shapeBoxRequest.SetAsBox(1, 1);
                body.CreateShape(shapeBoxRequest);

            }else {
                //创建圆形刚体形状需求
                var shapeCircleRequest:b2CircleDef = new b2CircleDef();
                shapeCircleRequest.density = 3;
                shapeCircleRequest.friction = 0.3;
                shapeCircleRequest.restitution = 0.2;
                shapeCircleRequest.radius = 1;
                body.CreateShape(shapeCircleRequest);
            }
            body.SetMassFromShapes();
      }

      private function createCircleGround():void
      {
            var centerX:Number = stage.stageWidth / 2;
            var centerY:Number = stage.stageHeight / 2;
            //1.创建刚体需求b2BodyDef
            var bodyRequest:b2BodyDef = new b2BodyDef();
            bodyRequest.position.Set(centerX / 30, centerY / 30);//记得米和像素的转换关系
            //2.Box2D世界工厂更具需求创建createBody()生产刚体
            body = world.CreateBody(bodyRequest);

            //3.创建敢提形状需求b2ShapeDef的子类
            //定义线段的个数
            var segmentNum:Number = 36;
            //定义圆形边界的半径
            var radius:Number = 200;
            //根据半径和个数计算线段的长度
            var segmentlength:Number = radius * Math.sin(Math.PI/segmentNum);
            //for循环创建segmentNum个线段,合成圆形边界
            for (var i:int = 0; i < segmentNum; i++) {
                //定义形状需求
                var shapeRequest:b2PolygonDef = new b2PolygonDef();
                //形状的质量、摩擦系数、硬度
                shapeRequest.density = 0;
                shapeRequest.friction = 0.3;
                shapeRequest.restitution = 0.2;
                //计算每个线段的角度、坐标
                var angle:Number = i/segmentNum *Math.PI*2;
                var bx:Number = radius * Math.cos(angle);
                var by:Number = radius * Math.sin(angle);
                //创建有方向的矩形刚体,合成总的圆形刚体
                shapeRequest.SetAsOrientedBox(5/30, segmentlength/30, new b2Vec2(bx/30,by/30),angle);
                //4.b2Body刚体工厂根据需求createShape生产形状
                body.CreateShape(shapeRequest);
            }

            body.SetMassFromShapes();
      }
    }

}


下载:



2.1a版
package {

      import Box2D.Collision.Shapes.b2PolygonShape;
      import Box2D.Common.Math.b2Vec2;
      import Box2D.Dynamics.b2Body;
      import Box2D.Dynamics.b2BodyDef;
      import Box2D.Dynamics.b2DebugDraw;
      import Box2D.Dynamics.b2FixtureDef;
      import Box2D.Dynamics.b2World;

      import flash.display.Sprite;
      import flash.events.Event;
      import flash.events.MouseEvent;

      public class YuanXingBianJie extends Sprite {
                private var world:b2World;
                private var body:b2Body;
                private const WORLDSCALE:int = 30;

                public function YuanXingBianJie() {
                        createWorld();
                        createCircleGround();
                        createDebug();
                        createBody(stage.stageWidth / 2, 0);
                        addEventListener(Event.ENTER_FRAME, loop);
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
                }

                private function createWorld():void {
                        var gravity:b2Vec2 = new b2Vec2(0, 10);
                        var doSleep:Boolean = true;
                        world = new b2World(gravity, doSleep);
                }

                private function createCircleGround():void {
                        var bodyDef:b2BodyDef = new b2BodyDef();
                        bodyDef.type = b2Body.b2_staticBody;
                        bodyDef.position.Set(stage.stageWidth / 2 / WORLDSCALE, stage.stageHeight / 2 / WORLDSCALE);
                        body = world.CreateBody(bodyDef);
                        var segmentNum:Number = 36;
                        var radius:Number = 200;
                        var segmentLength:Number = radius * Math.sin(Math.PI / segmentNum);
                        var fixtureDef:b2FixtureDef = new b2FixtureDef();
                        fixtureDef.density = 0;
                        fixtureDef.friction = 0.3;
                        fixtureDef.restitution = 0.2;
                        for (var i:int = 0; i < segmentNum; i++) {
                              var angle:Number = i / segmentNum * Math.PI * 2;
                              var bx:Number = radius * Math.cos(angle);
                              var by:Number = radius * Math.sin(angle);
                              var polygonShape:b2PolygonShape = new b2PolygonShape();
                              polygonShape.SetAsOrientedBox(5 / WORLDSCALE, segmentLength / WORLDSCALE, new b2Vec2(bx / WORLDSCALE, by / WORLDSCALE), angle);
                              fixtureDef.shape = polygonShape;
                              body.CreateFixture(fixtureDef);
                        }
                }

                private function createDebug():void {
                        var debugSprite:Sprite = new Sprite();
                        addChild(debugSprite);
                        var debugDraw:b2DebugDraw = new b2DebugDraw();
                        debugDraw.SetSprite(debugSprite);
                        debugDraw.SetDrawScale(WORLDSCALE);
                        debugDraw.SetAlpha(0.5);
                        debugDraw.SetLineThickness(1);
                        debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
                        world.SetDebugDraw(debugDraw);
                }

                private function createBody(posX:Number, posY:Number):void {
                        var polygonShape:b2PolygonShape = new b2PolygonShape();
                        polygonShape.SetAsBox(20 / WORLDSCALE, 20 / WORLDSCALE);
                        var fixtureDef:b2FixtureDef = new b2FixtureDef();
                        fixtureDef.density = 3;
                        fixtureDef.friction = 0.3;
                        fixtureDef.restitution = 0.2;
                        fixtureDef.shape = polygonShape;
                        var bodyDef:b2BodyDef = new b2BodyDef();
                        bodyDef.type = b2Body.b2_dynamicBody;
                        bodyDef.position.Set(posX / WORLDSCALE, posY / WORLDSCALE);
                        body = world.CreateBody(bodyDef);
                        body.CreateFixture(fixtureDef);
                }

                private function onStageMouseDown(e:MouseEvent):void {
                        createBody(mouseX, mouseY);
                }

                private function loop(e:Event):void {
                        world.Step(1 / 30, 10, 10);
                        world.ClearForces();
                        world.DrawDebugData();
                }
      }
}
页: [1]
查看完整版本: 【9RIA—ladeng6666】—【Box2D系列教程 12】创建圆形Box2D边界

感谢所有支持论坛的朋友:下面展示最新的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)