浏览代码

Ragdoll
- made some clean up
- started a draft javadoc

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7360 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

rem..om 14 年之前
父节点
当前提交
c407296ccb

+ 212 - 91
engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java

@@ -75,8 +75,34 @@ import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-/**
- * 
+/**<strong>This control is still a WIP, use it at your own risk</strong><br>
+ * To use this control you need a model with an AnimControl and a SkeletonControl.<br>
+ * This should be the case if you imported an animated model from Ogre or blender.<br>
+ * <p>
+ * This control creates collision shapes for each bones of the skeleton when you call spatial.addControl(ragdollControl).
+ * <ul>
+ *     <li>The shape is HullCollision shape based on the vertices associated with each bone and based on a tweakable weight threshold (see setWeightThreshold)</li>
+ *     <li>If you don't want each bone to be a collision shape, you can specify what bone to use by using the addBoneName method<br>
+ *         By using this method, bone that are not used to create a shape, are "merged" to their parent to create the collision shape.
+ *     </li>
+ * </ul>
+ *</p>
+ *<p>
+ *There are 2 behavior for this control : 
+ * <ul>
+ *     <li><strong>The kinematic behavior :</strong><br>
+ *        this is the default behavior, this means that the collision shapes of the body are able to interact with physics enabled objects.
+ *        in this mode physic shapes follow the moovements of the animated skeleton (for example animated by a key framed animation)
+ *        this mode is enabled just by enabling the control with setEnabled(true);
+ *        disabling the control removes it from the phyic space
+ *     </li>
+ *     <li><strong>The ragdoll behavior :</strong><br>
+ *        To enable this behavior, you need to call setRagdollEnabled(true) method.
+ *        In this mode the charater is entirely controled by physics, so it will fall under the garvity and move if any force is applied to it.
+ *     </li>
+ * </ul>
+ *</p>
+ *
  * @author Normen Hansen and Rémy Bouquet (Nehon)
  */
 public class RagdollControl implements PhysicsControl, PhysicsCollisionListener {
@@ -97,14 +123,13 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
     protected float blendStart = 0.0f;
     protected List<RagdollCollisionListener> listeners;
     protected float eventDispatchImpulseThreshold = 10;
-    protected float eventDiscardImpulseThreshold = 3;
     protected RagdollPreset preset = new HumanoidRagdollPreset();
     protected List<String> boneList = new LinkedList<String>();
     protected Vector3f modelPosition = new Vector3f();
     protected Quaternion modelRotation = new Quaternion();
     protected float rootMass = 15;
     protected float totalMass = 0;
-    protected boolean added=false;
+    protected boolean added = false;
 
     public RagdollControl() {
     }
@@ -128,116 +153,144 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         }
         TempVars vars = TempVars.get();
         assert vars.lock();
-        Quaternion q2 = vars.quat1;
-        Quaternion q3 = vars.quat2;
+        Quaternion tmpRot1 = vars.quat1;
+        Quaternion tmpRot2 = vars.quat2;
 
