Most developers who use the Box2D-based Corona physics engine understand physical bodies, body types, body methods/properties, collision handling, etc. However, even some experienced developers struggle with the setup of physical joints which are used to attach two bodies. While the most basic joints are easy to configure, others are more complex and require a very specific setup, plus a thorough understanding of the properties and methods associated with each joint type.
In part 1 of this tutorial, we discussed five of the ten physics joints available in Corona: pivot, distance, piston, friction, and weld. In this part, we’ll explore the remaining five joint types:
- Wheel joint
- Pulley joint
- Touch joint
- Rope joint
- Gear joint
Creating and destroying joints
In Corona, most joints are used to connect two rigid physical bodies, so you must create these bodies first and then submit them as arguments to the physics.newJoint() constructor function. This function accepts the joint type (string) as the first parameter, followed by other properties which vary depending on the joint type.
physics.newJoint( jointType, … )
display.remove( joint )
Note that if one of the joined bodies is destroyed, the associated joint will be automatically destroyed. However, remember to properly remove and
nil any references to a joint which has been destroyed.
An often misunderstood joint is the wheel joint, known as a line joint in Box2D terms. This joint is similar to a piston joint, except that the attached body can rotate freely. This means that you can combine the “axis of motion” principal of the piston joint with an object that can rotate freely, like a wheel mounted to the shock absorber of a car.
Most of the wheel joint properties are inherited from the standard piston joint, but you can specify a mass-spring frequency and damping ratio for the axis portion.
The additional arguments for the physics.newJoint() constructor are bodies A and B to join, followed by an x and y coordinate for an anchor point on either body, followed by values which define the axis along which linear motion is allowed.
physics.newJoint( "wheel", bodyA, bodyB, anchor_x, anchor_y, axisX, axisY )
Like the piston joint, wheel joints have a restricted axis of linear motion, defined by
axisY. This axis is bi-directional and should not be considered as a directional vector. For example, setting these values to either
0,-1 will restrict motion to a vertical axis, but not restrict it to either upward or downward along that axis. Similarly, values of either
-1,0 will restrict linear motion to either left or right along a horizontal axis.
As stated, the wheel joint can be made soft, like a spring-damper connection. Many factors can influence the behavior of a soft wheel joint, including the mass of the attached bodies and forces upon them, so you should carefully test the specified values to achieve the desired simulation.
Please see the guide for details on setting damping and frequency values.
The pulley joint attaches two bodies with an imaginary rope whose length remains constant. If one body is pulled or pushed by some force, the other body will compensate according to the simulated rope.
The pulley joint requires a wide array of arguments in the physics.newJoint() constructor, but these are simple enough to understand. These arguments are bodies A and B to join, followed by two coordinate pairs which represent the stationary anchor points from where each side of the rope hangs.
The next four arguments are the x and y anchor point coordinates (one for each body).
The final argument is the ratio value which can be adjusted to simulate a block and tackle setup. In such a scenario, one side of the pulley rope moves faster than the other. The default ratio is
1.0 which simulates a simple pulley — this means that any movement on one side will be inversely but proportionally reflected on the other side.
physics.newJoint( "pulley", bodyA, bodyB, statA_x, statA_y, statB_x, statB_y, bodyA_x, bodyA_y, bodyB_x, bodyB_y, 1.0 )
Please see the guide for complete details on the pulley joint.
The touch joint, known as a mouse joint in Box2D terms, connects a single object to an on-screen target point. This can be used to move an object to a target point by a theoretical elastic joint with variable strength and elasticity. Note that this point is not the user’s touch as a strict requirement — in fact, it can be any coordinate point you wish.
The additional arguments for the physics.newJoint() constructor are body A to connect followed by the x and y anchor point coordinates in content space. This anchor point can be considered the point at which to “connect” the body. Although this point is commonly configured as a point within the bounds of the body, it can reside outside the body’s bounds if desired.
physics.newJoint( "touch", body, anchor_x, anchor_y )
The target-following behavior of a touch joint is set by passing x and y coordinates to the touchJoint:setTarget() function. This can be any specific content point, the location of the user’s touch, the coordinates of some other object to follow, successive points along a path, etc.
touchJoint:setTarget( targetX, targetY )
As stated, the touch joint has variable strength and elasticity based on various properties, including
maxForce. The actual behavior will depend on the mass of the attached body and other forces upon it, so you should carefully test the specified values to achieve the desired simulation.
Please see the guide for details on these values.
The rope joint connects two objects by a theoretical non-elastic rope. This restricts the maximum distance between the two bodies even if there are other significant forces upon them.
The additional arguments for the physics.newJoint() constructor are bodies A and B to join, followed by optional localized offset points which can be used to set non-center anchor points for each end of the rope.
physics.newJoint( "rope", bodyA, bodyB, offsetA_x, offsetA_y, offsetB_x, offsetB_y )
When configuring a rope joint, the offset values are optional and default to
0 unless set otherwise. Unlike other joints, these x and y values should not be specified in content space. Instead, they should be considered as localized offset values relative to either body. For example, if you specify
( ..., 0, 0, 0, 0 ), the rope ends will be attached to the center of each body. However, if you specify
( ..., -20, -20, 10, 10 ), the rope end attached to body A will be offset 20 pixels left and upward of its center point, while the rope end attached to body B will be offset 10 pixels right and downward of its center point.
The maximum length of the rope can be set via the ropeJoint.maxLength property. Unlike the distance joint which can be used to keep two bodies at a fixed distance apart, the theoretical rope can bend/flex like an actual rope, but the maximum distance will always be constrained to this value.
Please see the guide for complete details on the rope joint.
Of all physical joints, the gear joint is the most complex, but perhaps the most interesting. This joint can be used to simulate sophisticated mechanical contraptions involving gears or toothed bars. Then, one motor-driven body can realistically power the other bodies just like a real machine.
The most important distinction of the gear joint is that it operates directly upon two other joints. These two joints must be created before instantiating the gear joint, and they must be either pivot or piston joints. Once declared, one of pivot/piston joints can be powered by its motor and impact the other pivot/piston joint attached to the parent gear joint. The same principle applies to successive joints in a more complex chain configuration, assuming they are properly chained together by other gear joints.
physics.newJoint( "gear", bodyA, bodyB, joint1, joint2, ratio )
Another important aspect of the gear joint is the
ratio property. This indicates the ratio at which the motor-driven joint drives the corresponding joint in the gear configuration. The value can be either positive or negative, depending on the direction required to create an accurate simulation. Setting the correct ratio can be challenging when setting up a pivot-joined object which drives a piston-joined object, as shown in the diagram. In this case, the gear joint ratio between wheel B and wheel C are
1.0 since wheel B directly drives C. However, you must calculate the ratio for the gear joint which links wheel C to the vertical bar (D), and because wheel C has a larger circumference than wheel B, this ratio would not be
Please see the guide for further details on the gear joint.
Hopefully this tutorial has explained and illustrated the five described physics joints. While implementing joints may seem complicated, focusing on the proper configuration and setting the proper values for all parameters should yield the desired behavior.
If you missed part 1 of this tutorial series, please click over to learn about pivot, distance, piston, friction, and weld joints.