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