+        //if the ragdoll has the control of the skeleton, we update each bone with its position in physic world space.
         if (control) {
-
-
             for (PhysicsBoneLink link : boneLinks.values()) {
 
-                Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
                 Vector3f position = vars.vect1;
 
+                //retrieving bone position in physic world space
+                Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
+                //transforming this position with inverse transforms of the model
                 targetModel.getWorldTransform().transformInverseVector(p, position);
 
+                //retrieving bone rotation in physic world space
                 Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
 
-                q2.set(q).multLocal(link.initalWorldRotation).normalizeLocal();
-                q3.set(targetModel.getWorldRotation()).inverseLocal().mult(q2, q2);
-                q2.normalizeLocal();
+                //multiplying this rotation by the initialWorld rotation of the bone, 
+                //then transforming it with the inverse world rotation of the model
+                tmpRot1.set(q).multLocal(link.initalWorldRotation);
+                tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1);
+                tmpRot1.normalizeLocal();
+
+                //if the bone is the root bone, we apply the physic's transform to the model, so its position and rotation are correctly updated
                 if (link.bone.getParent() == null) {
+                    //offsetting the physic's position/rotation by the root bone inverse model space position/rotaion
                     modelPosition.set(p).subtractLocal(link.bone.getInitialPos());
-                    modelRotation.set(q).multLocal(link.bone.getInitialRot().inverse());
+                    modelRotation.set(q).multLocal(tmpRot2.set(link.bone.getInitialRot()).inverseLocal());
+
+                    //applying transforms to the model
                     targetModel.setLocalTranslation(modelPosition);
                     targetModel.setLocalRotation(modelRotation);
-                    link.bone.setUserControl(true);
-                    link.bone.setUserTransformsWorld(position, q2);
+
+                    //Applying computed transforms to the bone
+                    link.bone.setUserTransformsWorld(position, tmpRot1);
 
                 } else {
+                    //if boneList is empty, this means that every bone in the ragdoll has a collision shape,
+                    //so we just update the bone position
                     if (boneList.isEmpty()) {
-                        link.bone.setUserControl(true);
-                        link.bone.setUserTransformsWorld(position, q2);
+                        link.bone.setUserTransformsWorld(position, tmpRot1);
                     } else {
-                        setTransform(link.bone, position, q2);
+                        //boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
+                        //So we update them recusively
+                        setTransform(link.bone, position, tmpRot1, false);
                     }
                 }
             }
         } else {
-
-
+            //the ragdoll does not have the controll, so the keyframed animation updates the physic position of the physic bonces
             for (PhysicsBoneLink link : boneLinks.values()) {
-                //the ragdoll does not control the skeleton
-                link.bone.setUserControl(false);
+
                 if (!link.rigidBody.isKinematic()) {
                     link.rigidBody.setKinematic(true);
                 }
 
-                if (blendedControl) {
-
-
+                Vector3f position = vars.vect1;
 
-                    Vector3f position = vars.vect1.set(link.startBlendingPos);
+                //if blended control this means, keyframed animation is updating the skeleton, 
+                //but to allow smooth transition, we blend this transformation with the saved position of the ragdoll
+                if (blendedControl) {
                     Vector3f position2 = vars.vect2;
+                    //initializing tmp vars with the start position/rotation of the ragdoll
+                    position.set(link.startBlendingPos);
+                    tmpRot1.set(link.startBlendingRot);
 
-                    q2.set(link.startBlendingRot);
-
-                    q3.set(q2).slerp(link.bone.getModelSpaceRotation(), blendStart / blendTime);
+                    //interpolating between ragdoll position/rotation and keyframed position/rotation
+                    tmpRot2.set(tmpRot1).slerp(link.bone.getModelSpaceRotation(), blendStart / blendTime);
                     position2.set(position).interpolate(link.bone.getModelSpacePosition(), blendStart / blendTime);
-                    q2.set(q3);
+                    tmpRot1.set(tmpRot2);
                     position.set(position2);
+
+                    //updating bones transforms
                     if (boneList.isEmpty()) {
+                        //we ensure we have the control to update the bone
                         link.bone.setUserControl(true);
-                        link.bone.setUserTransformsWorld(position, q2);
+                        link.bone.setUserTransformsWorld(position, tmpRot1);
+                        //we give control back to the key framed animation.
+                        link.bone.setUserControl(false);
                     } else {
-                        setTransform(link.bone, position, q2);
+                        setTransform(link.bone, position, tmpRot1, true);
                     }
 
                 }
 
-
-
-
-
-                Vector3f position = vars.vect1;
-                Quaternion rotation = vars.quat1;
-
                 //computing position from rotation and scale
                 targetModel.getWorldTransform().transformVector(link.bone.getModelSpacePosition(), position);
 
                 //computing rotation
-                rotation.set(link.bone.getModelSpaceRotation()).multLocal(link.bone.getWorldBindInverseRotation());
-                targetModel.getWorldRotation().mult(rotation, rotation);
-                rotation.normalize();
+                tmpRot1.set(link.bone.getModelSpaceRotation()).multLocal(link.bone.getWorldBindInverseRotation());
+                targetModel.getWorldRotation().mult(tmpRot1, tmpRot1);
+                tmpRot1.normalizeLocal();
 
+                //updating physic location/rotation of the physic bone
                 link.rigidBody.setPhysicsLocation(position);
-                link.rigidBody.setPhysicsRotation(rotation);
+                link.rigidBody.setPhysicsRotation(tmpRot1);
             }
+
+            //time control for blending
             if (blendedControl) {
                 blendStart += tpf;
-
                 if (blendStart > blendTime) {
                     blendedControl = false;
 
                 }
             }
         }
-
-
         assert vars.unlock();
 
     }
 
