PivotJoint关节实现Nape刚体拖动

Nape中的关节与Box2D有很多相似之处,但也有不同之处,例如今天我们要学到的PivotJoint,从效果上来看,它和Box2D中的ProvitJoint类似。但是同时它还可以实现MouseJoint的功能。具体怎么实现呢,继续往下看!

如果是第一次接触”关节”这个概念,建议你先看看一下我的Box2D初始关节这篇文章,对关节先有个初步的认识。

PivotJoint关节通过一个指定的节点anchor,将两个不同的刚体连接到一起,刚体可以以固定的距离绕这个节点anchor旋转。下面是PivotJoint的构造函数:

public function PivotJoint(
	body1:Body,
	body2:Body,
	anchor1:Vec2,
	anchor2:Vec2):void

body1和body2是节点anchor链接的两个不同的刚体,anchor1和anchor2是指…

“拉登大叔忽悠人,不是只有一个节点anchor吗?怎么构造函数里有两个节点anchor1和anchor2啊?”

大叔我还没讲完呢,别打岔!

构造函数里的两个节点anchor1和anchor2,是两个Vec2类型的向量,指节点分别是指anchor相对于两个刚体本地坐标系统的位置。通过设置整个两个节点调整刚体与节点anchor连接的位置,看看下面的图示,可以更好理解:

Nape_PivotJoint

实际上anchor1和anchor2是相同的,anchor对于body1叫做anchor1,对于body2叫做anchor2,对于我们来讲,就只有一个anchor。

直接在PivotJoint的构造函数中设置anchor1和anchor2 是比较困难的,很难按照我们的期望实现效果。常用的方法是从我们的角度定义好关节的anchor,布置好刚体,然后再通过Body. worldPointToLocal()方法,将anchor转换成相对于刚体本地坐标系统的坐标,然后传入到PivotJoint的构造函数中,具体举例如下:

       //PivotJoint关节的节点
       var anchor : Vec2 = new Vec2(100,100);
       //anchor相对于body1的本地坐标
       var anchor1 : Vec2 = body1.worldPointToLocal(anchor);
       //anchor相对于body2的本地坐标,
       var anchor2 : Vec2 = body2.worldPointToLocal(anchor));
       //创建图中所示的PivotJoint关节
       var joint : Pivotjoint = new PivotJoint(
                                       body1,
                                       body2,
                                       anchor1,
                                       anchor2);

了解了PivotJoint关节创建方法,下面我们来看看具体的示例吧!

[swfobject]825[/swfobject]

在下面的SWF中,创建了包含鼠标关节在内的4中PivotJoint示例,点击并拖动刚体试试吧!

示例中用到了LDEasyNape来简化创建过程,如果你不熟悉LDEasyNape,请参考这里。

完整的代码和解释如下:

示例1 蓝色刚体的关节

		private function createJoint1() : void {
			var body1:Body=LDEasyNape.createBox(X1-50,Y2,50,50,false,false,autoGraphic);
			var body2:Body=LDEasyNape.createCircle(X1+50,Y2,20,false,false,autoGraphic.clone());
			body1.force.set(napeWorld.gravity.mul(-body1.gravMass,true));
			body2.force.set(napeWorld.gravity.mul(-body2.gravMass,true));

			var anchor:Vec2=new Vec2(X1,Y1);
			var joint : PivotJoint = new PivotJoint(
											body1,
											body2,
											body1.worldPointToLocal(anchor),
											body2.worldPointToLocal(anchor));
			joint.space = napeWorld;
		}

这是最基本的PivotJoint关节,和前面举的示例是一样的,我就不重复了。

第4~5行:给刚体添加一个反重力的作用力,让刚体不做自由落体运动。

