用马达关节创建Box2D锁链效果
今天我们来学习Box2D锁链效果。这个效果并不难,记得我们学过的Box2D 关节——”马达关节” b2RevoluteJoint吗?锁链效果其实就是用多个b2RevolueJoint连接多个刚体,很简单吧!
简单在用多个关节连接多个刚体,难也难在这里。我们还是先来看看效果吧。在下面的效果中我创建了两个锁链,一个是小桥,另一个是连接了一个圆形刚体的锁链。鼠标可以点击并拖动下面的刚体。
[swfobject]665[/swfobject]
看过效果之后,我想你肯定也想到了,要用for循环来创建锁链。要用for循环就要有可以重复执行的过程,仔细想想这个过程并不难。
创建当前的刚体body,指定节点的位置anchor,创建节点为anchor的关节,链接当前刚体body和前一个刚体preBody。如下图所示。图中虚线框内是fox循环要重复执行的过程。anchor1用来连接preBody和Body。相信可能有人会跟我一样,犯下面的错误,把关节点设置为body的中心点。这样旋转后,会出现图中下面的效果。因为preBody和body都是围绕anchor1旋转的嘛,想想风扇效果?!
正确的做法是像下图一样,创建当前刚体时body时,让它偏移anchor1一点,偏移多少呢?最好是刚体的一半,这样节点就移到了刚体的边缘处了。旋转之后就会像图中下面的效果一样自然了。
另外设置刚体的宽度为两个节点之间的间距,这样刚体之间会紧密相连,效果就跟上的SWF示例一样了!
完整的代码和注释如下:
package { import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2World; import Box2D.Dynamics.Joints.b2RevoluteJointDef; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; /** * ... * @author ladeng6666 */ public class Bridge extends Sprite { private var world:b2World; public function Bridge() { //初始化,创建世界,添加事件侦听等等 init(); //创建小桥锁链 createBridge(); //创建一个可以拖动的锁链 creaetLinkage(); //随机创建几个刚体 createBodies(); } private function init():void { //初始化世界 world = LDEasyBox2D.createWorld(); addChild(LDEasyBox2D.createDebug(world)); LDEasyBox2D.stage = this; LDEasyBox2D.createWrapWall(world,this); //添加事件侦听 addEventListener(Event.ENTER_FRAME, loop); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHandler); } //拖动刚体 private function mouseEventHandler(e:MouseEvent):void { if (e.type == MouseEvent.MOUSE_DOWN) { var body:b2Body = LDEasyBox2D.getBodyAtMouse(world); if (body != null) { LDEasyBox2D.startDragBody(world, body); } }else if (e.type == MouseEvent.MOUSE_UP) { LDEasyBox2D.stopDragBody(world); } } //更新世界 private function loop(e:Event):void { LDEasyBox2D.updateWorld(world); } private function createBodies():void { //随机创建刚体 for (var i:int = 0; i < 10; i++) { if (Math.random() > 0.5) { LDEasyBox2D.createBox(world, Math.random() * 300 + 100, 100, Math.random() * 20 + 10, Math.random() * 20 + 10); }else { LDEasyBox2D.createCircle(world, Math.random() * 300 + 100, 100, Math.random() * 10 + 10); } } } private function creaetLinkage():void { //设置第一节刚体开始的位置 var initx:Number = 150; var inity:Number = 50; //两个节点之间的间距 var gapBetweenAnchor:Number = 30; //定义节点 var anchor:b2Vec2=new b2Vec2(); //当前刚体 var body:b2Body; //前一个刚体 var preBody:b2Body; //设置前一个刚体是一个圆形刚体,这个刚体不在for循环范围内, //但是要在for循环里引用,所以在这里预先定义好 preBody = LDEasyBox2D.createCircle(world, initx, inity, 15); //定义关节 var revoluteJoint:b2RevoluteJointDef = new b2RevoluteJointDef(); for (var i:int = 0; i < 4; i++) { //循环创建刚体,它们的x坐标都基于节点的位置向右偏移15个像素(也就是刚体的半宽) body = LDEasyBox2D.createBox(world, initx + i * gapBetweenAnchor+15, inity, gapBetweenAnchor, 5); //设置节点的坐标 anchor.Set((initx + i * gapBetweenAnchor) / 30, inity / 30); //初始化关节 revoluteJoint.Initialize( preBody, body, anchor); world.CreateJoint(revoluteJoint); //设置preBody引用当前的刚体 preBody = body; } } private function createBridge():void { //设置第一节刚体开始的位置 var initx:Number = 100; var inity:Number = 250; //两个节点之间的间距 var gapBetweenAnchor:Number = 50; //定义节点 var anchor:b2Vec2=new b2Vec2(); //当前刚体 var body:b2Body; //前一个刚体 var preBody:b2Body; //在for循环之外预先定义第一个刚体,定义成GetGroundBody,固定锁链的起点 preBody = world.GetGroundBody(); //定义关节 var revoluteJoint:b2RevoluteJointDef = new b2RevoluteJointDef(); for (var i:int = 0; i < 6; i++) { //循环创建刚体,它们的x坐标都基于节点的位置向右偏移15个像素(也就是刚体的半宽) body = LDEasyBox2D.createBox(world, initx + i * gapBetweenAnchor+25, inity, gapBetweenAnchor, 10); //设置节点的坐标 anchor.Set((initx + i * gapBetweenAnchor) / 30, inity / 30); //初始化关节 revoluteJoint.Initialize( preBody, body, anchor); world.CreateJoint(revoluteJoint); //设置preBody引用当前的刚体 preBody = body; } //设置最后一个节点 anchor.Set((initx + i * 50) / 30, inity / 30); //将最后一个节点链接到GetGroundBody,固定锁链的终点 revoluteJoint.Initialize( preBody, world.GetGroundBody(), anchor); world.CreateJoint(revoluteJoint).GetAnchorB().x; } } }
值得注意的是第121行和139行,将关节的起点和终点设置成了GetGroundBody()返回的刚体,用来固定住这两个位置,模拟小桥的效果。关于GetGroundBody()的用法请参考Box2D如何固定动态刚体
源文件下载地址
联系作者
哈哈。最近教程更新挺快的~
拉登兄,怎么使用键盘控制世界中物体的旋转,以中心点为旋转。
设置刚体的角速度就好了,查一下API我记得有这么个函数的
拉登兄,你好,想请教一下,如何让一些物体的碰撞给过滤掉。我最近做了个东西就如同你的“桥”的做法,我做了4跟单头锁定的飘带并加了关节,但我不希望2根飘带之间碰撞,但同时又希望飘带自身是联动的。我尝试了简历几个世界但失败了,你能教教我怎么实现吗?谢谢
你应该已经在我的网站上找到相关的教程了,希望你能继续关注。
一个节点可以创建多个关节吗?
不可以,一个关节只能连接两个关节!
您好,请问怎样隐藏关节?
谢谢您的回答
谢谢你的关注,隐藏关节有两种方法,一种是有b2DebugDraw,这时可以通过设置b2DebugDraw的绘制选项可以设置,具体可以参考b2DebugDraw到底是什么,如果没有b2DebugDraw的话,不会只关节的userData就可以了。
请教,我做了一个绳索桥,绑定方法如下,但是当我的主角走在桥上的时候,绳索就会断成一节一节的。。 ,怎么破?
b2RevoluteJointDef jointDef;
jointDef.Initialize(body1, body2, body1->GetWorldPoint(ToMeter1(anchor1)));
m_world->CreateJoint(&jointDef);