import com.jme3.bullet.control.ragdoll.RagdollUtils;
import com.jme3.bullet.joints.SixDofJoint;
import com.jme3.bullet.objects.PhysicsRigidBody;
+import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
*
* @author Normen Hansen and Rémy Bouquet (Nehon)
*/
-public class KinematicRagdollControl implements PhysicsControl, PhysicsCollisionListener {
+public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener {
protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
- protected Map<String, PhysicsBoneLink> boneLinks = new HashMap<String, PhysicsBoneLink>();
- protected Skeleton skeleton;
- protected PhysicsSpace space;
- protected boolean enabled = true;
- protected boolean debug = false;
+ protected List<RagdollCollisionListener> listeners;
+ protected final Set<String> boneList = new TreeSet<String>();
+ protected final Map<String, PhysicsBoneLink> boneLinks = new HashMap<String, PhysicsBoneLink>();
+ protected final Vector3f modelPosition = new Vector3f();
+ protected final Quaternion modelRotation = new Quaternion();
protected PhysicsRigidBody baseRigidBody;
- protected float weightThreshold = -1.0f;
protected Spatial targetModel;
+ protected Skeleton skeleton;
+ protected RagdollPreset preset = new HumanoidRagdollPreset();
protected Vector3f initScale;
protected Mode mode = Mode.Kinematic;
+ protected boolean debug = false;
protected boolean blendedControl = false;
- protected float blendTime = 1.0f;
+ protected float weightThreshold = -1.0f;
protected float blendStart = 0.0f;
- protected List<RagdollCollisionListener> listeners;
+ protected float blendTime = 1.0f;
protected float eventDispatchImpulseThreshold = 10;
- protected RagdollPreset preset = new HumanoidRagdollPreset();
- protected Set<String> boneList = new TreeSet<String>();
- protected Vector3f modelPosition = new Vector3f();
- protected Quaternion modelRotation = new Quaternion();
protected float rootMass = 15;
protected float totalMass = 0;
- protected boolean added = false;
public static enum Mode {
return;
}
TempVars vars = TempVars.get();
-
+
Quaternion tmpRot1 = vars.quat1;
Quaternion tmpRot2 = vars.quat2;
}
/**
- * Set the transforms of a rigidBody to match the transforms of a bone.
- * this is used to make the ragdoll follow the skeleton motion while in Kinematic mode
+ * Set the transforms of a rigidBody to match the transforms of a bone. this
+ * is used to make the ragdoll follow the skeleton motion while in Kinematic
+ * mode
+ *
* @param link the link containing the bone and the rigidBody
* @param position just a temp vector for position
- * @param tmpRot1 just a temp quaternion for rotation
+ * @param tmpRot1 just a temp quaternion for rotation
*/
- private void matchPhysicObjectToBone(PhysicsBoneLink link, Vector3f position, Quaternion tmpRot1) {
+ protected void matchPhysicObjectToBone(PhysicsBoneLink link, Vector3f position, Quaternion tmpRot1) {
//computing position from rotation and scale
targetModel.getWorldTransform().transformVector(link.bone.getModelSpacePosition(), position);
}
- public Control cloneForSpatial(Spatial spatial) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
/**
- * rebuild the ragdoll
- * this is useful if you applied scale on the ragdoll after it's been initialized
+ * rebuild the ragdoll this is useful if you applied scale on the ragdoll
+ * after it's been initialized, same as reattaching.
*/
public void reBuild() {
- setSpatial(targetModel);
- addToPhysicsSpace();
+ if (added) {
+ removePhysics(space);
+ setSpatial(targetModel);
+ addPhysics(space);
+ } else {
+ setSpatial(targetModel);
+ }
}
+ @Override
public void setSpatial(Spatial model) {
+ super.setSpatial(model);
+ if (added) {
+ removePhysics(space);
+ }
+ boneLinks.clear();
+ baseRigidBody = null;
if (model == null) {
- removeFromPhysicsSpace();
- clearData();
return;
}
targetModel = model;
SkeletonControl sc = model.getControl(SkeletonControl.class);
model.removeControl(sc);
model.addControl(sc);
- //----
- removeFromPhysicsSpace();
- clearData();
// put into bind pose and compute bone transforms in model space
// maybe dont reset to ragdoll out of animations?
scanSpatial(model);
model.setLocalRotation(initRotation);
model.setLocalScale(initScale);
+ if (added) {
+ addPhysics(space);
+ }
logger.log(Level.FINE, "Created physics ragdoll for skeleton {0}", skeleton);
}
/**
- * Add a bone name to this control
- * Using this method you can specify which bones of the skeleton will be used to build the collision shapes.
- * @param name
+ * Add a bone name to this control Using this method you can specify which
+ * bones of the skeleton will be used to build the collision shapes.
+ *
+ * @param name
*/
public void addBoneName(String name) {
boneList.add(name);
}
- private void scanSpatial(Spatial model) {
+ protected void scanSpatial(Spatial model) {
AnimControl animControl = model.getControl(AnimControl.class);
Map<Integer, List<Float>> pointsMap = null;
if (weightThreshold == -1.0f) {
}
}
- private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map<Integer, List<Float>> pointsMap) {
+ protected void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map<Integer, List<Float>> pointsMap) {
PhysicsRigidBody parentShape = parent;
if (boneList.isEmpty() || boneList.contains(bone.getName())) {
/**
* Set the joint limits for the joint between the given bone and its parent.
* This method can't work before attaching the control to a spatial
+ *
* @param boneName the name of the bone
* @param maxX the maximum rotation on the x axis (in radians)
* @param minX the minimum rotation on the x axis (in radians)
}
/**
- * Return the joint between the given bone and its parent.
- * This return null if it's called before attaching the control to a spatial
+ * Return the joint between the given bone and its parent. This return null
+ * if it's called before attaching the control to a spatial
+ *
* @param boneName the name of the bone
* @return the joint between the given bone and its parent
*/
}
}
- private void clearData() {
- boneLinks.clear();
- baseRigidBody = null;
+ @Override
+ protected void setPhysicsLocation(Vector3f vec) {
+ if (baseRigidBody != null) {
+ baseRigidBody.setPhysicsLocation(vec);
+ }
}
- private void addToPhysicsSpace() {
- if (space == null) {
- return;
+ @Override
+ protected void setPhysicsRotation(Quaternion quat) {
+ if (baseRigidBody != null) {
+ baseRigidBody.setPhysicsRotation(quat);
}
+ }
+
+ @Override
+ protected void addPhysics(PhysicsSpace space) {
if (baseRigidBody != null) {
space.add(baseRigidBody);
- added = true;
}
for (Iterator<PhysicsBoneLink> it = boneLinks.values().iterator(); it.hasNext();) {
PhysicsBoneLink physicsBoneLink = it.next();
space.add(physicsBoneLink.joint);
}
- added = true;
}
}
+ space.addCollisionListener(this);
}
- protected void removeFromPhysicsSpace() {
- if (space == null) {
- return;
- }
+ @Override
+ protected void removePhysics(PhysicsSpace space) {
if (baseRigidBody != null) {
space.remove(baseRigidBody);
}
}
}
}
- added = false;
- }
-
- /**
- * enable or disable the control
- * note that if enabled is true and that the physic space has been set on the ragdoll, the ragdoll is added to the physic space
- * if enabled is false the ragdoll is removed from physic space.
- * @param enabled
- */
- public void setEnabled(boolean enabled) {
- if (this.enabled == enabled) {
- return;
- }
- this.enabled = enabled;
- if (!enabled && space != null) {
- removeFromPhysicsSpace();
- } else if (enabled && space != null) {
- addToPhysicsSpace();
- }
+ space.removeCollisionListener(this);
}
/**
- * returns true if the control is enabled
- * @return
- */
- public boolean isEnabled() {
- return enabled;
- }
-
- /**
- * For internal use only
- * specific render for the ragdoll(if debugging)
- * @param rm
- * @param vp
- */
- public void render(RenderManager rm, ViewPort vp) {
- }
-
- /**
- * set the physic space to this ragdoll
- * @param space
- */
- public void setPhysicsSpace(PhysicsSpace space) {
- if (space == null) {
- removeFromPhysicsSpace();
- this.space = space;
- } else {
- if (this.space == space) {
- return;
- }
- this.space = space;
- addToPhysicsSpace();
- this.space.addCollisionListener(this);
- }
- }
-
- /**
- * returns the physic space
- * @return
- */
- public PhysicsSpace getPhysicsSpace() {
- return space;
- }
-
- /**
- * serialize this control
- * @param ex
- * @throws IOException
- */
- public void write(JmeExporter ex) throws IOException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- /**
- * de-serialize this control
- * @param im
- * @throws IOException
- */
- public void read(JmeImporter im) throws IOException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- /**
- * For internal use only
- * callback for collisionevent
- * @param event
+ * For internal use only callback for collisionevent
+ *
+ * @param event
*/
public void collision(PhysicsCollisionEvent event) {
PhysicsCollisionObject objA = event.getObjectA();
}
/**
- * Enable or disable the ragdoll behaviour.
- * if ragdollEnabled is true, the character motion will only be powerd by physics
- * else, the characted will be animated by the keyframe animation,
- * but will be able to physically interact with its physic environnement
- * @param ragdollEnabled
+ * Enable or disable the ragdoll behaviour. if ragdollEnabled is true, the
+ * character motion will only be powerd by physics else, the characted will
+ * be animated by the keyframe animation, but will be able to physically
+ * interact with its physic environnement
+ *
+ * @param ragdollEnabled
*/
protected void setMode(Mode mode) {
this.mode = mode;
baseRigidBody.setKinematic(mode == Mode.Kinematic);
TempVars vars = TempVars.get();
-
+
for (PhysicsBoneLink link : boneLinks.values()) {
link.rigidBody.setKinematic(mode == Mode.Kinematic);
if (mode == Mode.Ragdoll) {
}
/**
- * Smoothly blend from Ragdoll mode to Kinematic mode
- * This is useful to blend ragdoll actual position to a keyframe animation for example
+ * Smoothly blend from Ragdoll mode to Kinematic mode This is useful to
+ * blend ragdoll actual position to a keyframe animation for example
+ *
* @param blendTime the blending time between ragdoll to anim.
*/
public void blendToKinematicMode(float blendTime) {
animControl.setEnabled(true);
- TempVars vars = TempVars.get();
+ TempVars vars = TempVars.get();
for (PhysicsBoneLink link : boneLinks.values()) {
Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
}
/**
- * Set the control into Kinematic mode
- * In theis mode, the collision shapes follow the movements of the skeleton,
- * and can interact with physical environement
+ * Set the control into Kinematic mode In theis mode, the collision shapes
+ * follow the movements of the skeleton, and can interact with physical
+ * environement
*/
public void setKinematicMode() {
if (mode != Mode.Kinematic) {
}
/**
- * Sets the control into Ragdoll mode
- * The skeleton is entirely controlled by physics.
+ * Sets the control into Ragdoll mode The skeleton is entirely controlled by
+ * physics.
*/
public void setRagdollMode() {
if (mode != Mode.Ragdoll) {
/**
* retruns the mode of this control
- * @return
+ *
+ * @return
*/
public Mode getMode() {
return mode;
}
/**
- * add a
- * @param listener
+ * add a
+ *
+ * @param listener
*/
public void addCollisionListener(RagdollCollisionListener listener) {
if (listeners == null) {
/**
* Set the CcdMotionThreshold of all the bone's rigidBodies of the ragdoll
- * @see PhysicsRigidBody#setCcdMotionThreshold(float)
- * @param value
+ *
+ * @see PhysicsRigidBody#setCcdMotionThreshold(float)
+ * @param value
*/
public void setCcdMotionThreshold(float value) {
for (PhysicsBoneLink link : boneLinks.values()) {
/**
* Set the CcdSweptSphereRadius of all the bone's rigidBodies of the ragdoll
- * @see PhysicsRigidBody#setCcdSweptSphereRadius(float)
- * @param value
+ *
+ * @see PhysicsRigidBody#setCcdSweptSphereRadius(float)
+ * @param value
*/
public void setCcdSweptSphereRadius(float value) {
for (PhysicsBoneLink link : boneLinks.values()) {
/**
* return the rigidBody associated to the given bone
+ *
* @param boneName the name of the bone
* @return the associated rigidBody.
*/
}
return null;
}
+
+ /**
+ * For internal use only specific render for the ragdoll(if debugging)
+ *
+ * @param rm
+ * @param vp
+ */
+ public void render(RenderManager rm, ViewPort vp) {
+ }
+
+ public Control cloneForSpatial(Spatial spatial) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /**
+ * serialize this control
+ *
+ * @param ex
+ * @throws IOException
+ */
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ }
+
+ /**
+ * de-serialize this control
+ *
+ * @param im
+ * @throws IOException
+ */
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ }
}