Home | History | Annotate | Download | only in objects
      1 /*
      2  * Copyright (c) 2009-2010 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.jme3.bullet.collision.PhysicsCollisionObject;
     35 import com.jme3.bullet.collision.shapes.CollisionShape;
     36 import com.jme3.export.InputCapsule;
     37 import com.jme3.export.JmeExporter;
     38 import com.jme3.export.JmeImporter;
     39 import com.jme3.export.OutputCapsule;
     40 import com.jme3.math.Quaternion;
     41 import com.jme3.math.Vector3f;
     42 import java.io.IOException;
     43 import java.util.logging.Level;
     44 import java.util.logging.Logger;
     45 
     46 /**
     47  * Basic Bullet Character
     48  * @author normenhansen
     49  */
     50 public class PhysicsCharacter extends PhysicsCollisionObject {
     51 
     52     protected long characterId = 0;
     53     protected float stepHeight;
     54     protected Vector3f walkDirection = new Vector3f();
     55     protected float fallSpeed = 55.0f;
     56     protected float jumpSpeed = 10.0f;
     57     protected int upAxis = 1;
     58     protected boolean locationDirty = false;
     59     //TEMP VARIABLES
     60     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
     61 
     62     public PhysicsCharacter() {
     63     }
     64 
     65     /**
     66      * @param shape The CollisionShape (no Mesh or CompoundCollisionShapes)
     67      * @param stepHeight The quantization size for vertical movement
     68      */
     69     public PhysicsCharacter(CollisionShape shape, float stepHeight) {
     70         this.collisionShape = shape;
     71 //        if (shape instanceof MeshCollisionShape ||shape instanceof CompoundCollisionShape) {
     72 //            throw (new UnsupportedOperationException("Kinematic character nodes cannot have mesh or compound collision shapes"));
     73 //        }
     74         this.stepHeight = stepHeight;
     75         buildObject();
     76     }
     77 
     78     protected void buildObject() {
     79         if (objectId == 0) {
     80             objectId = createGhostObject();
     81             Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Creating GhostObject {0}", Long.toHexString(objectId));
     82             initUserPointer();
     83         }
     84         setCharacterFlags(objectId);
     85         attachCollisionShape(objectId, collisionShape.getObjectId());
     86         if (characterId != 0) {
     87             Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Clearing Character {0}", Long.toHexString(objectId));
     88             finalizeNativeCharacter(characterId);
     89         }
     90         characterId = createCharacterObject(objectId, collisionShape.getObjectId(), stepHeight);
     91         Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Creating Character {0}", Long.toHexString(characterId));
     92     }
     93 
     94     private native long createGhostObject();
     95 
     96     private native void setCharacterFlags(long objectId);
     97 
     98     private native long createCharacterObject(long objectId, long shapeId, float stepHeight);
     99 
    100     /**
    101      * Sets the location of this physics character
    102      * @param location
    103      */
    104     public void warp(Vector3f location) {
    105         warp(characterId, location);
    106     }
    107 
    108     private native void warp(long characterId, Vector3f location);
    109 
    110     /**
    111      * Set the walk direction, works continuously.
    112      * This should probably be called setPositionIncrementPerSimulatorStep.
    113      * This is neither a direction nor a velocity, but the amount to
    114      * increment the position each physics tick. So vector length = accuracy*speed in m/s
    115      * @param vec the walk direction to set
    116      */
    117     public void setWalkDirection(Vector3f vec) {
    118         walkDirection.set(vec);
    119         setWalkDirection(characterId, vec);
    120     }
    121 
    122     private native void setWalkDirection(long characterId, Vector3f vec);
    123 
    124     /**
    125      * @return the currently set walkDirection
    126      */
    127     public Vector3f getWalkDirection() {
    128         return walkDirection;
    129     }
    130 
    131     public void setUpAxis(int axis) {
    132         upAxis = axis;
    133         setUpAxis(characterId, axis);
    134     }
    135 
    136     private native void setUpAxis(long characterId, int axis);
    137 
    138     public int getUpAxis() {
    139         return upAxis;
    140     }
    141 
    142     public void setFallSpeed(float fallSpeed) {
    143         this.fallSpeed = fallSpeed;
    144         setFallSpeed(characterId, fallSpeed);
    145     }
    146 
    147     private native void setFallSpeed(long characterId, float fallSpeed);
    148 
    149     public float getFallSpeed() {
    150         return fallSpeed;
    151     }
    152 
    153     public void setJumpSpeed(float jumpSpeed) {
    154         this.jumpSpeed = jumpSpeed;
    155         setJumpSpeed(characterId, jumpSpeed);
    156     }
    157 
    158     private native void setJumpSpeed(long characterId, float jumpSpeed);
    159 
    160     public float getJumpSpeed() {
    161         return jumpSpeed;
    162     }
    163 
    164     public void setGravity(float value) {
    165         setGravity(characterId, value);
    166     }
    167 
    168     private native void setGravity(long characterId, float gravity);
    169 
    170     public float getGravity() {
    171         return getGravity(characterId);
    172     }
    173 
    174     private native float getGravity(long characterId);
    175 
    176     public void setMaxSlope(float slopeRadians) {
    177         setMaxSlope(characterId, slopeRadians);
    178     }
    179 
    180     private native void setMaxSlope(long characterId, float slopeRadians);
    181 
    182     public float getMaxSlope() {
    183         return getMaxSlope(characterId);
    184     }
    185 
    186     private native float getMaxSlope(long characterId);
    187 
    188     public boolean onGround() {
    189         return onGround(characterId);
    190     }
    191 
    192     private native boolean onGround(long characterId);
    193 
    194     public void jump() {
    195         jump(characterId);
    196     }
    197 
    198     private native void jump(long characterId);
    199 
    200     @Override
    201     public void setCollisionShape(CollisionShape collisionShape) {
    202 //        if (!(collisionShape.getObjectId() instanceof ConvexShape)) {
    203 //            throw (new UnsupportedOperationException("Kinematic character nodes cannot have mesh collision shapes"));
    204 //        }
    205         super.setCollisionShape(collisionShape);
    206         if (objectId == 0) {
    207             buildObject();
    208         } else {
    209             attachCollisionShape(objectId, collisionShape.getObjectId());
    210         }
    211     }
    212 
    213     /**
    214      * Set the physics location (same as warp())
    215      * @param location the location of the actual physics object
    216      */
    217     public void setPhysicsLocation(Vector3f location) {
    218         warp(location);
    219     }
    220 
    221     /**
    222      * @return the physicsLocation
    223      */
    224     public Vector3f getPhysicsLocation(Vector3f trans) {
    225         if (trans == null) {
    226             trans = new Vector3f();
    227         }
    228         getPhysicsLocation(objectId, trans);
    229         return trans;
    230     }
    231 
    232     private native void getPhysicsLocation(long objectId, Vector3f vec);
    233 
    234     /**
    235      * @return the physicsLocation
    236      */
    237     public Vector3f getPhysicsLocation() {
    238         return getPhysicsLocation(null);
    239     }
    240 
    241     public void setCcdSweptSphereRadius(float radius) {
    242         setCcdSweptSphereRadius(objectId, radius);
    243     }
    244 
    245     private native void setCcdSweptSphereRadius(long objectId, float radius);
    246 
    247     public void setCcdMotionThreshold(float threshold) {
    248         setCcdMotionThreshold(objectId, threshold);
    249     }
    250 
    251     private native void setCcdMotionThreshold(long objectId, float threshold);
    252 
    253     public float getCcdSweptSphereRadius() {
    254         return getCcdSweptSphereRadius(objectId);
    255     }
    256 
    257     private native float getCcdSweptSphereRadius(long objectId);
    258 
    259     public float getCcdMotionThreshold() {
    260         return getCcdMotionThreshold(objectId);
    261     }
    262 
    263     private native float getCcdMotionThreshold(long objectId);
    264 
    265     public float getCcdSquareMotionThreshold() {
    266         return getCcdSquareMotionThreshold(objectId);
    267     }
    268 
    269     private native float getCcdSquareMotionThreshold(long objectId);
    270 
    271     /**
    272      * used internally
    273      */
    274     public long getControllerId() {
    275         return characterId;
    276     }
    277 
    278     public void destroy() {
    279     }
    280 
    281     @Override
    282     public void write(JmeExporter e) throws IOException {
    283         super.write(e);
    284         OutputCapsule capsule = e.getCapsule(this);
    285         capsule.write(stepHeight, "stepHeight", 1.0f);
    286         capsule.write(getGravity(), "gravity", 9.8f * 3);
    287         capsule.write(getMaxSlope(), "maxSlope", 1.0f);
    288         capsule.write(fallSpeed, "fallSpeed", 55.0f);
    289         capsule.write(jumpSpeed, "jumpSpeed", 10.0f);
    290         capsule.write(upAxis, "upAxis", 1);
    291         capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0);
    292         capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
    293         capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
    294     }
    295 
    296     @Override
    297     public void read(JmeImporter e) throws IOException {
    298         super.read(e);
    299         InputCapsule capsule = e.getCapsule(this);
    300         stepHeight = capsule.readFloat("stepHeight", 1.0f);
    301         buildObject();
    302         setGravity(capsule.readFloat("gravity", 9.8f * 3));
    303         setMaxSlope(capsule.readFloat("maxSlope", 1.0f));
    304         setFallSpeed(capsule.readFloat("fallSpeed", 55.0f));
    305         setJumpSpeed(capsule.readFloat("jumpSpeed", 10.0f));
    306         setUpAxis(capsule.readInt("upAxis", 1));
    307         setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));
    308         setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0));
    309         setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
    310     }
    311 
    312     @Override
    313     protected void finalize() throws Throwable {
    314         super.finalize();
    315         finalizeNativeCharacter(characterId);
    316     }
    317 
    318     private native void finalizeNativeCharacter(long characterId);
    319 }
    320