组合法创Nape多边形刚体

看到题目有没有有想到Box2D多边形刚体里的组合法和原生法创建Box2D多边形刚体呢?没错Nape的组合法跟Box2D在原理上是一样的。今天我们来学习一下Nape中创建多边形刚体的组合法。

我们知道,Nape中的刚体结构比Box2D刚体结构要简单,没有b2FixtureDef、b2Fixture或b2ShapeDef、b2Shape等这些让人头疼的类和混乱的关系,Nape刚体的所有图形都在Body.shapes属性中,用组合法创建多边形刚体,我们需要做的就是把多个Shape对象或子对象添加到Body.shapes属性中就可以了。

打个比方来讲。我们都知道,在Flash中可以将一个MovieClip对象作为容器,将其他的MoviClip对象添加到其中,作为它的子对象,当我们旋转这个容器时,里面的子对象也会随着旋转。Body.shapes属性就相当于这个容器,要添加的Shape图形就是容器中的子对象,这样讲应该会比较好理解吧!

Body.shapes会返回一个ShapeList对象,然后我们可以通过调用ShapeList的push()方法将其他Shape图形添加进去,代码如下:

				var circle:Shape=new Circle(5);
				body.shapes.push(circle);

图形添加进去之后,默认是在刚体的中心的,如下面图中的矩形。但是,有时候我们也会遇到下图中圆形Shape的情况,图形不在刚体的中心,

这时候就要用shape的localCOM(即local center of mass重心)属性设置图像的偏移量。

napeShapeOffset

如上图圆形的圆心在(10,10)处,那么设置它的偏移量代码应该写成:

				var circle:Shape = new Circle(5);
				//设置图形的偏移量
				circle.localCOM.setxy(10,10);
				body.shapes.push(circle);

解决了图形偏移量的问题,新的问题又来了,像下图中添加图形后,刚体中心(也是重心)在图形之外,这在现实生活中是不大可能发生的,我们需要把刚体重心移动至合理的位置,比如下图中矩形和圆形之间。

napeShapeOffset2

怎么做呢?很简单,Body中有一个align()方法,可以自动纠正刚体的重心移动到图形中心位置。代码如下:

				//纠正刚体的重心
				body.align();

完成了这些工作之后,我们就可以创建出完美的组合式多边形刚体啦!

在下面的示例用,点击并拖动上面工具条中的矩形或圆形,可以创建一个图形,点击创建好的图形,可以进行角度调整,多创建几个并将它们进行组合后,点击create按钮创建刚体。试试看吧!

Sorry, either Adobe flash is not installed or you do not have it enabled

很酷吧,是不是有点神奇的阿力的感觉?

完整的源代码如下,点击这里下载源文件。

代码的重点在71-98行,创建图形并添加到Body刚体中,我已经添加了详细的注释,就不再赘述了。