示例2 红色刚体的关节

		private function createJoint2() : void {
			autoGraphic.setGraphicAuotmatically(0xFF0000);
			var body1:Body = napeWorld.world;
			var body2:Body=LDEasyNape.createCircle(X3-100,Y2,40,false,false,autoGraphic.clone());
			var anchor:Vec2=new Vec2(X3,Y1);
			var joint : PivotJoint = new PivotJoint(
											body1,
											body2,
											body1.worldPointToLocal(anchor),
											body2.worldPointToLocal(anchor));

			joint.space = napeWorld;
		}

示例中关节只连接了一个红色的圆形刚体。实际上依然是两个刚体,不过其中一个引用了space.world返回的空刚体。空刚体是Nape中不可以修改的、不参加碰撞检测的、静止的刚体,可以像本例中用来连接关节等。

第3行:设置刚体body1为napeWorld.world,引用空刚体,将这个点固定住。

示例3 绿色刚体的关节

		private function createJoint3() : void {
			autoGraphic.setGraphicAuotmatically(0x00FF00);
			var body1:Body = napeWorld.world;
			var body2:Body=LDEasyNape.createBox(X4,Y1+90,20,200,false,false,autoGraphic.clone());
			var anchor:Vec2 = new Vec2(X4,Y1);
			var joint : PivotJoint = new PivotJoint(
											body1,
											body2,
											body1.worldPointToLocal(anchor),
											body2.worldPointToLocal(anchor));

			joint.space = napeWorld;
		}

这个示例和上面红色刚体关节实质上是一样的,不同之处是在初始化时,把anchor放到了刚体内部,这样刚体仿佛是被钉在了墙上。

同时我也将这个过程集成到了LDEasyNape.fixBodyAt()方法中,上面的代码用LDEasyNape简化为:

			autoGraphic.setGraphicAuotmatically(0x00FF00);
			var body2:Body=LDEasyNape.createBox(X4,Y1,20,200,false,false,autoGraphic.clone());
			LDEasyNape.fixBodyAt(body2, X4, Y1, 0, -90);

 

示例4 鼠标关节

		private function createMouseJoint() : void {
			var body1:Body = napeWorld.world;
			mousePivot = new PivotJoint(
											body1,
											null,
											Vec2.weak(X3,Y1),
											Vec2.weak(0,0));
			mousePivot.stiff = false;
		}
		override protected function mouseEventHanlder(event : MouseEvent) : void {
			switch (event.type){
				case MouseEvent.MOUSE_DOWN:
					var body : Body = LDEasyNape.getBodyAtMouse();
					if (body!=null){
						mousePivot.active = true;
						mousePivot.body2 = body;
						mousePivot.anchor1.setxy(mouseX, mouseY);
						mousePivot.anchor2=body.worldPointToLocal(Vec2.weak(mouseX,mouseY));
						mousePivot.space = napeWorld;
						stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseEventHanlder);
					}
					break;
				case MouseEvent.MOUSE_UP:
					if(mousePivot!=null){
						mousePivot.active = false;
					}

					stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseEventHanlder);
					break;
				case MouseEvent.MOUSE_MOVE:
					mousePivot.anchor1.setxy(mouseX, mouseY);
					break;
			}

示例中鼠标拖动效果就是用PivotJoint实现的鼠标关节。步骤大致如下:

  1. 当鼠标点击时,创建示例3中的关节。
  2. 当鼠标移动时,设置第一个刚体的anchor1为鼠标当前位置
  3. 鼠标弹起时,设置PivotJoint.active = false,停止关节模拟

同样鼠标拖动的效果也继承了LDEasyNape中了,只需要根据鼠目标动作调用startDragBody()和stopDragBody()就可以轻松实现鼠标拖动了。

点击下载源文件

联系作者

公众号:拉小登 | 微博:拉登Dony | B站:拉小登Excel

5 Replies to “PivotJoint关节实现Nape刚体拖动”

  1. 感谢ladeng大师的教程,请问:PivotJoint如何销毁?PivotJoint.active=false吗?PivotJoint如何触发CbEvent.BREAK状态?谢谢!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注