浏览代码

Ragdoll, some enhancements

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7261 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
rem..om 14 年之前
父节点
当前提交
cdba72d2b7

+ 1 - 1
engine/src/jbullet/com/jme3/bullet/collision/RagdollCollisionListener.java

@@ -12,6 +12,6 @@ import com.jme3.animation.Bone;
  */
 public interface RagdollCollisionListener {
     
-    public void collide(Bone bone, PhysicsCollisionObject object);
+    public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event);
     
 }

+ 75 - 43
engine/src/jbullet/com/jme3/bullet/control/RagdollControl.java

@@ -83,8 +83,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
     protected Skeleton skeleton;
     protected PhysicsSpace space;
     protected boolean enabled = true;
-    protected boolean debug = false;
-    protected Quaternion tmp_jointRotation = new Quaternion();
+    protected boolean debug = false;   
     protected PhysicsRigidBody baseRigidBody;
     protected float weightThreshold = 1.0f;
     protected Spatial targetModel;
@@ -95,7 +94,9 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
     protected float eventDiscardImpulseThreshold = 3;
     protected RagdollPreset preset = new HumanoidRagdollPreset();
     protected List<String> boneList = new LinkedList<String>();
-    protected Vector3f initPosition = new Vector3f();
+    protected Vector3f modelPosition = new Vector3f();
+    protected float rootMass = 15;
+    private float totalMass = 0;
 
     public RagdollControl() {
     }
@@ -104,6 +105,15 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         this.weightThreshold = weightThreshold;
     }
 
+    public RagdollControl(RagdollPreset preset, float weightThreshold) {
+        this.preset = preset;
+        this.weightThreshold = weightThreshold;
+    }
+
+    public RagdollControl(RagdollPreset preset) {
+        this.preset = preset;
+    }
+
     public void update(float tpf) {
         if (!enabled) {
             return;
@@ -114,7 +124,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
 
             Quaternion q2 = vars.quat1;
             Quaternion q3 = vars.quat2;
-          
+
             for (PhysicsBoneLink link : boneLinks.values()) {
 
                 Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
@@ -128,12 +138,12 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 q3.set(targetModel.getWorldRotation()).inverseLocal().mult(q2, q2);
                 q2.normalize();
                 if (link.bone.getParent() == null) {
-                    initPosition.set(p).subtractLocal(link.bone.getInitialPos());
-                    targetModel.setLocalTranslation(initPosition);
+                    modelPosition.set(p).subtractLocal(link.bone.getInitialPos());
+                    targetModel.setLocalTranslation(modelPosition);
                     link.bone.setUserControl(true);
                     link.bone.setUserTransformsWorld(position, q2);
 
-                } else {                    
+                } else {
                     if (boneList.isEmpty()) {
                         link.bone.setUserControl(true);
                         link.bone.setUserTransformsWorld(position, q2);
@@ -151,7 +161,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 }
 
                 Vector3f position = vars.vect1;
-                Quaternion rotation = vars.quat1;           
+                Quaternion rotation = vars.quat1;
 
                 //computing position from rotation and scale
                 targetModel.getWorldTransform().transformVector(link.bone.getModelSpacePosition(), position);
@@ -161,7 +171,6 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 targetModel.getWorldRotation().mult(rotation, rotation);
                 rotation.normalize();
 
-                // scale.set(link.bone.getModelSpaceScale());
                 link.rigidBody.setPhysicsLocation(position);
                 link.rigidBody.setPhysicsRotation(rotation);
             }
@@ -240,34 +249,30 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         skeleton = animControl.getSkeleton();
         skeleton.resetAndUpdate();
         for (int i = 0; i < skeleton.getRoots().length; i++) {
-            Bone childBone = skeleton.getRoots()[i];           
+            Bone childBone = skeleton.getRoots()[i];
             if (childBone.getParent() == null) {
-                // Quaternion parentRot= childBone.getModelSpaceRotation().mult(initRotation);
                 logger.log(Level.INFO, "Found root bone in skeleton {0}", skeleton);
-                baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(.1f)), 1);
-                //  baseRigidBody.setPhysicsRotation(parentRot);
+                baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1);
                 boneRecursion(model, childBone, baseRigidBody, 1);
-                return;
             }
-
         }
