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 */ 32package com.jme3.bullet.objects; 33 34import com.jme3.bullet.collision.PhysicsCollisionObject; 35import com.jme3.bullet.collision.shapes.CollisionShape; 36import com.jme3.export.InputCapsule; 37import com.jme3.export.JmeExporter; 38import com.jme3.export.JmeImporter; 39import com.jme3.export.OutputCapsule; 40import com.jme3.math.Quaternion; 41import com.jme3.math.Vector3f; 42import java.io.IOException; 43import java.util.logging.Level; 44import java.util.logging.Logger; 45 46/** 47 * Basic Bullet Character 48 * @author normenhansen 49 */ 50public 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