Many games today use a blend of animations and physics to create realistic movement. For animated characters, this revolves around balance. It could take the shape of a runner who leans inwards through a curve to counter the centrifugal force. Creating a system like this is not easy and requires a lot of tweaking. In this recipe, we'll look into some of the fundamentals of this, and we'll create a new Control
class that will try to balance itself using the rotational motors of SixDofJoint
.
To simulate balancing, we will begin by creating the upper body of a stickman-shape figure with a torso and two rigid arms. To do this, perform the following set of steps:
BulletAppState
.simpleInitApp
method, we create a small square Box Geometry
to be the waist of the character. It can be 0.25f
in all the axes.RigidBodyControl
to it with 0
in mass since it shouldn't move.RigidBodyControl
with 1
in mass and BoxCollisionShape
should be of the same size as the geometry:torso = new Geometry("Torso", new Box(0.25f, 2f, 0.25f); RigidBodyControl torsoRigidBody = new RigidBodyControl(new BoxCollisionShape(...), 1f); ... torsoRigidBody.setPhysicsLocation(new Vector3f(0, 4.25f, 0));
SixDofJoint
between the waist and torso and afterwards add it to physicsSpace
as follows:SixDofJoint waistJoint = new SixDofJoint(waistRigidBody, torsoRigidBody, new Vector3f(0, 0.25f, 0), new Vector3f(0, -2.25f, 0f), true);
setAngularLowerLimit
and setAngularUpperLimit
methods for this:waistJoint.setAngularLowerLimit(new Vector3f(-FastMath.QUARTER_PI * 0.3f, 0, 0)); waistJoint.setAngularUpperLimit(new Vector3f(FastMath.QUARTER_PI * 0.3f, 0, 0));
Vector3f(0.25f, 0.25f, 2f)
, making it stretch out sideways, as shown in the following code snippet:leftArm = new Geometry("Left Arm", new Box(0.25f, 0.25f, 2f); RigidBodyControl leftArmRigidBody = new RigidBodyControl(new BoxCollisionShape(...), 1f); ... leftArmRigidBody.setPhysicsLocation(new Vector3f(0, 4.25f, 0));
SixDofJoint
for it using the pivot points of Vector3f(0, 2.5f, 0.25f)
and Vector3f(0, 0, -2.5f)
, offsetting it some distance to the side of the torso's spatial.Vector3f(0, 0, 0)
and Vector3f(FastMath.QUARTER_PI, 0, 0)
.We now have the basics done for our recipe. Running it should show the character slumping to one side with the arms stretched out to the sides. Now, we can begin with balancing by performing the following steps:
BalanceControl
, extending AbstractControl
.SixDofJoint
field called joint
and a RotationalLimitMotor
field called motorX
.setJoint
method.motorX
with one of the RotationalLimitMotor
instances, as follows:motorX = joint.getRotationalLimitMotor(0);
controlUpdate
method, we get bodyA
from the joint and store it in PhysicsRigidBody
. This is the torso:PhysicsRigidBody bodyA = joint.getBodyA();
bodyA
to see how much it pivots. We then convert the rotation to angles and store them as follows:float[] anglesA = new float[3]; bodyA.getPhysicsRotation().toAngles(anglesA);
angles[0]
in a float variable called x
.x
is more than 0.01f or less than -0.01, we should start motorX
and rotate it to compensate for the pivot, as follows:motorX.setEnableMotor(true); motorX.setTargetVelocity(x*1.1f); motorX.setMaxMotorForce(13.5f);
motorX.setTargetVelocity(0); motorX.setMaxMotorForce(0);
Running the result, we should see the stickman desperately trying to stay upright while flailing his arms up and down. The reason is that getting the forces right when balancing can be very difficult. With values that are too high, the stickman will constantly overshoot the target and instead rotate in the other direction. With values that are too low, it won't have the strength to get upright. With some further tweaking to targetVelocity
and maxMotorForce
, we might be able make him stable.
We started by creating the basic shape of a figure that would try to keep the balance. The waist was made to not be affected by the physics, so it could be a solid point. We then added a torso and two arms, resulting in a center of mass somewhere in the upper part of the torso. By placing each of the body parts at some distance from each other with the joints, we give them more freedom of movement.
The BalanceControl
class we created has one simple strategy. It looks for the torso (bodyA)'s rotation along the x axis, and tries to keep it as close to 0 as possible. If it notices that it's anything but near 0, it will try to move the arms, shifting the center of the mass to the opposite direction.
Despite the low number of components, getting it all to balance out is really difficult! Having more components, such as a whole human skeleton, requires a much more advanced strategy, with body parts moving in a synchronized fashion, rather than they trying to do so individually.
18.188.61.81