自定义刚体与拖动

调用b2PolygonDef的setAsBox函数传入一个半宽和半高,即可以创建一个矩形刚体,设置b2CircleDef的radius属性,即可以创建一个圆形的刚体,如果现在要创建一个五边形,六边形的刚体呢,box2d并没有提供这样的方法来创建。

利用b2PolygonDef的两个属性vertexCount和vertices,可以创建自定义刚体。

vertexCount:刚体的顶点数。
vertices:一个数组,用来保存刚体的所有定点。

package  
{
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import myClass.box2d.PhyOption;
	import myClass.box2d.Floor;
	import myClass.box2d.Wall;
	
	/**
	 * ...
	 * @author ywxgod
	 */
	[SWF(backgroundColor="0x333333",frameRate="30")]
	public class CustomBody extends Sprite
	{
		private var _world:b2World;
		private var _mouseJoint:b2MouseJoint;
		
		public function CustomBody() 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event=null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			_world = PhyOption.getInstance().world;
			new Floor(new MyFloor(), this);
			new Wall(new MyFloor(), this, Wall.LEFT);
			new Wall(new MyFloor(), this,Wall.RIGHT);
			
			createBodies();
			showDebug();
			
			addEventListener(Event.ENTER_FRAME, onFrame);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
		}
		
		private function setConvexVertex(shapeDef:b2PolygonDef,n:int,radius:Number):void 
		{
			shapeDef.vertexCount = n;
			var angle:Number = Math.PI * 2 / n;
			var radius:Number = radius / PhyOption.PHYSCALE;
			for (var i:int = 0; i < n;i++ )
			{
				var dx:Number = radius * Math.cos(angle * i);
				var dy:Number = radius * Math.sin(angle * i);
				shapeDef.vertices[i].Set(dx,dy);
			}
			shapeDef.friction = 0.3;
			shapeDef.restitution = 0.3;
			shapeDef.density = 2;
		}
		
		private function setRandomInt(a:int,b:int):int
		{
			return a + Math.floor(Math.random() * (b - a + 1));
		}
		
		private function createBodies():void 
		{
			for (var i:int = 3; i <= 7;i++ )
			{
				var xpos:Number = 275 + setRandomInt( -20, 20);
				var ypos:Number = 0;
				var radius:Number = 30 + setRandomInt( -20, 20);
				createBody(xpos,ypos,i,radius);
			}
			
		}
		
		private function createBody(xpos:Number,ypos:Number,vertexCount:int,radius:Number):void
		{
			var boxShapeDef:b2PolygonDef = new b2PolygonDef();
			setConvexVertex(boxShapeDef,vertexCount,radius);
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.angle = Math.random() * 360;
			bodyDef.position.Set(xpos/ PhyOption.PHYSCALE, ypos/PhyOption.PHYSCALE);
			var body:b2Body = _world.CreateBody(bodyDef);
			body.CreateShape(boxShapeDef);
			body.SetMassFromShapes();
		}
		
		private function showDebug():void 
		{
			var sp:Sprite = new Sprite();
			this.addChild(sp);
			var dbg:b2DebugDraw = new b2DebugDraw();
			dbg.m_sprite = sp;
			dbg.m_alpha = 0.5;
			dbg.m_drawScale = PhyOption.PHYSCALE;
			dbg.m_fillAlpha = 0.5;
			dbg.m_drawFlags = b2DebugDraw.e_shapeBit;
			dbg.m_lineThickness = 1;
			_world.SetDebugDraw(dbg);
		}
		
		private function onFrame(e:Event):void 
		{
			PhyOption.getInstance().update();
			if (_mouseJoint)
			{
				_mouseJoint.SetTarget(new b2Vec2(stage.mouseX/PhyOption.PHYSCALE,stage.mouseY/PhyOption.PHYSCALE));
			}
		}
		
		private function onDown(e:MouseEvent):void 
		{
			var body:b2Body = PhyOption.getInstance().GetBodyAtMouse(this.stage);
			if (body)
			{
				var mouseJointDef:b2MouseJointDef = new b2MouseJointDef();
				mouseJointDef.body1 = _world.GetGroundBody();
				mouseJointDef.body2 = body;
				mouseJointDef.maxForce = 40000;
				mouseJointDef.timeStep = PhyOption.STEP;
				mouseJointDef.target.Set(stage.mouseX / PhyOption.PHYSCALE, stage.mouseY / PhyOption.PHYSCALE);
				_mouseJoint = _world.CreateJoint(mouseJointDef) as b2MouseJoint;
			}
		}
		
		private function onUp(e:MouseEvent):void 
		{
			if (_mouseJoint)
			{
				_world.DestroyJoint(_mouseJoint);
				_mouseJoint = null;
			}
		}
		
	}

}

39-42行:PhyOption,Floor,Wall都是自定义类,分别用来初始化b2world,创建地面,墙壁等。

52-66行:函数setConvexVertex创建圆内切多边形,box2d中只对凸多边形起作用,凹多边形是box2d无法处理的。

73-83行:创建3,4,5。。。7边形。奇怪的是,如果创建九边形,就会报错,即:循环i从3到8没问题,一旦循环到9就会报错:

      TypeError: Error #1010: 术语尚未定义,并且无任何属性。
       at CustomBody/setConvexVertex()
       at CustomBody/createBody()
       at CustomBody/createBodies()
       at CustomBody/init()
       at CustomBody()
此处我用的flashDevelop创建的一个Flash IDE Project,用的是FlashCS4编译运行,不知道这个是不是一个bug呢?有遇到过此类问题的朋友还请不吝赐教。

97-109行:显示box2d的debug模式。

122行:寻找鼠标点击处的刚体。

125-131行:创建一个mouseJoint,用来拖动刚体。创建mouseJoint跟刚体一样,先要创建mouseJointDef的各个参数。

      body1:值为_world.GetGroundBody(),_world.GetGroundBody()具体表示的是哪一个刚体,本人还未明白,看源代码注释不是很清楚,如果您明白还请不吝赐教啊!

      body2:鼠标点击处的刚体。

      maxForce:拖动刚体时铰链给刚体的最大力,box2d会根据这个力来计算刚体被拖动的最大速度及位移,使得刚体始终处于鼠标的控制之下,实际这里的拖动,并不像flash中拖动一个显示对象用startDrag()或者设置对象的坐标为鼠标的坐标,box2d中考虑了更多复杂的运动参数,有加速度,质量,动量,冲量等。

      timeStep:box2d模拟屋里世界的时间片,一般取swf文件帧频的倒数。

      target:目标位置,设置为鼠标位置。在EnterFrame事件中更新目标。

原文地址:https://www.cnblogs.com/ywxgod/p/1710676.html