package 
{
	import com.bit101.components.PushButton;

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

	import utils.LDEasyNape;
	import utils.TransformTool;
	import utils.Stats;

	import nape.phys.Body;
	import nape.phys.BodyType;
	import nape.phys.Material;
	import nape.shape.Circle;
	import nape.shape.Polygon;
	import nape.shape.Shape;

	[SWF( width="550", height="400", frameRate="60")]
	public class T12_CreatePolygonBodyWithShapes extends AbstractNapeTest
	{
		private var spriteList:Vector.<Sprite>;
		private var curShape:Sprite;
		//旋转工具类
		private var transformTool:TransformTool;
		private var transformPara:Object;

		public function T12_CreatePolygonBodyWithShapes()
		{
			//创建多动变形工具
			transformTool=new TransformTool(stage);
			transformPara={enScaleX:false,
							enScaleY:false,
							enSkewX:false,
							enSkewY:false,
							enSetMidPoint:false };
			//创建存储图形的Vector数组
			spriteList=new Vector.<Sprite>();
		}
		override protected function onNapeWorldReady():void
		{
			//添加上方的工具条
			var bg:Sprite=new Sprite();
			addChild(bg);
			bg.graphics.beginFill(0,0.8);
			bg.graphics.drawRect(0,0,550,50);
			bg.graphics.endFill();

			var shape1:Sprite=createRectShape(150,25,80,30);
			var shape2:Sprite=createCircleShape(250,25,15);
			shape1.name="rectBtn";
			shape2.name="circleBtn";
			//添加create按钮,并侦听按钮事件
			var btn:PushButton = new PushButton(this, 400, 10, "createBody", function():void {
				//按钮按下后,遍历spriteList数组,根据数组里的元素创建Nape刚体
				if (spriteList.length < 1) return;
				//创建Nape刚体
				createBodyWidthShapes();
				//删除Sprite图形
				for (var i:int=0 ;i<spriteList.length;i++){
					var sprite:Sprite=spriteList[i];
					sprite.parent.removeChild(sprite);
				}
				//清空数组
				spriteList=new Vector.<Sprite>();
			});
		}

		//创建刚体
		private function createBodyWidthShapes():void{
			var body:Body = new Body();
			//遍历SpriteList数组里的每个元素
			for each(var sprite:Sprite in spriteList) {
				//根据这些元素,创建图形,并添加到body.shapes属性中
				body.shapes.push(createNapeShape(sprite));
			}
			//纠正刚体重心
			body.align();
			body.space=napeWorld;
		}
		//创建Nape中的shape对象,准备添加到刚体中
		private function createNapeShape(sprite:Sprite):Shape
		{
			var s:Shape;
			if(sprite.name=="circleBody"){
				s = new Circle(15, null, Material.glass());
				//设置刚体偏移量
				s.localCOM.setxy(sprite.x,sprite.y);
			}else if(sprite.name=="rectBody"){
				s = new Polygon(Polygon.box(80, 30), Material.glass());
				//旋转图形
				s.rotate((sprite.rotation) % 360 * Math.PI / 180);
				//设置刚体偏移量
				s.localCOM.setxy(sprite.x,sprite.y);
			}
			return s;
		}
		//鼠标点击后,根据点击的对象不同,进行不同的操作
		override protected function mouseEventHanlder(me:MouseEvent):void{
			if(me.type==MouseEvent.MOUSE_DOWN){
				switch(me.target.name)
				{
					//如果是工具条中的矩形或圆形,则新建相应的图形
					case "circleBtn":
					{
						curShape=createCircleShape(mouseX,mouseY,15,0x339999);
						curShape.name="circleBody";
						curShape.startDrag();
						spriteList.push(curShape);
						break;
					}
					case "rectBtn":
					{
						curShape=createRectShape(mouseX,mouseY,80,30,0x339999);
						curShape.name="rectBody";
						curShape.startDrag();
						spriteList.push(curShape);
						break;
					}
					//如果是创建好的图形,则进行拖动或旋转
					case "rectBody":
					case "circleBody":
					{
						curShape=me.target as Sprite;
						transformTool.AddControl(curShape);
						transformTool.SetStyle(curShape,transformPara);
						transformTool.Init();
						break;
					}
					default:
					{
						break;
					}
				}
			}else if(me.type==MouseEvent.MOUSE_UP){
				if(curShape!=null) curShape.stopDrag();
			}
		}
		//创建图形的两个函数
		private function createRectShape(x:Number,y:Number,w:Number,h:Number,color:uint=0xFFFFFF):Sprite{
			var rect:Sprite=new Sprite();
			rect.graphics.lineStyle(1);
			rect.graphics.beginFill(color,1);
			rect.graphics.drawRect(-w/2,-h/2,w,h);
			rect.graphics.endFill();
			rect.x=x;
			rect.y=y;
			addChild(rect);
			rect.buttonMode=true;
			return rect;
		}
		private function createCircleShape(x:Number,y:Number,r:Number,color:uint=0xFFFFFF):Sprite{
			var circle:Sprite=new Sprite();
			circle.graphics.lineStyle(1);
			circle.graphics.beginFill(color,1);
			circle.graphics.drawCircle(0,0,r);
			circle.graphics.endFill();
			circle.x=x;
			circle.y=y;
			addChild(circle);
			circle.buttonMode=true;
			return circle;
		}
	}
}

 

2 Replies to “组合法创Nape多边形刚体”

Comments are closed.