9RIA-ladeng6666 发表于 2018-2-6 14:12:35

【9RIA—ladeng6666】—【Box2D系列教程 16】多边形刚体贴图

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


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


在前面的刚体的上衣教程中,我们学会了简单的刚体贴图,确实非常简单,只需要根据b2Body刚体的坐标和角度实时更新userData的坐标和角度就可以了。那么多边形刚体贴图呢?

放心啦,没你想象的那么复杂,和简单刚体的贴图方法是一样一样的,重点是如何绘制和多边形刚体一样的图形,很幸运,我们在用drawPath自由绘制图形中已经学会了,结合运行时创建多边形刚体,我们可以轻松给多边形刚体啦(如果你还不熟练,强烈建议你好好看看这两篇教程)。效果如下:

attach://870.swf

完整的代码和注释如下:
package
{
        import Box2D.Collision.b2AABB;
        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 Box2DSeparator.b2Separator;
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.DisplayObject;
        import flash.geom.Matrix;

        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Point;
        import flash.display.GraphicsPathCommand;

        /**
       * http://www.ladeng6666.com
       * @author ladeng6666
       */
        public class MainWithSeparator extends Sprite
        {
                private const segmentLength:Number = 20;

                private var world:b2World;
                //绘制图形的画布
                private var spriteCanvas:Sprite;
                private var spriteCommand:Vector.<int> = new Vector.<int>();
                private var spriteData:Vector.<Number> = new Vector.<Number>();
                //绘制图像的纹理
                private var woodBmd:BitmapData = new Wood();

                private var prePoint:Point = new Point();
                private var curPoint:Point = new Point();

                private var verticesList:Vector.<b2Vec2> = new Vector.<b2Vec2>();

                private var isDrawing:Boolean = false;
                public function MainWithSeparator()
                {
                        //创建box2D世界
                        world = LDEasyBox2D.createWorld();
                        //创建box2D调试图
                        addChild(LDEasyBox2D.createDebug(world));
                        //创建地面
                        LDEasyBox2D.createWrapWall(world,stage);

                        spriteCanvas = new Sprite();
                        addChild(spriteCanvas);
                        //侦听事件
                        addEventListener(Event.ENTER_FRAME, loop);
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
                        stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove);
                }

                private function onStageMouseMove(e:MouseEvent):void
                {
                        //如果鼠标没有按下,isDrawing为false,跳出
                        if(!isDrawing) return;
                        spriteCanvas.graphics.lineTo(mouseX, mouseY);
                        //记录鼠标坐标为当前curPoint,并计算curPoint与上一个点prePoint的距离
                        curPoint = new Point(mouseX, mouseY);
                        var distance:Number = Point.distance(prePoint, curPoint);
                        //当前后两个点的距离大于线段距离时,添加顶点
                        if (distance >= segmentLength) {
                                //记录顶点到verticesList数组中
                                verticesList.push(new b2Vec2(mouseX / 30, mouseY / 30));
                                prePoint = curPoint.clone();
                                //存储绘制命令和绘制顶点
                                spriteCommand.push(GraphicsPathCommand.LINE_TO);
                                spriteData.push(mouseX);
                                spriteData.push(mouseY);
                        }
                }

                private function onStageMouseUp(e:MouseEvent):void
                {
                        spriteCommand.push(GraphicsPathCommand.LINE_TO);
                        spriteData.push(spriteData);
                        spriteData.push(spriteData);
                        //鼠标弹起后,停止绘制
                        isDrawing = false;
                        //画布里的内容
                        spriteCanvas.graphics.clear();
                        //在鼠标位置随机创建一个多边形刚体
                        var polygonBody:b2Body=createPolygon();
                        if (polygonBody != null) {
                                createUseData(polygonBody, spriteCommand, spriteData);
                        }
                        //清空存储命令和顶点的数组
                        spriteCommand = new Vector.<int>();
                        spriteData = new Vector.<Number>();
                        //清空存储顶点的Vector数组
                        verticesList = new Vector.<b2Vec2>();
                }
                /**
               * 鼠标按下事件侦听
               * @param        e
               */
                private function onStageMouseDown(e:MouseEvent):void
                {
                        //鼠标按下后,开始绘制
                        isDrawing = true;
                        //设置线条样式
                        spriteCanvas.graphics.lineStyle(2);
                        spriteCanvas.graphics.moveTo(mouseX, mouseY);
                        //存储绘制命令和绘制顶点
                        spriteCommand.push(GraphicsPathCommand.MOVE_TO);
                        spriteData.push(mouseX);
                        spriteData.push(mouseY);
                        //定义鼠标点为起点
                        curPoint = new Point(mouseX, mouseY);
                        prePoint = curPoint.clone();

                        verticesList.push(new b2Vec2(mouseX / 30, mouseY / 30));
                }
                /**
               * 刷新屏幕
               * @param        e
               */
                private function loop(e:Event):void
                {
                        world.Step(1 / 30, 10, 10);
                        world.ClearForces();
                        world.DrawDebugData();

                        for (var body:b2Body = world.GetBodyList(); body; body=body.GetNext()) {
                                if (body.GetUserData() != null) {
                                        //根据刚体的坐标个角度,更新绑定的userData
                                        body.GetUserData().x = body.GetPosition().x * 30;
                                        body.GetUserData().y = body.GetPosition().y * 30;
                                        body.GetUserData().rotation = body.GetAngle() * 180 / Math.PI;
                                }
                        }
                }
                /**
               * 创建多边形刚体
               * @return
               */
                private function createPolygon():b2Body
                {
                        //1.创建刚体需求b2BodyDef
                        var bodyRequest:b2BodyDef = new b2BodyDef();
                        bodyRequest.type = b2Body.b2_dynamicBody;
                        bodyRequest.position.Set(0 , 0);//记得米和像素的转换关系
                        //2.Box2D世界工厂更具需求创建createBody()生产刚体
                        var body:b2Body=world.CreateBody(bodyRequest);
                        //3.创建敢提形状需求b2ShapeDef的子类
                                //创建矩形刚体形状需求
                        var fixtureRequest:b2FixtureDef = new b2FixtureDef();
                        fixtureRequest.density = 3;
                        fixtureRequest.friction = 0.3;
                        fixtureRequest.restitution = 0.2;
                        //创建一个Separator对象
                        var separator:b2Separator = new b2Separator();
                        //验证顶点是否符合创建多边形的标准
                        var validate:int = separator.Validate(verticesList);
                        //如果是顶点因非顺时针不符标准,则反转数组中的顶点顺序
                        if (validate == 2) {
                                verticesList.reverse();
                        }else if (validate != 0) {
                                //如果不符合多边形标准,跳出
                                return null;
                        }
                        //将顶点分解成多个凸多边形,组合成复杂的多边形
                        separator.Separate(body, fixtureRequest, verticesList);

                        return body;
                }
                /**
               * 根据存储的路径、顶点绘制多边形图形,并绑定到刚体中
               * @param        body 要添加贴图的刚体
               * @param        commandVector 存储绘图命令的刚体
               * @param        posVector 存储绘图顶点的刚体
               */
                private function createUseData(body:b2Body, commandVector:Vector.<int>, posVector:Vector.<Number>):void {
                        //创建一个空白的画布
                        var canvas:Sprite = new Sprite();
                        canvas.graphics.clear();
                        canvas.graphics.lineStyle(3, 0x4D370B);
                        //利用存储的命令和顶点绘制并填充图形
                        canvas.graphics.beginBitmapFill(woodBmd);
                        canvas.graphics.drawPath(commandVector, posVector);
                        canvas.graphics.endFill();
                        addChild(canvas);
                        //把画布绑定到刚体中
                        body.SetUserData(canvas);
                }
        }

}
页: [1]
查看完整版本: 【9RIA—ladeng6666】—【Box2D系列教程 16】多边形刚体贴图

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