-    private void setTransform(Bone bone, Vector3f pos, Quaternion rot) {
-        bone.setUserControl(true);
+    /**
+     * Updates a bone position and rotation.
+     * if the child bones are not in the bone list this means, they are not associated with a physic shape.
+     * So they have to be updated
+     * @param bone the bone
+     * @param pos the position
+     * @param rot the rotation
+     */
+    private void setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl) {
+        //we ensure that we have the control
+        if (restoreBoneControl) {
+            bone.setUserControl(true);
+        }
+        //we set te user transforms of the bone
         bone.setUserTransformsWorld(pos, rot);
         for (Bone childBone : bone.getChildren()) {
+            //each child bone that is not in the list is updated
             if (!boneList.contains(childBone.getName())) {
                 Transform t = childBone.getCombinedTransform(pos, rot);
-                setTransform(childBone, t.getTranslation(), t.getRotation());
+                setTransform(childBone, t.getTranslation(), t.getRotation(), restoreBoneControl);
             }
         }
-        bone.setUserControl(false);
+        //we give back the control to the keyframed animation
+        if (restoreBoneControl) {
+            bone.setUserControl(false);
+        }
+
     }
 
     public Control cloneForSpatial(Spatial spatial) {
@@ -285,7 +338,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         model.setLocalRotation(initRotation);
         model.setLocalScale(initScale);
 
-        logger.log(Level.INFO, "Create physics ragdoll for skeleton {0}", skeleton);
+        logger.log(Level.INFO, "Created physics ragdoll for skeleton {0}", skeleton);
     }
 
     public void addBoneName(String name) {
@@ -405,29 +458,36 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
     }
 
     private void addToPhysicsSpace() {
-        
+
         if (baseRigidBody != null) {
             space.add(baseRigidBody);
-            added=true;
+            added = true;
         }
         for (Iterator<PhysicsBoneLink> it = boneLinks.values().iterator(); it.hasNext();) {
             PhysicsBoneLink physicsBoneLink = it.next();
             if (physicsBoneLink.rigidBody != null) {
                 space.add(physicsBoneLink.rigidBody);
-                added=true;
+                added = true;
             }
         }
         for (Iterator<PhysicsBoneLink> it = boneLinks.values().iterator(); it.hasNext();) {
             PhysicsBoneLink physicsBoneLink = it.next();
             if (physicsBoneLink.joint != null) {
                 space.add(physicsBoneLink.joint);
-                added=true;
+                added = true;
             }
         }
-        
+
     }
 
-    private HullCollisionShape makeShape(PhysicsBoneLink link, Spatial model) {
+    /**
+     * Create a hull collision shape from linked vertices to this bone.
+     * 
+     * @param link
+     * @param model
+     * @return 
+     */
+    protected HullCollisionShape makeShape(PhysicsBoneLink link, Spatial model) {
         Bone bone = link.bone;
         List<Integer> boneIndices = null;
         if (boneList.isEmpty()) {
@@ -437,12 +497,11 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
             boneIndices = getBoneIndices(bone, skeleton);
         }
 
-
         ArrayList<Float> points = new ArrayList<Float>();
         if (model instanceof Geometry) {
             Geometry g = (Geometry) model;
             for (Integer index : boneIndices) {
-                points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition(), link));
+                points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition()));
             }
         } else if (model instanceof Node) {
             Node node = (Node) model;
@@ -450,7 +509,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 if (s instanceof Geometry) {
                     Geometry g = (Geometry) s;
                     for (Integer index : boneIndices) {
-                        points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition(), link));
+                        points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition()));
                     }
 
                 }
@@ -464,7 +523,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         return new HullCollisionShape(p);
     }
 