+
+
     }
 
     private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount) {
         PhysicsRigidBody parentShape = parent;
         if (boneList.isEmpty() || boneList.contains(bone.getName())) {
 
-            //creating the collision shape from the bone's associated vertices
-            PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(bone, model), 10.0f / (float) reccount);
-
             PhysicsBoneLink link = new PhysicsBoneLink();
             link.bone = bone;
-            link.rigidBody = shapeNode;
+            //creating the collision shape from the bone's associated vertices
+            PhysicsRigidBody shapeNode = new PhysicsRigidBody(makeShape(link, model), rootMass / (float) reccount);
+            totalMass += rootMass / (float) reccount;
 
+            link.rigidBody = shapeNode;
             link.initalWorldRotation = bone.getModelSpaceRotation().clone();
-            //       link.mass = 10.0f / (float) reccount;
 
-            //TODO: ragdoll mass 1
             if (parent != null) {
                 //get joint position for parent
                 Vector3f posToParent = new Vector3f();
@@ -281,11 +286,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 link.pivotB = new Vector3f(0, 0, 0f);
 
                 SixDofJoint joint = new SixDofJoint(parent, shapeNode, link.pivotA, link.pivotB, true);
-                joint.getTranslationalLimitMotor().setUpperLimit(new Vector3f(0, 0, 0));
-                joint.getTranslationalLimitMotor().setLowerLimit(new Vector3f(0, 0, 0));
-                //TODO find a way to correctly compute/import joints (maybe based on their names)
                 preset.setupJointForBone(bone.getName(), joint);
-                //setJointLimit(joint, 0, 0, 0, 0, 0, 0);
 
                 link.joint = joint;
                 joint.setCollisionBetweenLinkedBodys(false);
@@ -297,7 +298,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
 
         for (Iterator<Bone> it = bone.getChildren().iterator(); it.hasNext();) {
             Bone childBone = it.next();
-            boneRecursion(model, childBone, parentShape, reccount++);
+            boneRecursion(model, childBone, parentShape, reccount + 1);
         }
 
 
@@ -372,8 +373,8 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         }
     }
 
-    private HullCollisionShape makeShape(Bone bone, Spatial model) {
-
+    private HullCollisionShape makeShape(PhysicsBoneLink link, Spatial model) {
+        Bone bone = link.bone;
         List<Integer> boneIndices = null;
         if (boneList.isEmpty()) {
             boneIndices = new LinkedList<Integer>();
@@ -387,7 +388,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         if (model instanceof Geometry) {
             Geometry g = (Geometry) model;
             for (Integer index : boneIndices) {
-                points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition()));
+                points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition(), link));
             }
         } else if (model instanceof Node) {
             Node node = (Node) model;
@@ -395,7 +396,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()));
+                        points.addAll(getPoints(g.getMesh(), index, bone.getModelSpacePosition(), link));
                     }
 
                 }
@@ -420,7 +421,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         return list;
     }
 
-    protected List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f offset) {
+    protected List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f offset, PhysicsBoneLink link) {
 
         FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
         ByteBuffer boneIndices = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
@@ -433,6 +434,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         ArrayList<Float> results = new ArrayList<Float>();
 
         int vertexComponents = mesh.getVertexCount() * 3;
+
         for (int i = 0; i < vertexComponents; i += 3) {
             int k;
             boolean add = false;
@@ -444,6 +446,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 }
             }
             if (add) {
+
                 Vector3f pos = new Vector3f();
                 pos.x = vertices.get(i);
                 pos.y = vertices.get(i + 1);
@@ -452,8 +455,10 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 results.add(pos.x);
                 results.add(pos.y);
                 results.add(pos.z);
+
             }
         }
+
         return results;
     }
 
@@ -566,7 +571,7 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         boolean hit = false;
         Bone hitBone = null;
         PhysicsCollisionObject hitObject = null;
-        
+
 
         if (objA.getUserObject() instanceof PhysicsBoneLink) {
             PhysicsBoneLink link = (PhysicsBoneLink) objA.getUserObject();
@@ -585,15 +590,12 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
                 hitObject = objA;
 
             }
-        }    
+        }
 
-        if (hit && event.getAppliedImpulse() > eventDispatchImpulseThreshold) {
-            // System.out.println("trigger impact " + event.getNodeA() + " " + event.getNodeB() + " " + event.getAppliedImpulse());
-            //setControl(true);
+        if (hit && event.getAppliedImpulse() > eventDispatchImpulseThreshold) {       
             for (RagdollCollisionListener listener : listeners) {
-                listener.collide(hitBone, hitObject);
+                listener.collide(hitBone, hitObject, event);
             }
-
         }
 
     }
