1 /* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5 package com.jme3.bullet.control; 6 7 import com.jme3.bullet.PhysicsSpace; 8 import com.jme3.bullet.collision.shapes.CollisionShape; 9 import com.jme3.bullet.objects.PhysicsCharacter; 10 import com.jme3.export.InputCapsule; 11 import com.jme3.export.JmeExporter; 12 import com.jme3.export.JmeImporter; 13 import com.jme3.export.OutputCapsule; 14 import com.jme3.math.Quaternion; 15 import com.jme3.math.Vector3f; 16 import com.jme3.renderer.RenderManager; 17 import com.jme3.renderer.ViewPort; 18 import com.jme3.scene.Spatial; 19 import com.jme3.scene.control.Control; 20 import java.io.IOException; 21 22 /** 23 * 24 * @author normenhansen 25 */ 26 public class CharacterControl extends PhysicsCharacter implements PhysicsControl { 27 28 protected Spatial spatial; 29 protected boolean enabled = true; 30 protected boolean added = false; 31 protected PhysicsSpace space = null; 32 protected Vector3f viewDirection = new Vector3f(Vector3f.UNIT_Z); 33 protected boolean useViewDirection = true; 34 protected boolean applyLocal = false; 35 36 public CharacterControl() { 37 } 38 39 public CharacterControl(CollisionShape shape, float stepHeight) { 40 super(shape, stepHeight); 41 } 42 43 public boolean isApplyPhysicsLocal() { 44 return applyLocal; 45 } 46 47 /** 48 * When set to true, the physics coordinates will be applied to the local 49 * translation of the Spatial 50 * @param applyPhysicsLocal 51 */ 52 public void setApplyPhysicsLocal(boolean applyPhysicsLocal) { 53 applyLocal = applyPhysicsLocal; 54 } 55 56 private Vector3f getSpatialTranslation() { 57 if (applyLocal) { 58 return spatial.getLocalTranslation(); 59 } 60 return spatial.getWorldTranslation(); 61 } 62 63 public Control cloneForSpatial(Spatial spatial) { 64 CharacterControl control = new CharacterControl(collisionShape, stepHeight); 65 control.setCcdMotionThreshold(getCcdMotionThreshold()); 66 control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); 67 control.setCollideWithGroups(getCollideWithGroups()); 68 control.setCollisionGroup(getCollisionGroup()); 69 control.setFallSpeed(getFallSpeed()); 70 control.setGravity(getGravity()); 71 control.setJumpSpeed(getJumpSpeed()); 72 control.setMaxSlope(getMaxSlope()); 73 control.setPhysicsLocation(getPhysicsLocation()); 74 control.setUpAxis(getUpAxis()); 75 control.setApplyPhysicsLocal(isApplyPhysicsLocal()); 76 77 control.setSpatial(spatial); 78 return control; 79 } 80 81 public void setSpatial(Spatial spatial) { 82 if (getUserObject() == null || getUserObject() == this.spatial) { 83 setUserObject(spatial); 84 } 85 this.spatial = spatial; 86 if (spatial == null) { 87 if (getUserObject() == spatial) { 88 setUserObject(null); 89 } 90 return; 91 } 92 setPhysicsLocation(getSpatialTranslation()); 93 } 94 95 public void setEnabled(boolean enabled) { 96 this.enabled = enabled; 97 if (space != null) { 98 if (enabled && !added) { 99 if (spatial != null) { 100 warp(getSpatialTranslation()); 101 } 102 space.addCollisionObject(this); 103 added = true; 104 } else if (!enabled && added) { 105 space.removeCollisionObject(this); 106 added = false; 107 } 108 } 109 } 110 111 public boolean isEnabled() { 112 return enabled; 113 } 114 115 public void setViewDirection(Vector3f vec) { 116 viewDirection.set(vec); 117 } 118 119 public Vector3f getViewDirection() { 120 return viewDirection; 121 } 122 123 public boolean isUseViewDirection() { 124 return useViewDirection; 125 } 126 127 public void setUseViewDirection(boolean viewDirectionEnabled) { 128 this.useViewDirection = viewDirectionEnabled; 129 } 130 131 public void update(float tpf) { 132 if (enabled && spatial != null) { 133 Quaternion localRotationQuat = spatial.getLocalRotation(); 134 Vector3f localLocation = spatial.getLocalTranslation(); 135 if (!applyLocal && spatial.getParent() != null) { 136 getPhysicsLocation(localLocation); 137 localLocation.subtractLocal(spatial.getParent().getWorldTranslation()); 138 localLocation.divideLocal(spatial.getParent().getWorldScale()); 139 tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation); 140 spatial.setLocalTranslation(localLocation); 141 142 if (useViewDirection) { 143 localRotationQuat.lookAt(viewDirection, Vector3f.UNIT_Y); 144 spatial.setLocalRotation(localRotationQuat); 145 } 146 } else { 147 spatial.setLocalTranslation(getPhysicsLocation()); 148 localRotationQuat.lookAt(viewDirection, Vector3f.UNIT_Y); 149 spatial.setLocalRotation(localRotationQuat); 150 } 151 } 152 } 153 154 public void render(RenderManager rm, ViewPort vp) { 155 if (enabled && space != null && space.getDebugManager() != null) { 156 if (debugShape == null) { 157 attachDebugShape(space.getDebugManager()); 158 } 159 debugShape.setLocalTranslation(getPhysicsLocation()); 160 debugShape.updateLogicalState(0); 161 debugShape.updateGeometricState(); 162 rm.renderScene(debugShape, vp); 163 } 164 } 165 166 public void setPhysicsSpace(PhysicsSpace space) { 167 if (space == null) { 168 if (this.space != null) { 169 this.space.removeCollisionObject(this); 170 added = false; 171 } 172 } else { 173 if (this.space == space) { 174 return; 175 } 176 space.addCollisionObject(this); 177 added = true; 178 } 179 this.space = space; 180 } 181 182 public PhysicsSpace getPhysicsSpace() { 183 return space; 184 } 185 186 @Override 187 public void write(JmeExporter ex) throws IOException { 188 super.write(ex); 189 OutputCapsule oc = ex.getCapsule(this); 190 oc.write(enabled, "enabled", true); 191 oc.write(applyLocal, "applyLocalPhysics", false); 192 oc.write(useViewDirection, "viewDirectionEnabled", true); 193 oc.write(viewDirection, "viewDirection", new Vector3f(Vector3f.UNIT_Z)); 194 oc.write(spatial, "spatial", null); 195 } 196 197 @Override 198 public void read(JmeImporter im) throws IOException { 199 super.read(im); 200 InputCapsule ic = im.getCapsule(this); 201 enabled = ic.readBoolean("enabled", true); 202 useViewDirection = ic.readBoolean("viewDirectionEnabled", true); 203 viewDirection = (Vector3f) ic.readSavable("viewDirection", new Vector3f(Vector3f.UNIT_Z)); 204 applyLocal = ic.readBoolean("applyLocalPhysics", false); 205 spatial = (Spatial) ic.readSavable("spatial", null); 206 setUserObject(spatial); 207 } 208 } 209