Box2D 关节——”马达关节” b2RevoluteJoint

昨天我们学习了 Box2D 的“距离关节”b2DistanceJoint,并用它模拟了一个简单的自行车。今天我们来学习”马达关节” b2RevoluteJoint 。

“马达关节”b2RevoluteJoint同样连接了两个刚体bodyA和bodyB。不过和”马达关节”不同的是,它只有一个节点anchor,所以两个刚体都只能围绕这一个节点选择。另外,我们可以在这个节点anchor位置施加一个作用力maxMotorTorque,这样节点就会想马达一样转起来,所以我把它叫做”马达关节”。

还是不好理解,对吧!那就再打个比方,我把b2RevoluteJoint关节比作….电风扇。风扇叶是bodyA,马达是anchor,底座是bodyB,下面的图可以更好的解释这一点:

b2RevoluteJoint

如上图所示,因为节点anchor在bodyA的圆心处,所以bodyA会围绕着节点anchor旋转。

b2RevoluteJoint的initialize方法结构如下:

	public function Initialize(
		bA:b2Body,
		bB:b2Body,
		anchor:b2Vec2
	) : void

bA即bodyA,bB即bodyB,anchor即节点,具体的功能,我在前面都讲过了,就不再赘述了。

另外,如前面提到的,通过设置b2RevoluteJointDef的maxMotorTorque、motorSpeed和enableMotor,可以模拟马达旋转。这三个参数的作用分别如下:

  • enableMotor:决定是否使用motor
  • motorSpeed:设置最大的角速度
  • maxMotorTorque:要达到角速度应用的扭矩力

这三个属性是让节点转起来的必要条件,缺一不可!记住哦。

用b2RevoluteJoint实现风扇的效果如下:

完整的代码和注释如下:

 

package
{
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	import Box2D.Dynamics.Joints.b2RevoluteJoint;
	import Box2D.Dynamics.Joints.b2RevoluteJointDef;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	/**
	 * http://www.ladeng6666.com
	 * @author ladeng6666
	 */
	public class RevoluteJointTest extends Sprite
	{
		private var world:b2World;
		private var debugSprite:Sprite;
		private var bodyA:b2Body, bodyB:b2Body;
		private var posA:Point, posB:Point;

		public function RevoluteJointTest()
		{
			LDEasyBox2D.stage = stage;
			world=LDEasyBox2D.createWorld();
			debugSprite=LDEasyBox2D.createDebug(world);
			addChild(debugSprite);

			//创建地面,
			LDEasyBox2D.createWrapWall(world, stage);
			createBodies();

			createRevoluteJoint();

			addEventListener(Event.ENTER_FRAME, loop);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
		}

		private function createRevoluteJoint():void
		{
			//创建马达关节需求
			var revoluteJoint:b2RevoluteJointDef = new b2RevoluteJointDef();
			//用bodyA、bodyB和anchor节点初始化马达关节
			revoluteJoint.Initialize( bodyA, bodyB, new b2Vec2(posA.x / 30, posA.y / 30));
			//设置连接的两个刚体之间不进行碰撞检测
			revoluteJoint.collideConnected = false;
			//开启马达
			revoluteJoint.enableMotor = true;
			//设置马达的最大角速度,单位为 弧度/秒,如设置为Math.PI,即每秒钟转180度
			revoluteJoint.motorSpeed = Math.PI;
			//设置最大的扭力值
			revoluteJoint.maxMotorTorque = 500;
			//创建马达关节
			world.CreateJoint(revoluteJoint);
		}
		//创建bodyA和bodyB刚体
		private function createBodies():void
		{
			//设置两个刚体的坐标位置
			posA = new Point(275, 100);
			posB = new Point(275, 300);
			//创建一个十字刚体,赋值给bodyA
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type = b2Body.b2_dynamicBody;
			bodyDef.position.Set(posA.x / 30, posA.y / 30);
			bodyA = world.CreateBody(bodyDef);
			//设置刚体属性
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.density = 3;
			fixtureDef.restitution = .2;
			fixtureDef.friction = .2;

			//设置刚体形状,并赋值给fixtureDef
			//一个横着的矩形
			var shape:b2PolygonShape = new b2PolygonShape();
			shape.SetAsBox(50/30, 5/30);
			fixtureDef.shape = shape;
			bodyA.CreateFixture(fixtureDef);
			//加一个竖着的矩形
			shape.SetAsBox(5 / 30, 50 / 30);
			fixtureDef.shape = shape;
			//生成刚体bodyA的形状
			bodyA.CreateFixture(fixtureDef);

			//创建bodyB刚体
			bodyB = LDEasyBox2D.createBox(world, posB.x, posB.y, 200, 50);
		}

		private function onStageMouseDown(e:MouseEvent):void
		{
			var dragBody:b2Body = LDEasyBox2D.getBodyAtMouse(world);
			if (dragBody != null) {
				LDEasyBox2D.startDragBody(world,dragBody,10000*dragBody.GetMass());
			}

		}

		private function onStageMouseUp(e:MouseEvent):void
		{
			LDEasyBox2D.stopDragBody(world);
		}

		private function loop(e:Event):void
		{
			LDEasyBox2D.updateWorld(world);

		}

	}

}

代码中用到了我写的静态类LDEasyBox2D,可以有效的简化代码,具体请参考这里

点击刚体,还可以进行拖动,如果对鼠标拖动刚体,我建议你看看之前的让刚体听我的——鼠标拖动刚体

 源代码下载

联系作者

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

5 Replies to “Box2D 关节——”马达关节” b2RevoluteJoint”

  1. 拉登兄, 文中

    //设置马达的最大角速度,单位为 弧度/秒,如设置为Math.PI,即每秒钟转180度
    revoluteJoint.motorSpeed = Math.PI;

    如果用以下代码代替应该也有类似的效果。
    body.SetAngle(angle);
    body.SetAngularVelocity(Math.PI);

    另外,关于

    motorSpeed:设置最大的角速度
    maxMotorTorque:要达到角速度应用的扭矩力

    motorSpeed设置角速度可以理解,那么maxMotorTorque和角速度到底有什么关系呢? 推动力还是阻力?我不太清楚这个属性的具体意义。

  2. 你设置角度的方法也是正确的。
    关于maxMotorTorque是指要达到指定的角度的,可以施加的最大扭力。示例中,固定了底座,风扇可以转,但是固定了风扇,底座是不会绕着风扇转的,因为maxMotorTorque的力度不够,无法转动底座!

  3. 拉登大叔,您好,我是box2dweb新手,请问您有没有尝试在box2dweb中添加ropeJoint功能?

回复 ladeng6666

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