BOX2d绘制曲线

来自天地会的wkyjoey同学问道如何做一个重力大师游戏(如下图)。这里要特意表示一下歉意,最近一直忙于工作,没有及时更新教程。


对于重力大师游戏,试玩之后,不难发现,我们在运行时可以创建的刚体有两种,线条刚体和多边形刚体。今天我们来一起研究一下线条刚体的创建。多边形刚体会在下次教程中讨论。
这里我们要绘制的线条不是直线而是曲线,所以简单的矩形刚体无法实现这个效果。在圆形边界教程中,我们同样接触到了曲线。解决方法是用多个线段组合起来模拟一个圆圈。庆幸的是这个方法同样适用于本例中的曲线。下面我们详细讨论一下。
线条是由无数个点组成的,把点放大一些就成了线段,所以一个线条可以变成多个线段的组合。

如上图,我们假设每个先断掉长度为segmentLength,线段的长度越短,segmentLength越小,线条模拟就越逼真。

在线条绘制过程中,持续检测鼠标坐标curPoint与前一个点prePoint之间的距离distance,当distance大于线段长度时,创建一个新的线段,并将curPoint赋值给prePoint。

好吧,下面我介绍一下具体的步骤:

  • 定义线段的长度segmentLength
  • 在鼠标点下后,卡是绘制线条,并记录之前的鼠标坐标位置为prePoint
  • 在绘制过程中。如果鼠标坐标与prePoint之间的距离distance大于segmentLength,则将鼠标坐标赋值给prePoint,创建新的线段,并添加到segmentList中
  • 鼠标弹起后,遍历所有的线段,并利用多边形组合法,创建对于的线段刚体,然后组合成一个完整的线条。


效果如下,点击并拖动鼠标开始绘制,其中的红点是线段的坐标位置。另外这里我没有限制线段的交叉,所以在绘制时尽量避免交叉,防止意外的错误,后续我们再讨论如何防止绘制线段时交叉。