-    private List<Integer> getBoneIndices(Bone bone, Skeleton skeleton) {
+    //retruns the list of bone indices of the given bone and its child(if they are not in the boneList)
+    protected List<Integer> getBoneIndices(Bone bone, Skeleton skeleton) {
         List<Integer> list = new LinkedList<Integer>();
         list.add(skeleton.getBoneIndex(bone));
         for (Bone chilBone : bone.getChildren()) {
@@ -475,7 +535,15 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         return list;
     }
 
-    protected List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f offset, PhysicsBoneLink link) {
+    /**
+     * returns a list of points for the given bone
+     * @param mesh
+     * @param boneIndex
+     * @param offset
+     * @param link
+     * @return 
+     */
+    private List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f offset) {
 
         FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
         ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
@@ -516,8 +584,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         return results;
     }
 
-    private void removeFromPhysicsSpace() {
-        
+    protected void removeFromPhysicsSpace() {
+
         if (baseRigidBody != null) {
             space.remove(baseRigidBody);
         }
@@ -533,9 +601,15 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 space.remove(physicsBoneLink.rigidBody);
             }
         }
-        added=false;
+        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;
@@ -548,11 +622,15 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         }
     }
 
+    /**
+     * returns true if the control is enabled
+     * @return 
+     */
     public boolean isEnabled() {
         return enabled;
     }
 
