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连接的位置,看看下面的图示,可以更好理解:
实际上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实现的鼠标关节。步骤大致如下:
- 当鼠标点击时,创建示例3中的关节。
- 当鼠标移动时,设置第一个刚体的anchor1为鼠标当前位置
- 鼠标弹起时,设置PivotJoint.active = false,停止关节模拟
同样鼠标拖动的效果也继承了LDEasyNape中了,只需要根据鼠目标动作调用startDragBody()和stopDragBody()就可以轻松实现鼠标拖动了。
联系作者
大叔v5,一直在关注,希望教程越出越快,哈哈!!
感谢ladeng大师的教程,请问:PivotJoint如何销毁?PivotJoint.active=false吗?PivotJoint如何触发CbEvent.BREAK状态?谢谢!
一个球被拉着去撞击另一个球,有没有办法控制控制撞击的冲量大小哦。。。
可以试着将刚体的密度降低一点。或者在CollisionArbiter中,降低elasticity属性。关于CollisionArbiter的内容,请参考http://www.ladeng6666.com/blog/2014/10/27/what-is-arbiter/
恩。我加了个判断 collisionArbiter.elasticity > 0.1 的时候把它设置为0.1了