@@ -629,10 +631,6 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
 
     }
 
-    public boolean collide(PhysicsCollisionObject nodeA, PhysicsCollisionObject nodeB) {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     public void addCollisionListener(RagdollCollisionListener listener) {
         if (listeners == null) {
             listeners = new ArrayList<RagdollCollisionListener>();
@@ -648,6 +646,40 @@ public class RagdollControl implements PhysicsControl, PhysicsCollisionListener
         PhysicsRigidBody rigidBody;
         Vector3f pivotA;
         Vector3f pivotB;
-        //       float mass;
+        float volume = 0;
+    }
+
+    public void setRootMass(float rootMass) {
+        this.rootMass = rootMass;
+    }
+
+    public float getTotalMass() {
+        return totalMass;
+    }
+
+    public float getWeightThreshold() {
+        return weightThreshold;
+    }
+
+    public void setWeightThreshold(float weightThreshold) {
+        this.weightThreshold = weightThreshold;
+    }
+
+    public float getEventDiscardImpulseThreshold() {
+        return eventDiscardImpulseThreshold;
+    }
+
+    public void setEventDiscardImpulseThreshold(float eventDiscardImpulseThreshold) {
+        this.eventDiscardImpulseThreshold = eventDiscardImpulseThreshold;
+    }
+
+    public float getEventDispatchImpulseThreshold() {
+        return eventDispatchImpulseThreshold;
+    }
+
+    public void setEventDispatchImpulseThreshold(float eventDispatchImpulseThreshold) {
+        this.eventDispatchImpulseThreshold = eventDispatchImpulseThreshold;
     }
+    
+    
 }

+ 3 - 3
engine/src/jbullet/com/jme3/bullet/control/ragdoll/HumanoidRagdollPreset.java

@@ -18,15 +18,15 @@ public class HumanoidRagdollPreset extends RagdollPreset {
 
         boneMap.put("torso", new JointPreset(FastMath.QUARTER_PI, -FastMath.QUARTER_PI, 0, 0, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
 
-        boneMap.put("upperleg", new JointPreset(FastMath.PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
+        boneMap.put("upperleg", new JointPreset(FastMath.PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI/2, -FastMath.QUARTER_PI/2, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
 
         boneMap.put("lowerleg", new JointPreset(0, -FastMath.PI, 0, 0, 0, 0));
 
         boneMap.put("foot", new JointPreset(0, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
 
-        boneMap.put("upperarm", new JointPreset(FastMath.HALF_PI, -FastMath.QUARTER_PI, 0, 0, FastMath.QUARTER_PI, -FastMath.HALF_PI));
+        boneMap.put("upperarm", new JointPreset(FastMath.HALF_PI, -FastMath.QUARTER_PI, 0, 0, FastMath.PI, -FastMath.QUARTER_PI));
 
-        boneMap.put("lowerarm", new JointPreset(FastMath.PI, 0, 0, 0, 0, 0));
+        boneMap.put("lowerarm", new JointPreset(FastMath.HALF_PI, 0, 0, 0, 0, 0));
 
         boneMap.put("hand", new JointPreset(FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
 

+ 2 - 4
engine/src/jbullet/com/jme3/bullet/control/ragdoll/RagdollPreset.java

@@ -35,18 +35,16 @@ public abstract class RagdollPreset {
         String resultName = "";
         int resultScore = 0;
 
-        System.out.println("-------------- " +boneName); 
         for (String key : lexicon.keySet()) {
         
-            int score = lexicon.get(key).getScore(boneName);
-            System.out.println(key+" " +score);
+            int score = lexicon.get(key).getScore(boneName);        
             if (score > resultScore) {
                 resultScore = score;
                 resultName = key;
             }
             
         }
-        System.out.println("-------------- "); 
+        
         JointPreset preset = boneMap.get(resultName);
 
         if (preset != null && resultScore >= 50) {

+ 11 - 2
engine/src/test/jme3test/bullet/BombControl.java

@@ -105,14 +105,14 @@ public class BombControl extends RigidBodyControl implements PhysicsCollisionLis
             spatial.removeFromParent();
         }
     }
-
+    
     public void prePhysicsTick(PhysicsSpace space, float f) {
         space.removeCollisionListener(this);
     }
 
     public void physicsTick(PhysicsSpace space, float f) {
         //get all overlapping objects and apply impulse to them
-        for (Iterator<PhysicsCollisionObject> it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) {
+        for (Iterator<PhysicsCollisionObject> it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) {            
             PhysicsCollisionObject physicsCollisionObject = it.next();
             if (physicsCollisionObject instanceof PhysicsRigidBody) {
                 PhysicsRigidBody rBody = (PhysicsRigidBody) physicsCollisionObject;
@@ -157,6 +157,15 @@ public class BombControl extends RigidBodyControl implements PhysicsCollisionLis
         createGhostObject();
     }
 
+    public float getForceFactor() {
+        return forceFactor;
+    }
+
+    public void setForceFactor(float forceFactor) {
+        this.forceFactor = forceFactor;
+    }
+    
+    
     @Override
     public void read(JmeImporter im) throws IOException {
         throw new UnsupportedOperationException("Reading not supported.");

+ 68 - 102
engine/src/test/jme3test/bullet/TestBoneRagdoll.java

@@ -38,11 +38,13 @@ import com.jme3.bullet.BulletAppState;
 import com.jme3.app.SimpleApplication;
 import com.jme3.asset.TextureKey;
 import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.PhysicsCollisionEvent;
 import com.jme3.bullet.collision.PhysicsCollisionObject;
 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;
@@ -92,7 +94,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         bulletAppState = new BulletAppState();
         bulletAppState.setEnabled(true);
         stateManager.attach(bulletAppState);
-        //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+//        bulletAppState.getPhysicsSpace().enableDebug(assetManager);
         PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
         setupLight();
 
@@ -110,13 +112,16 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         skeletonDebug.setLocalTranslation(model.getLocalTranslation());
 
         //Note: PhysicsRagdollControl is still TODO, constructor will change
-        ragdoll = new RagdollControl(0.7f);
+        ragdoll = new RagdollControl(0.5f);
         setupSinbad(ragdoll);
         ragdoll.addCollisionListener(this);
         model.addControl(ragdoll);
 
         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);
 
@@ -128,8 +133,8 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         flyCam.setMoveSpeed(50);
 
 
-        final AnimChannel channel = control.createChannel();
-        channel.setAnim("Dance");
+        animChannel = control.createChannel();
+        animChannel.setAnim("Dance");
 
         inputManager.addListener(new ActionListener() {
 
@@ -158,21 +163,34 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
                     bulletg.setMaterial(matBullet);
                     bulletg.setLocalTranslation(cam.getLocation());
                     bulletg.setLocalScale(bulletSize);
-                    bulletCollisionShape = new SphereCollisionShape(bulletSize);
-                    //    RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
+                    bulletCollisionShape = new SphereCollisionShape(bulletSize);                   
                     RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, bulletSize * 10);
                     bulletNode.setCcdMotionThreshold(0.001f);
-                    bulletNode.setLinearVelocity(cam.getDirection().mult(80));
+                    bulletNode.setLinearVelocity(cam.getDirection().mult(180));
+                    bulletg.addControl(bulletNode);
+                    rootNode.attachChild(bulletg);
+                    getPhysicsSpace().add(bulletNode);
+                }
+                if (name.equals("boom") && !isPressed) {
+                    Geometry bulletg = new Geometry("bullet", bullet);
+                    bulletg.setMaterial(matBullet);
+                    bulletg.setLocalTranslation(cam.getLocation());
+                    bulletg.setLocalScale(bulletSize);
+                    bulletCollisionShape = new SphereCollisionShape(bulletSize);
+                    BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
+                    bulletNode.setForceFactor(10);
+                    bulletNode.setExplosionRadius(30);                    
+                    bulletNode.setCcdMotionThreshold(0.001f);
+                    bulletNode.setLinearVelocity(cam.getDirection().mult(180));
                     bulletg.addControl(bulletNode);
                     rootNode.attachChild(bulletg);
                     getPhysicsSpace().add(bulletNode);
-
-
                 }
             }
-        }, "toggle", "shoot", "stop", "bullet+", "bullet-");
+        }, "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));
         inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_H));
         inputManager.addMapping("bullet-", new KeyTrigger(KeyInput.KEY_COMMA));
         inputManager.addMapping("bullet+", new KeyTrigger(KeyInput.KEY_PERIOD));
@@ -181,7 +199,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);
 
@@ -225,7 +243,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         guiNode.attachChild(ch);
     }
 
-    public void collide(Bone bone, PhysicsCollisionObject object) {
+    public void collide(Bone bone, PhysicsCollisionObject object,PhysicsCollisionEvent event) {
 
         if (object.getUserObject() != null && object.getUserObject() instanceof Geometry) {
             Geometry geom = (Geometry) object.getUserObject();
@@ -237,7 +255,6 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
 
         if (!ragdoll.hasControl()) {
 
-            //bulletTime();
             ragdoll.setControl(true);
 
         }
@@ -252,7 +269,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         ragdoll.addBoneName("Hand.R");
         ragdoll.addBoneName("Hand.L");
         ragdoll.addBoneName("Neck");
-        ragdoll.addBoneName("Head");
+        //  ragdoll.addBoneName("Head");
         ragdoll.addBoneName("Root");
         ragdoll.addBoneName("Stomach");
         ragdoll.addBoneName("Waist");
@@ -265,104 +282,53 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
         ragdoll.addBoneName("Clavicle.L");
         ragdoll.addBoneName("Clavicle.R");
 
-//        <boneparent bone="ThumbMed.R" parent="ThumbProx.R" />
-//        <boneparent bone="IndexFingerMed.R" parent="IndexFingerProx.R" />
-//        <boneparent bone="Clavicle.R" parent="Chest" />
-//        <boneparent bone="PinkyDist.L" parent="PinkyMed.L" />
-//        <boneparent bone="IndexFingerDist.R" parent="IndexFingerMed.R" />
-//        <boneparent bone="Cheek.L" parent="Head" />
-//        <boneparent bone="MiddleFingerMed.L" parent="MiddleFingerProx.L" />
-//        <boneparent bone="Jaw" parent="Head" />
-//        <boneparent bone="TongueMid" parent="TongueBase" />
-//        <boneparent bone="Ulna.L" parent="Humerus.L" />
-//        <boneparent bone="Handle.R" parent="Hand.R" />
-//        <boneparent bone="Ulna.R" parent="Humerus.R" />
-//        <boneparent bone="Chest" parent="Stomach" />
-//        <boneparent bone="Foot.L" parent="Calf.L" />
-//        <boneparent bone="Foot.R" parent="Calf.R" />
-//        <boneparent bone="Hand.R" parent="Ulna.R" />
-//        <boneparent bone="IndexFingerDist.L" parent="IndexFingerMed.L" />
-//        <boneparent bone="Cheek.R" parent="Head" />
-//        <boneparent bone="PinkyDist.R" parent="PinkyMed.R" />
-//        <boneparent bone="IndexFingerProx.R" parent="Hand.R" />
-//        <boneparent bone="Handle.L" parent="Hand.L" />
-//        <boneparent bone="RingFingerProx.R" parent="Hand.R" />
-//        <boneparent bone="LowerLip" parent="Jaw" />
-//        <boneparent bone="Neck" parent="Chest" />
-//        <boneparent bone="TongueBase" parent="Jaw" />
-//        <boneparent bone="Head" parent="Neck" />
-//        <boneparent bone="Sheath.R" parent="Chest" />
-//        <boneparent bone="Stomach" parent="Waist" />
-//        <boneparent bone="Toe.L" parent="Foot.L" />
-//        <boneparent bone="MiddleFingerProx.L" parent="Hand.L" />
-//        <boneparent bone="RingFingerMed.L" parent="RingFingerProx.L" />
-//        <boneparent bone="PinkyMed.L" parent="PinkyProx.L" />
-//        <boneparent bone="MiddleFingerMed.R" parent="MiddleFingerProx.R" />
-//        <boneparent bone="ThumbProx.L" parent="Hand.L" />
-//        <boneparent bone="PinkyMed.R" parent="PinkyProx.R" />
-//        <boneparent bone="Clavicle.L" parent="Chest" />
-//        <boneparent bone="MiddleFingerProx.R" parent="Hand.R" />
-//        <boneparent bone="Toe.R" parent="Foot.R" />
-//        <boneparent bone="Sheath.L" parent="Chest" />
-//        <boneparent bone="TongueTip" parent="TongueMid" />
-//        <boneparent bone="RingFingerProx.L" parent="Hand.L" />
-//        <boneparent bone="Waist" parent="Root" />
-//        <boneparent bone="MiddleFingerDist.R" parent="MiddleFingerMed.R" />
-//        <boneparent bone="Hand.L" parent="Ulna.L" />
-//        <boneparent bone="Humerus.R" parent="Clavicle.R" />
-//        <boneparent bone="RingFingerDist.L" parent="RingFingerMed.L" />
-//        <boneparent bone="Eye.L" parent="Head" />
-//        <boneparent bone="Humerus.L" parent="Clavicle.L" />
-//        <boneparent bone="RingFingerDist.R" parent="RingFingerMed.R" />
-//        <boneparent bone="MiddleFingerDist.L" parent="MiddleFingerMed.L" />
-//        <boneparent bone="IndexFingerMed.L" parent="IndexFingerProx.L" />
-//        <boneparent bone="ThumbMed.L" parent="ThumbProx.L" />
-//        <boneparent bone="Thigh.L" parent="Root" />
-//        <boneparent bone="UpperLip" parent="Head" />
-//        <boneparent bone="RingFingerMed.R" parent="RingFingerProx.R" />
-//        <boneparent bone="Eye.R" parent="Head" />
-//        <boneparent bone="Brow.L" parent="Head" />
-//        <boneparent bone="Brow.C" parent="Head" />
-//        <boneparent bone="Calf.L" parent="Thigh.L" />
-//        <boneparent bone="PinkyProx.L" parent="Hand.L" />
-//        <boneparent bone="ThumbDist.L" parent="ThumbMed.L" />
-//        <boneparent bone="ThumbProx.R" parent="Hand.R" />
-//        <boneparent bone="ThumbDist.R" parent="ThumbMed.R" />
-//        <boneparent bone="Calf.R" parent="Thigh.R" />
-//        <boneparent bone="PinkyProx.R" parent="Hand.R" />
-//        <boneparent bone="IndexFingerProx.L" parent="Hand.L" />
-//        <boneparent bone="Brow.R" parent="Head" />
-//        <boneparent bone="Thigh.R" parent="Root" />
-
     }
 
-    private void bulletTime() {
-        speed = 0.1f;
-        elTime = 0;
-    }
     float elTime = 0;
     boolean forward = true;
 
+    AnimControl animControl;
+    AnimChannel animChannel;
+    Vector3f direction = new Vector3f(0, 0, 1);
+    Quaternion rotate = new Quaternion().fromAngleAxis(FastMath.PI / 8, Vector3f.UNIT_Y);
+    boolean dance = true;
+
     @Override
     public void simpleUpdate(float tpf) {
-        //  System.out.println(model.getLocalTranslation());
-//        elTime += tpf;
-//        if (elTime > 0.05f && speed < 1.0f) {
-//            speed += tpf * 8;
-//        }
-//        timer += tpf;
-        fpsText.setText("Bullet Size: " + bulletSize);
-        if (!ragdoll.hasControl()) {
+        elTime += tpf;
+        if (elTime > 3) {
+            elTime = 0;
+            if (dance) {
+                rotate.multLocal(direction);
+            }
+            if (Math.random() > 0.80) {
+                dance = true;
+                animChannel.setAnim("Dance");
+            } else {
+                dance = false;
+                animChannel.setAnim("RunBase");
+                rotate.fromAngleAxis(FastMath.QUARTER_PI * ((float) Math.random() - 0.5f), Vector3f.UNIT_Y);
+                rotate.multLocal(direction);
+            }
+        }
+        if (!ragdoll.hasControl() && !dance) {
             if (model.getLocalTranslation().getZ() < -10) {
-                forward = true;
+                direction.z = 1;
+                direction.normalizeLocal();
             } else if (model.getLocalTranslation().getZ() > 10) {
-                forward = false;
+                direction.z = -1;
+                direction.normalizeLocal();
             }
-            if (forward) {
-                model.move(-tpf, 0, tpf);
-            } else {
-                model.move(tpf, 0, -tpf);
+            if (model.getLocalTranslation().getX() < -10) {
+                direction.x = 1;
+                direction.normalizeLocal();
+            } else if (model.getLocalTranslation().getX() > 10) {
+                direction.x = -1;
+                direction.normalizeLocal();
             }
+            model.move(direction.multLocal(tpf * 8));
+            direction.normalizeLocal();
+            model.lookAt(model.getLocalTranslation().add(direction), Vector3f.UNIT_Y);
         }
     }
 }