-    public void attachDebugShape(AssetManager manager) {
+    protected void attachDebugShape(AssetManager manager) {
         for (Iterator<PhysicsBoneLink> it = boneLinks.values().iterator(); it.hasNext();) {
             PhysicsBoneLink physicsBoneLink = it.next();
             physicsBoneLink.rigidBody.createDebugShape(manager);
@@ -560,7 +638,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         debug = true;
     }
 
-    public void detachDebugShape() {
+    protected void detachDebugShape() {
         for (Iterator<PhysicsBoneLink> it = boneLinks.values().iterator(); it.hasNext();) {
             PhysicsBoneLink physicsBoneLink = it.next();
             physicsBoneLink.rigidBody.detachDebugShape();
@@ -568,6 +646,12 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         debug = false;
     }
 
+    /**
+     * For internal use only
+     * specific render for the ragdoll(if debugging)      
+     * @param rm
+     * @param vp 
+     */
     public void render(RenderManager rm, ViewPort vp) {
         if (enabled && space != null && space.getDebugManager() != null) {
             if (!debug) {
@@ -586,6 +670,10 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         }
     }
 
+    /**
+     * set the physic space to this ragdoll
+     * @param space 
+     */
     public void setPhysicsSpace(PhysicsSpace space) {
         if (space == null) {
             removeFromPhysicsSpace();
@@ -600,27 +688,48 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         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 
+     */
     public void collision(PhysicsCollisionEvent event) {
         PhysicsCollisionObject objA = event.getObjectA();
         PhysicsCollisionObject objB = event.getObjectB();
 
+        //excluding collisions that do not involve the ragdoll
         if (event.getNodeA() == null && event.getNodeB() == null) {
             return;
         }
 
-        if (event.getAppliedImpulse() < eventDiscardImpulseThreshold) {
+        //discarding low impulse collision
+        if (event.getAppliedImpulse() < eventDispatchImpulseThreshold) {
             return;
         }
 
@@ -628,7 +737,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         Bone hitBone = null;
         PhysicsCollisionObject hitObject = null;
 
-
+        //Computing which bone has been hit
         if (objA.getUserObject() instanceof PhysicsBoneLink) {
             PhysicsBoneLink link = (PhysicsBoneLink) objA.getUserObject();
             if (link != null) {
@@ -648,7 +757,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
             }
         }
 
-        if (hit && event.getAppliedImpulse() > eventDispatchImpulseThreshold) {
+        //dispatching the event if the ragdoll has been hit
+        if (hit) {
             for (RagdollCollisionListener listener : listeners) {
                 listener.collide(hitBone, hitObject, event);
             }
@@ -656,26 +766,38 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
 
     }
 
-    public void setControl(boolean control) {
+    /**
+     * 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 
+     */
+    public void setRagdollEnabled(boolean ragdollEnabled) {
 
         AnimControl animControl = targetModel.getControl(AnimControl.class);
-        animControl.setEnabled(!control);
+        animControl.setEnabled(!ragdollEnabled);
 
-        this.control = control;
+        this.control = ragdollEnabled;
         for (PhysicsBoneLink link : boneLinks.values()) {
-            //  link.bone.setUserControl(control);
-            link.rigidBody.setKinematic(!control);
+            link.rigidBody.setKinematic(!ragdollEnabled);
         }
 
-
         for (Bone bone : skeleton.getRoots()) {
-            setUserControl(bone, control);
+            setUserControl(bone, ragdollEnabled);
         }
-
     }
 
-    public void blendControlToAnim(String anim, AnimChannel channel) {
+    /**
+     * Blend motion between the ragdoll actual physic state to the given animation, in the given blendTime
+     * Note that this disable the ragdoll behaviour of the control
+     * @param anim the animation name to blend to
+     * @param channel the channel to use for this animation
+     * @param blendTime the blending time between ragdoll to anim.
+     */
+    public void blendRagdollToAnim(String anim, AnimChannel channel, float blendTime) {
         blendedControl = true;
+        this.blendTime = blendTime;
         control = false;
         AnimControl animControl = targetModel.getControl(AnimControl.class);
         animControl.setEnabled(true);
@@ -696,9 +818,9 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
             Quaternion q2 = vars.quat1;
             Quaternion q3 = vars.quat2;
 
-            q2.set(q).multLocal(link.initalWorldRotation).normalize();
+            q2.set(q).multLocal(link.initalWorldRotation).normalizeLocal();
             q3.set(targetModel.getWorldRotation()).inverseLocal().mult(q2, q2);
-            q2.normalize();
+            q2.normalizeLocal();
             link.startBlendingPos.set(position);
             link.startBlendingRot.set(q2);
             link.rigidBody.setKinematic(true);
@@ -719,12 +841,19 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         }
     }
 
-    public boolean hasControl() {
-
+    /**
+     * returns true if the ragdoll behaviour is enabled
+     * @return 
+     */
+    public boolean isRagdollEnabled() {
         return control;
 
     }
 
+    /**
+     * add a 
+     * @param listener 
+     */
     public void addCollisionListener(RagdollCollisionListener listener) {
         if (listeners == null) {
             listeners = new ArrayList<RagdollCollisionListener>();
@@ -760,14 +889,6 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         this.weightThreshold = weightThreshold;
     }
 
-    public float getEventDiscardImpulseThreshold() {
-        return eventDiscardImpulseThreshold;
-    }
-
-    public void setEventDiscardImpulseThreshold(float eventDiscardImpulseThreshold) {
-        this.eventDiscardImpulseThreshold = eventDiscardImpulseThreshold;
-    }
-
     public float getEventDispatchImpulseThreshold() {
         return eventDispatchImpulseThreshold;
     }

+ 25 - 34
engine/src/test/jme3test/bullet/TestBoneRagdoll.java

@@ -46,20 +46,16 @@ import com.jme3.bullet.collision.RagdollCollisionListener;
 import com.jme3.bullet.collision.shapes.SphereCollisionShape;
 import com.jme3.bullet.control.RagdollControl;
 import com.jme3.bullet.control.RigidBodyControl;
-import com.jme3.bullet.joints.SixDofJoint;
 import com.jme3.font.BitmapText;
 import com.jme3.input.KeyInput;
 import com.jme3.input.MouseInput;
 import com.jme3.input.controls.ActionListener;
 import com.jme3.input.controls.KeyTrigger;
-import com.jme3.input.controls.MouseAxisTrigger;
 import com.jme3.input.controls.MouseButtonTrigger;
-import com.jme3.light.AmbientLight;
 import com.jme3.light.DirectionalLight;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.FastMath;
-import com.jme3.math.Matrix3f;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
@@ -73,7 +69,7 @@ import com.jme3.texture.Texture;
  * PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET!
  * @author normenhansen
  */
-public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener, AnimEventListener{
+public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener, AnimEventListener {
 
     private BulletAppState bulletAppState;
     Material matBullet;
@@ -131,8 +127,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         float eighth_pi = FastMath.PI * 0.125f;
         ragdoll.setJointLimit("Waist", eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi);
         ragdoll.setJointLimit("Chest", eighth_pi, eighth_pi, 0, 0, eighth_pi, eighth_pi);
-   
-        
+
+
         //Oto's head is almost rigid
         //    ragdoll.setJointLimit("head", 0, 0, eighth_pi, -eighth_pi, 0, 0);
 
@@ -152,21 +148,21 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
 
             public void onAction(String name, boolean isPressed, float tpf) {
                 if (name.equals("toggle") && isPressed) {
-                    
-                    Vector3f v=new Vector3f();
+
+                    Vector3f v = new Vector3f();
                     v.set(model.getLocalTranslation());
-                    v.y=0;
+                    v.y = 0;
                     model.setLocalTranslation(v);
-                    Quaternion q=new Quaternion();
-                    float[] angles=new float[3];
+                    Quaternion q = new Quaternion();
+                    float[] angles = new float[3];
                     model.getLocalRotation().toAngles(angles);
-                    q.fromAngleAxis(angles[1],  Vector3f.UNIT_Y);
+                    q.fromAngleAxis(angles[1], Vector3f.UNIT_Y);
                     //q.lookAt(model.getLocalRotation().toRotationMatrix().getColumn(2), Vector3f.UNIT_Y);
-                    model.setLocalRotation(q);              
-                    if(angles[0]<0){
-                        ragdoll.blendControlToAnim("StandUpBack",animChannel);
-                    }else{
-                        ragdoll.blendControlToAnim("StandUpFront",animChannel);
+                    model.setLocalRotation(q);
+                    if (angles[0] < 0) {
+                        ragdoll.blendRagdollToAnim("StandUpBack", animChannel, 1);
+                    } else {
+                        ragdoll.blendRagdollToAnim("StandUpFront", animChannel, 1);
                     }
 
                 }
@@ -190,7 +186,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
                     bulletg.setMaterial(matBullet);
                     bulletg.setLocalTranslation(cam.getLocation());
                     bulletg.setLocalScale(bulletSize);
-                    bulletCollisionShape = new SphereCollisionShape(bulletSize);                   
+                    bulletCollisionShape = new SphereCollisionShape(bulletSize);
                     RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, bulletSize * 10);
                     bulletNode.setCcdMotionThreshold(0.001f);
                     bulletNode.setLinearVelocity(cam.getDirection().mult(80));
@@ -206,7 +202,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
                     bulletCollisionShape = new SphereCollisionShape(bulletSize);
                     BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
                     bulletNode.setForceFactor(10);
-                    bulletNode.setExplosionRadius(30);                    
+                    bulletNode.setExplosionRadius(30);
                     bulletNode.setCcdMotionThreshold(0.001f);
                     bulletNode.setLinearVelocity(cam.getDirection().mult(180));
                     bulletg.addControl(bulletNode);
@@ -214,7 +210,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
                     getPhysicsSpace().add(bulletNode);
                 }
             }
-        }, "toggle", "shoot", "stop", "bullet+", "bullet-","boom");
+        }, "toggle", "shoot", "stop", "bullet+", "bullet-", "boom");
         inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
         inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
         inputManager.addMapping("boom", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
@@ -226,7 +222,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
     }
 
     private void setupLight() {
-       // AmbientLight al = new AmbientLight();
+        // AmbientLight al = new AmbientLight();
         //  al.setColor(ColorRGBA.White.mult(1));
         //   rootNode.addLight(al);
 
@@ -260,7 +256,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         guiNode.attachChild(ch);
     }
 
-    public void collide(Bone bone, PhysicsCollisionObject object,PhysicsCollisionEvent event) {
+    public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event) {
 
         if (object.getUserObject() != null && object.getUserObject() instanceof Geometry) {
             Geometry geom = (Geometry) object.getUserObject();
@@ -269,10 +265,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
             }
         }
 
-
-        if (!ragdoll.hasControl()) {
-
-            ragdoll.setControl(true);
+        if (!ragdoll.isRagdollEnabled()) {
+            ragdoll.setRagdollEnabled(true);
 
         }
     }
@@ -300,10 +294,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         ragdoll.addBoneName("Clavicle.R");
 
     }
-
     float elTime = 0;
     boolean forward = true;
-
     AnimControl animControl;
     AnimChannel animChannel;
     Vector3f direction = new Vector3f(0, 0, 1);
@@ -353,19 +345,18 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
 //        if(channel.getAnimationName().equals("StandUpFront")){
 //            channel.setAnim("Dance");
 //        }
-       
-        if(channel.getAnimationName().equals("StandUpBack") || channel.getAnimationName().equals("StandUpFront")){
+
+        if (channel.getAnimationName().equals("StandUpBack") || channel.getAnimationName().equals("StandUpFront")) {
             channel.setLoopMode(LoopMode.DontLoop);
-            channel.setAnim("IdleTop",5);
+            channel.setAnim("IdleTop", 5);
             channel.setLoopMode(LoopMode.Loop);
         }
 //        if(channel.getAnimationName().equals("IdleTop")){
 //            channel.setAnim("StandUpFront");
 //        }
-       
+
     }
 
     public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
-      
     }
 }