🔗LBJT: Motor Joint 1️⃣2️⃣.

LibGDX Box2d Joints Tutorials.

Vladislav Shesternin
5 min readJan 6, 2024
LBJT Application: Download for ease of study!
Motor Joint

Text separators are set using chatGPT.

This article is about the Motor Joint, its settings, and how to make it work.

To make it easier to understand what is happening and how to perform practical tasks, start with the article: 🔗LBJT: Сommon in Joints 1️⃣.

And so the… Motor Joint

Motor joint — a joint designed to connect two bodies together used as a magnet.

First, we need to set up the joint. For this, each joint has its own implementation of JointDef. You can read about this in the article: 🔗LBJT: Common in Joints 1️⃣. And now let’s talk about the MotorJointDef.

MotorJointDef settings:

(Mandatory)

  • bodyA — first joint body.
  • bodyB — second joint body.
  • collideConnected — <boolean> Specifies whether bodyA should collide with bodyB.

(Optional)

  • linearOffset— similar to a localAnchorA, bodyB will be attracted to it.
  • angularOffset — similar to a referenceAngle, initial angle between bodyA and bodyB, (default 0 | measured in radians).
  • maxForce — the force required to attract bodyB. Usually expressed as (multiplier * mass * gravity) = (500 * bodyB.mass * world.gravity ). I personally usually do this for tests (500 * bodyB.mass).
  • maxTorque — torque is required to return to the original position.
  • correctionFactor — the value of which depends on how quickly bodyB will return to its initial position.

Practice. How to create a Motor Joint?

In order for you to be able to test Joints, you need to interact with bodies, for this you need to implement MouseJoint. How to implement it is described in article 🔗LBJT: Mouse Joint 2️⃣.

Our example will consist of a static circle (blue) and a dynamic circle (green) connected by MotorJoint.

Motor Joint

1️⃣Create 2 bodies: a static circle and a dynamic circle:

val staticCircle  = StaticBody
val dynamicCircle = DynamicBody

2️⃣Create MotorJoint:

world.createJoint(MotorJointDef().apply {
bodyA = staticCircle
bodyB = dynamicCircle
collideConnected = false
}

Note that collideConnected = false, this is done so that the connected bodies do not touch each other.

3️⃣Configure: maxForce:

  • If the force is very small, bodyB will not be attracted.
  • If the force is greater than the force indicated in MouseJoint, then you will not be able to move the bodyB from its place.
world.createJoint(MotorJointDef().apply {
...
maxForce = 300f * bodyB.mass
}
MotorJoint maxForce

As we can see, maxForce is sufficient to return bodyB to its initial position. But it spins for a long time, to fix it, you need to configure maxTorque.

4️⃣Configure: maxTorque:

  • If the torque is very small, bodyB will not return to original angle.
  • If the torque is greater than the force indicated in MouseJoint, then you won’t be able to change the angle of bodyB.
world.createJoint(MotorJointDef().apply {
...
maxTorque = 5_000f
}
MotorJoint maxTorque

As you can see, the body does not immediately return to its original position, now it works as if it is attached by a spring, in order to configure the stiffness, so to speak, of this spring, it is necessary to configure correctionFactor.

5️⃣Configure: correctionFactor:

correctionFactor is set to values from 0 to 1 (default 0.3).

  • 0 — is not attracted to the initial position at all.
  • 1 — it is attracted to the initial position for a long time like a soft spring.
  • < 0 — is infinitely repelled from the initial position as if the same side of the magnet.
  • > 1 — for a very long time it is attracted to the initial position like a very soft spring.

6️⃣Configure: linearOffset:

By default, bodyB is attracted to the center of mass of bodyA, to change this you need to configure linearOffset.

Configured in the same way as localAnchorA.

world.createJoint(MotorJointDef().apply {
...
linearOffset.set(5f, 5f)
}

Do not forget that the values are indicated in meters.
How to calculate anchor points and about the units of measurement of meters, kilograms, seconds (MKS) is written in the article: 🔗LBJT: Сommon in Joints 1️⃣.

MotorJoint linearOffset

7️⃣Configure: angularOffset:

angularOffset — simply changes the angle of the initial position to which bodyB will return.

const val PI: Double = 3.141592653589793
const val DEGTORAD = (PI / 180f).toFloat()

world.createJoint(MotorJointDef().apply {
...
angularOffset = 90f * DEGTORAD
}

To convert radians to degrees, we need to multiply the radians by our constant:

const val PI: Double = 3.141592653589793
const val RADTODEG = (180f / PI).toFloat()

val degrees = body.angle * RADTODEG

Do not forget that all angles in Box2d are measured in radians.

Clockwise negative angles.
Counter-clockwise are positive angles.

MotorJoint angularOffset

That’s all, friends, the series of articles LBJT has come to an end, thank you for reading to this point, I hope it helped you understand how they work and how to use Joints Box2d in LibGDX.

Everything will be Wonderful😉.

Thanks to all.

PS. Vel_daN: Love what You DO 💚.

--

--