Home | History | Annotate | Download | only in objects
      1 /*
      2  * Copyright (c) 2009-2012 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.bullet.objects;
     33 
     34 import com.bulletphysics.collision.dispatch.CollisionFlags;
     35 import com.bulletphysics.dynamics.RigidBody;
     36 import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
     37 import com.bulletphysics.linearmath.Transform;
     38 import com.jme3.bullet.PhysicsSpace;
     39 import com.jme3.bullet.collision.PhysicsCollisionObject;
     40 import com.jme3.bullet.collision.shapes.CollisionShape;
     41 import com.jme3.bullet.collision.shapes.MeshCollisionShape;
     42 import com.jme3.bullet.joints.PhysicsJoint;
     43 import com.jme3.bullet.objects.infos.RigidBodyMotionState;
     44 import com.jme3.bullet.util.Converter;
     45 import com.jme3.export.InputCapsule;
     46 import com.jme3.export.JmeExporter;
     47 import com.jme3.export.JmeImporter;
     48 import com.jme3.export.OutputCapsule;
     49 import com.jme3.math.Matrix3f;
     50 import com.jme3.math.Quaternion;
     51 import com.jme3.math.Vector3f;
     52 import com.jme3.scene.Geometry;
     53 import com.jme3.scene.Node;
     54 import com.jme3.scene.Spatial;
     55 import com.jme3.scene.debug.Arrow;
     56 import java.io.IOException;
     57 import java.util.ArrayList;
     58 import java.util.Iterator;
     59 import java.util.List;
     60 
     61 /**
     62  * <p>PhysicsRigidBody - Basic physics object</p>
     63  * @author normenhansen
     64  */
     65 public class PhysicsRigidBody extends PhysicsCollisionObject {
     66 
     67     protected RigidBodyConstructionInfo constructionInfo;
     68     protected RigidBody rBody;
     69     protected RigidBodyMotionState motionState = new RigidBodyMotionState();
     70     protected float mass = 1.0f;
     71     protected boolean kinematic = false;
     72     protected javax.vecmath.Vector3f tempVec = new javax.vecmath.Vector3f();
     73     protected javax.vecmath.Vector3f tempVec2 = new javax.vecmath.Vector3f();
     74     protected Transform tempTrans = new Transform(new javax.vecmath.Matrix3f());
     75     protected javax.vecmath.Matrix3f tempMatrix = new javax.vecmath.Matrix3f();
     76     //TEMP VARIABLES
     77     protected javax.vecmath.Vector3f localInertia = new javax.vecmath.Vector3f();
     78     protected ArrayList<PhysicsJoint> joints = new ArrayList<PhysicsJoint>();
     79 
     80     public PhysicsRigidBody() {
     81     }
     82 
     83     /**
     84      * Creates a new PhysicsRigidBody with the supplied collision shape
     85      * @param shape
     86      */
     87     public PhysicsRigidBody(CollisionShape shape) {
     88         collisionShape = shape;
     89         rebuildRigidBody();
     90     }
     91 
     92     public PhysicsRigidBody(CollisionShape shape, float mass) {
     93         collisionShape = shape;
     94         this.mass = mass;
     95         rebuildRigidBody();
     96     }
     97 
     98     /**
     99      * Builds/rebuilds the phyiscs body when parameters have changed
    100      */
    101     protected void rebuildRigidBody() {
    102         boolean removed = false;
    103         if(collisionShape instanceof MeshCollisionShape && mass != 0){
    104             throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
    105         }
    106         if (rBody != null) {
    107             if (rBody.isInWorld()) {
    108                 PhysicsSpace.getPhysicsSpace().remove(this);
    109                 removed = true;
    110             }
    111             rBody.destroy();
    112         }
    113         preRebuild();
    114         rBody = new RigidBody(constructionInfo);
    115         postRebuild();
    116         if (removed) {
    117             PhysicsSpace.getPhysicsSpace().add(this);
    118         }
    119     }
    120 
    121     protected void preRebuild() {
    122         collisionShape.calculateLocalInertia(mass, localInertia);
    123         if (constructionInfo == null) {
    124             constructionInfo = new RigidBodyConstructionInfo(mass, motionState, collisionShape.getCShape(), localInertia);
    125         } else {
    126             constructionInfo.mass = mass;
    127             constructionInfo.collisionShape = collisionShape.getCShape();
    128             constructionInfo.motionState = motionState;
    129         }
    130     }
    131 
    132     protected void postRebuild() {
    133         rBody.setUserPointer(this);
    134         if (mass == 0.0f) {
    135             rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT);
    136         } else {
    137             rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT);
    138         }
    139     }
    140 
    141     /**
    142      * @return the motionState
    143      */
    144     public RigidBodyMotionState getMotionState() {
    145         return motionState;
    146     }
    147 
    148     /**
    149      * Sets the physics object location
    150      * @param location the location of the actual physics object
    151      */
    152     public void setPhysicsLocation(Vector3f location) {
    153         rBody.getCenterOfMassTransform(tempTrans);
    154         Converter.convert(location, tempTrans.origin);
    155         rBody.setCenterOfMassTransform(tempTrans);
    156         motionState.setWorldTransform(tempTrans);
    157     }
    158 
    159     /**
    160      * Sets the physics object rotation
    161      * @param rotation the rotation of the actual physics object
    162      */
    163     public void setPhysicsRotation(Matrix3f rotation) {
    164         rBody.getCenterOfMassTransform(tempTrans);
    165         Converter.convert(rotation, tempTrans.basis);
    166         rBody.setCenterOfMassTransform(tempTrans);
    167         motionState.setWorldTransform(tempTrans);
    168     }
    169 
    170     /**
    171      * Sets the physics object rotation
    172      * @param rotation the rotation of the actual physics object
    173      */
    174     public void setPhysicsRotation(Quaternion rotation) {
    175         rBody.getCenterOfMassTransform(tempTrans);
    176         Converter.convert(rotation, tempTrans.basis);
    177         rBody.setCenterOfMassTransform(tempTrans);
    178         motionState.setWorldTransform(tempTrans);
    179     }
    180 
    181     /**
    182      * Gets the physics object location, instantiates a new Vector3f object
    183      */
    184     public Vector3f getPhysicsLocation() {
    185         return getPhysicsLocation(null);
    186     }
    187 
    188     /**
    189      * Gets the physics object rotation
    190      */
    191     public Matrix3f getPhysicsRotationMatrix() {
    192         return getPhysicsRotationMatrix(null);
    193     }
    194 
    195     /**
    196      * Gets the physics object location, no object instantiation
    197      * @param location the location of the actual physics object is stored in this Vector3f
    198      */
    199     public Vector3f getPhysicsLocation(Vector3f location) {
    200         if (location == null) {
    201             location = new Vector3f();
    202         }
    203         rBody.getCenterOfMassTransform(tempTrans);
    204         return Converter.convert(tempTrans.origin, location);
    205     }
    206 
    207     /**
    208      * Gets the physics object rotation as a matrix, no conversions and no object instantiation
    209      * @param rotation the rotation of the actual physics object is stored in this Matrix3f
    210      */
    211     public Matrix3f getPhysicsRotationMatrix(Matrix3f rotation) {
    212         if (rotation == null) {
    213             rotation = new Matrix3f();
    214         }
    215         rBody.getCenterOfMassTransform(tempTrans);
    216         return Converter.convert(tempTrans.basis, rotation);
    217     }
    218 
    219     /**
    220      * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value,
    221      * instantiates new object
    222      */
    223     public Quaternion getPhysicsRotation(){
    224         return getPhysicsRotation(null);
    225     }
    226 
    227     /**
    228      * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value
    229      * @param rotation the rotation of the actual physics object is stored in this Quaternion
    230      */
    231     public Quaternion getPhysicsRotation(Quaternion rotation){
    232         if (rotation == null) {
    233             rotation = new Quaternion();
    234         }
    235         rBody.getCenterOfMassTransform(tempTrans);
    236         return Converter.convert(tempTrans.basis, rotation);
    237     }
    238 
    239     /**
    240      * Gets the physics object location
    241      * @param location the location of the actual physics object is stored in this Vector3f
    242      */
    243     public Vector3f getInterpolatedPhysicsLocation(Vector3f location) {
    244         if (location == null) {
    245             location = new Vector3f();
    246         }
    247         rBody.getInterpolationWorldTransform(tempTrans);
    248         return Converter.convert(tempTrans.origin, location);
    249     }
    250 
    251     /**
    252      * Gets the physics object rotation
    253      * @param rotation the rotation of the actual physics object is stored in this Matrix3f
    254      */
    255     public Matrix3f getInterpolatedPhysicsRotation(Matrix3f rotation) {
    256         if (rotation == null) {
    257             rotation = new Matrix3f();
    258         }
    259         rBody.getInterpolationWorldTransform(tempTrans);
    260         return Converter.convert(tempTrans.basis, rotation);
    261     }
    262 
    263     /**
    264      * Sets the node to kinematic mode. in this mode the node is not affected by physics
    265      * but affects other physics objects. Its kinetic force is calculated by the amount
    266      * of movement it is exposed to and its weight.
    267      * @param kinematic
    268      */
    269     public void setKinematic(boolean kinematic) {
    270         this.kinematic = kinematic;
    271         if (kinematic) {
    272             rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
    273             rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.DISABLE_DEACTIVATION);
    274         } else {
    275             rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.KINEMATIC_OBJECT);
    276             rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.ACTIVE_TAG);
    277         }
    278     }
    279 
    280     public boolean isKinematic() {
    281         return kinematic;
    282     }
    283 
    284     public void setCcdSweptSphereRadius(float radius) {
    285         rBody.setCcdSweptSphereRadius(radius);
    286     }
    287 
    288     /**
    289      * Sets the amount of motion that has to happen in one physics tick to trigger the continuous motion detection<br/>
    290      * This avoids the problem of fast objects moving through other objects, set to zero to disable (default)
    291      * @param threshold
    292      */
    293     public void setCcdMotionThreshold(float threshold) {
    294         rBody.setCcdMotionThreshold(threshold);
    295     }
    296 
    297     public float getCcdSweptSphereRadius() {
    298         return rBody.getCcdSweptSphereRadius();
    299     }
    300 
    301     public float getCcdMotionThreshold() {
    302         return rBody.getCcdMotionThreshold();
    303     }
    304 
    305     public float getCcdSquareMotionThreshold() {
    306         return rBody.getCcdSquareMotionThreshold();
    307     }
    308 
    309     public float getMass() {
    310         return mass;
    311     }
    312 
    313     /**
    314      * Sets the mass of this PhysicsRigidBody, objects with mass=0 are static.
    315      * @param mass
    316      */
    317     public void setMass(float mass) {
    318         this.mass = mass;
    319         if(collisionShape instanceof MeshCollisionShape && mass != 0){
    320             throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
    321         }
    322         if (collisionShape != null) {
    323             collisionShape.calculateLocalInertia(mass, localInertia);
    324         }
    325         if (rBody != null) {
    326             rBody.setMassProps(mass, localInertia);
    327             if (mass == 0.0f) {
    328                 rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT);
    329             } else {
    330                 rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT);
    331             }
    332         }
    333     }
    334 
    335     public Vector3f getGravity() {
    336         return getGravity(null);
    337     }
    338 
    339     public Vector3f getGravity(Vector3f gravity) {
    340         if (gravity == null) {
    341             gravity = new Vector3f();
    342         }
    343         rBody.getGravity(tempVec);
    344         return Converter.convert(tempVec, gravity);
    345     }
    346 
    347     /**
    348      * Set the local gravity of this PhysicsRigidBody<br/>
    349      * Set this after adding the node to the PhysicsSpace,
    350      * the PhysicsSpace assigns its current gravity to the physics node when its added.
    351      * @param gravity the gravity vector to set
    352      */
    353     public void setGravity(Vector3f gravity) {
    354         rBody.setGravity(Converter.convert(gravity, tempVec));
    355     }
    356 
    357     public float getFriction() {
    358         return rBody.getFriction();
    359     }
    360 
    361     /**
    362      * Sets the friction of this physics object
    363      * @param friction the friction of this physics object
    364      */
    365     public void setFriction(float friction) {
    366         constructionInfo.friction = friction;
    367         rBody.setFriction(friction);
    368     }
    369 
    370     public void setDamping(float linearDamping, float angularDamping) {
    371         constructionInfo.linearDamping = linearDamping;
    372         constructionInfo.angularDamping = angularDamping;
    373         rBody.setDamping(linearDamping, angularDamping);
    374     }
    375 
    376     public void setLinearDamping(float linearDamping) {
    377         constructionInfo.linearDamping = linearDamping;
    378         rBody.setDamping(linearDamping, constructionInfo.angularDamping);
    379     }
    380 
    381     public void setAngularDamping(float angularDamping) {
    382         constructionInfo.angularDamping = angularDamping;
    383         rBody.setDamping(constructionInfo.linearDamping, angularDamping);
    384     }
    385 
    386     public float getLinearDamping() {
    387         return constructionInfo.linearDamping;
    388     }
    389 
    390     public float getAngularDamping() {
    391         return constructionInfo.angularDamping;
    392     }
    393 
    394     public float getRestitution() {
    395         return rBody.getRestitution();
    396     }
    397 
    398     /**
    399      * The "bouncyness" of the PhysicsRigidBody, best performance if restitution=0
    400      * @param restitution
    401      */
    402     public void setRestitution(float restitution) {
    403         constructionInfo.restitution = restitution;
    404         rBody.setRestitution(restitution);
    405     }
    406 
    407     /**
    408      * Get the current angular velocity of this PhysicsRigidBody
    409      * @return the current linear velocity
    410      */
    411     public Vector3f getAngularVelocity() {
    412         return Converter.convert(rBody.getAngularVelocity(tempVec));
    413     }
    414 
    415     /**
    416      * Get the current angular velocity of this PhysicsRigidBody
    417      * @param vec the vector to store the velocity in
    418      */
    419     public void getAngularVelocity(Vector3f vec) {
    420         Converter.convert(rBody.getAngularVelocity(tempVec), vec);
    421     }
    422 
    423     /**
    424      * Sets the angular velocity of this PhysicsRigidBody
    425      * @param vec the angular velocity of this PhysicsRigidBody
    426      */
    427     public void setAngularVelocity(Vector3f vec) {
    428         rBody.setAngularVelocity(Converter.convert(vec, tempVec));
    429         rBody.activate();
    430     }
    431 
    432     /**
    433      * Get the current linear velocity of this PhysicsRigidBody
    434      * @return the current linear velocity
    435      */
    436     public Vector3f getLinearVelocity() {
    437         return Converter.convert(rBody.getLinearVelocity(tempVec));
    438     }
    439 
    440     /**
    441      * Get the current linear velocity of this PhysicsRigidBody
    442      * @param vec the vector to store the velocity in
    443      */
    444     public void getLinearVelocity(Vector3f vec) {
    445         Converter.convert(rBody.getLinearVelocity(tempVec), vec);
    446     }
    447 
    448     /**
    449      * Sets the linear velocity of this PhysicsRigidBody
    450      * @param vec the linear velocity of this PhysicsRigidBody
    451      */
    452     public void setLinearVelocity(Vector3f vec) {
    453         rBody.setLinearVelocity(Converter.convert(vec, tempVec));
    454         rBody.activate();
    455     }
    456 
    457     /**
    458      * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
    459      * updates the physics space.<br>
    460      * To apply an impulse, use applyImpulse, use applyContinuousForce to apply continuous force.
    461      * @param force the force
    462      * @param location the location of the force
    463      */
    464     public void applyForce(final Vector3f force, final Vector3f location) {
    465         rBody.applyForce(Converter.convert(force, tempVec), Converter.convert(location, tempVec2));
    466         rBody.activate();
    467     }
    468 
    469     /**
    470      * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
    471      * updates the physics space.<br>
    472      * To apply an impulse, use applyImpulse.
    473      *
    474      * @param force the force
    475      */
    476     public void applyCentralForce(final Vector3f force) {
    477         rBody.applyCentralForce(Converter.convert(force, tempVec));
    478         rBody.activate();
    479     }
    480 
    481     /**
    482      * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
    483      * updates the physics space.<br>
    484      * To apply an impulse, use applyImpulse.
    485      *
    486      * @param torque the torque
    487      */
    488     public void applyTorque(final Vector3f torque) {
    489         rBody.applyTorque(Converter.convert(torque, tempVec));
    490         rBody.activate();
    491     }
    492 
    493     /**
    494      * Apply an impulse to the PhysicsRigidBody in the next physics update.
    495      * @param impulse applied impulse
    496      * @param rel_pos location relative to object
    497      */
    498     public void applyImpulse(final Vector3f impulse, final Vector3f rel_pos) {
    499         rBody.applyImpulse(Converter.convert(impulse, tempVec), Converter.convert(rel_pos, tempVec2));
    500         rBody.activate();
    501     }
    502 
    503     /**
    504      * Apply a torque impulse to the PhysicsRigidBody in the next physics update.
    505      * @param vec
    506      */
    507     public void applyTorqueImpulse(final Vector3f vec) {
    508         rBody.applyTorqueImpulse(Converter.convert(vec, tempVec));
    509         rBody.activate();
    510     }
    511 
    512     /**
    513      * Clear all forces from the PhysicsRigidBody
    514      *
    515      */
    516     public void clearForces() {
    517         rBody.clearForces();
    518     }
    519 
    520     public void setCollisionShape(CollisionShape collisionShape) {
    521         super.setCollisionShape(collisionShape);
    522         if(collisionShape instanceof MeshCollisionShape && mass!=0){
    523             throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
    524         }
    525         if (rBody == null) {
    526             rebuildRigidBody();
    527         } else {
    528             collisionShape.calculateLocalInertia(mass, localInertia);
    529             constructionInfo.collisionShape = collisionShape.getCShape();
    530             rBody.setCollisionShape(collisionShape.getCShape());
    531         }
    532     }
    533 
    534     /**
    535      * reactivates this PhysicsRigidBody when it has been deactivated because it was not moving
    536      */
    537     public void activate() {
    538         rBody.activate();
    539     }
    540 
    541     public boolean isActive() {
    542         return rBody.isActive();
    543     }
    544 
    545     /**
    546      * sets the sleeping thresholds, these define when the object gets deactivated
    547      * to save ressources. Low values keep the object active when it barely moves
    548      * @param linear the linear sleeping threshold
    549      * @param angular the angular sleeping threshold
    550      */
    551     public void setSleepingThresholds(float linear, float angular) {
    552         constructionInfo.linearSleepingThreshold = linear;
    553         constructionInfo.angularSleepingThreshold = angular;
    554         rBody.setSleepingThresholds(linear, angular);
    555     }
    556 
    557     public void setLinearSleepingThreshold(float linearSleepingThreshold) {
    558         constructionInfo.linearSleepingThreshold = linearSleepingThreshold;
    559         rBody.setSleepingThresholds(linearSleepingThreshold, constructionInfo.angularSleepingThreshold);
    560     }
    561 
    562     public void setAngularSleepingThreshold(float angularSleepingThreshold) {
    563         constructionInfo.angularSleepingThreshold = angularSleepingThreshold;
    564         rBody.setSleepingThresholds(constructionInfo.linearSleepingThreshold, angularSleepingThreshold);
    565     }
    566 
    567     public float getLinearSleepingThreshold() {
    568         return constructionInfo.linearSleepingThreshold;
    569     }
    570 
    571     public float getAngularSleepingThreshold() {
    572         return constructionInfo.angularSleepingThreshold;
    573     }
    574 
    575     public float getAngularFactor() {
    576         return rBody.getAngularFactor();
    577     }
    578 
    579     public void setAngularFactor(float factor) {
    580         rBody.setAngularFactor(factor);
    581     }
    582 
    583     /**
    584      * do not use manually, joints are added automatically
    585      */
    586     public void addJoint(PhysicsJoint joint) {
    587         if (!joints.contains(joint)) {
    588             joints.add(joint);
    589         }
    590         updateDebugShape();
    591     }
    592 
    593     /**
    594      *
    595      */
    596     public void removeJoint(PhysicsJoint joint) {
    597         joints.remove(joint);
    598     }
    599 
    600     /**
    601      * Returns a list of connected joints. This list is only filled when
    602      * the PhysicsRigidBody is actually added to the physics space or loaded from disk.
    603      * @return list of active joints connected to this PhysicsRigidBody
    604      */
    605     public List<PhysicsJoint> getJoints() {
    606         return joints;
    607     }
    608 
    609     /**
    610      * used internally
    611      */
    612     public RigidBody getObjectId() {
    613         return rBody;
    614     }
    615 
    616     /**
    617      * destroys this PhysicsRigidBody and removes it from memory
    618      */
    619     public void destroy() {
    620         rBody.destroy();
    621     }
    622 
    623     @Override
    624     protected Spatial getDebugShape() {
    625         //add joints
    626         Spatial shape = super.getDebugShape();
    627         Node node = null;
    628         if (shape instanceof Node) {
    629             node = (Node) shape;
    630         } else {
    631             node = new Node("DebugShapeNode");
    632             node.attachChild(shape);
    633         }
    634         int i = 0;
    635         for (Iterator<PhysicsJoint> it = joints.iterator(); it.hasNext();) {
    636             PhysicsJoint physicsJoint = it.next();
    637             Vector3f pivot = null;
    638             if (physicsJoint.getBodyA() == this) {
    639                 pivot = physicsJoint.getPivotA();
    640             } else {
    641                 pivot = physicsJoint.getPivotB();
    642             }
    643             Arrow arrow = new Arrow(pivot);
    644             Geometry geom = new Geometry("DebugBone" + i, arrow);
    645             geom.setMaterial(debugMaterialGreen);
    646             node.attachChild(geom);
    647             i++;
    648         }
    649         return node;
    650     }
    651 
    652     @Override
    653     public void write(JmeExporter e) throws IOException {
    654         super.write(e);
    655         OutputCapsule capsule = e.getCapsule(this);
    656 
    657         capsule.write(getMass(), "mass", 1.0f);
    658 
    659         capsule.write(getGravity(), "gravity", Vector3f.ZERO);
    660         capsule.write(getFriction(), "friction", 0.5f);
    661         capsule.write(getRestitution(), "restitution", 0);
    662         capsule.write(getAngularFactor(), "angularFactor", 1);
    663         capsule.write(kinematic, "kinematic", false);
    664 
    665         capsule.write(constructionInfo.linearDamping, "linearDamping", 0);
    666         capsule.write(constructionInfo.angularDamping, "angularDamping", 0);
    667         capsule.write(constructionInfo.linearSleepingThreshold, "linearSleepingThreshold", 0.8f);
    668         capsule.write(constructionInfo.angularSleepingThreshold, "angularSleepingThreshold", 1.0f);
    669 
    670         capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0);
    671         capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
    672 
    673         capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
    674         capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f());
    675 
    676         capsule.writeSavableArrayList(joints, "joints", null);
    677     }
    678 
    679     @Override
    680     public void read(JmeImporter e) throws IOException {
    681         super.read(e);
    682 
    683         InputCapsule capsule = e.getCapsule(this);
    684         float mass = capsule.readFloat("mass", 1.0f);
    685         this.mass = mass;
    686         rebuildRigidBody();
    687         setGravity((Vector3f) capsule.readSavable("gravity", Vector3f.ZERO.clone()));
    688         setFriction(capsule.readFloat("friction", 0.5f));
    689         setKinematic(capsule.readBoolean("kinematic", false));
    690 
    691         setRestitution(capsule.readFloat("restitution", 0));
    692         setAngularFactor(capsule.readFloat("angularFactor", 1));
    693         setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0));
    694         setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f));
    695         setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));
    696         setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0));
    697 
    698         setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
    699         setPhysicsRotation((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f()));
    700 
    701         joints = capsule.readSavableArrayList("joints", null);
    702     }
    703 }
    704