源码中用到了LDEasyBox2D来简化代码。完整的代码及注释如下:

  1. package
  2. {
  3.     import Box2D.Collision.b2AABB;
  4.     import Box2D.Collision.Shapes.b2PolygonShape;
  5.     import Box2D.Common.Math.b2Vec2;
  6.     import Box2D.Dynamics.b2Body;
  7.     import Box2D.Dynamics.b2BodyDef;
  8.     import Box2D.Dynamics.b2DebugDraw;
  9.     import Box2D.Dynamics.b2FixtureDef;
  10.     import Box2D.Dynamics.b2World;
  11.     import flash.display.Sprite;
  12.     import flash.events.Event;
  13.     import flash.events.MouseEvent;
  14.     import flash.geom.Point;
  15.     /**
  16.      * http://www.ladeng6666.com
  17.      * @author ladeng6666
  18.      */
  19.     public class Main extends Sprite
  20.     {
  21.         private var world:b2World;
  22.         private var spriteCanvas:Sprite;
  23.         private var tipCanvas:Sprite;
  24.         //前一个point
  25.         private var prePoint:Point = new Point();
  26.         //当前的point
  27.         private var curPoint:Point = new Point();
  28.         //1.设置线段长度segmentLength
  29.         private var segmentLength:Number = 20;
  30.         private var segmentsList:Array=new Array();
  31.         private var isDrawing:Boolean = false;
  32.         public function Main()
  33.         {
  34.             //创建box2D世界
  35.             world = LDEasyBox2D.createWorld();
  36.             //创建box2D调试图
  37.             addChild(LDEasyBox2D.createDebug(world));
  38.             //创建地面
  39.             LDEasyBox2D.createWrapWall(world,stage);
  40.             spriteCanvas = new Sprite();
  41.             addChild(spriteCanvas);
  42.             tipCanvas = new Sprite();
  43.             addChild(tipCanvas);
  44.             //侦听事件
  45.             addEventListener(Event.ENTER_FRAME, loop);
  46.             stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
  47.             stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
  48.             stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove);
  49.         }
  50.         private function onStageMouseDown(e:MouseEvent):void
  51.         {
  52.             //2.开始绘制线条,并定义prePoint
  53.             isDrawing = true;
  54.             spriteCanvas.graphics.lineStyle(2);
  55.             spriteCanvas.graphics.moveTo(mouseX, mouseY);
  56.             curPoint = new Point(mouseX, mouseY);
  57.             prePoint = curPoint.clone();
  58.         }
  59.         private function onStageMouseMove(e:MouseEvent):void
  60.         {
  61.             if(!isDrawing) return;
  62.             spriteCanvas.graphics.lineTo(mouseX, mouseY);
  63.             curPoint = new Point(mouseX, mouseY);
  64.             var distance:Number = Point.distance(prePoint, curPoint);
  65.             if (distance >= segmentLength) {
  66.                 //3.创建线段,并添加到segmentsList中
  67.                 segmentsList.push( new Segment(prePoint, curPoint));
  68.                 prePoint = curPoint.clone();
  69.             }
  70.         }
  71.         private function onStageMouseUp(e:MouseEvent):void
  72.         {
  73.             isDrawing = false;
  74.             spriteCanvas.graphics.clear();
  75.             //在鼠标位置随机创建一个圆形或矩形刚体
  76.             createSegment(segmentsList);
  77.             //清楚segmengsList里的内容
  78.             segmentsList = new Array();
  79.         }
  80.         private function loop(e:Event):void
  81.         {
  82.             world.Step(1 / 30, 10, 10);
  83.             world.ClearForces();
  84.             world.DrawDebugData();
  85.             drawTip(segmentsList);
  86.         }
  87.         private function createSegment(segmentsArray:Array):void
  88.         {
  89.             //1.创建刚体需求b2BodyDef
  90.             var bodyRequest:b2BodyDef = new b2BodyDef();
  91.             bodyRequest.type = b2Body.b2_dynamicBody;
  92.             bodyRequest.position.Set(0 ,0);//记得米和像素的转换关系
  93.             //2.Box2D世界工厂更具需求创建createBody()生产刚体
  94.             var body:b2Body=world.CreateBody(bodyRequest);
  95.             //3.创建敢提形状需求b2ShapeDef的子类
  96.                 //创建矩形刚体形状需求
  97.             var fixtureRequest:b2FixtureDef = new b2FixtureDef();
  98.             fixtureRequest.density = 3;
  99.             fixtureRequest.friction = 0.3;
  100.             fixtureRequest.restitution = 0.2;
  101.             for each(var segment:Segment in segmentsArray) {
  102.                 var shapeBoxRequest:b2PolygonShape = new b2PolygonShape();
  103.                 shapeBoxRequest.SetAsOrientedBox(segment.length /2/ 30, 2 / 30, new b2Vec2(segment.centerX/30, segment.centerY/30), segment.rotation);
  104.                 fixtureRequest.shape = shapeBoxRequest;
  105.                 body.CreateFixture(fixtureRequest);
  106.             }
  107.         }
  108.         private function drawTip(segmengtsArray:Array):void {
  109.             tipCanvas.graphics.clear();
  110.             for each( var segment:Segment in segmengtsArray) {
  111.                 tipCanvas.graphics.beginFill(0xFF0000, 0.5);
  112.                 tipCanvas.graphics.drawCircle(segment.centerX, segment.centerY,3);
  113.             }
  114.         }
  115.     }
  116. }
复制代码

<ignore_js_op style="font: 16px/28px Tahoma, Helvetica, SimSun, sans-serif; color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; word-wrap: break-word; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"> 2012-07-08 实时绘制线条刚体2.1a.rar (336.7 KB, 下载次数: 307) 

posted @ 2014-02-21 16:00  酷小卡  阅读(753)  评论(0编辑  收藏  举报