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.PhysicsVehicle; 10 import com.jme3.bullet.objects.VehicleWheel; 11 import com.jme3.export.InputCapsule; 12 import com.jme3.export.JmeExporter; 13 import com.jme3.export.JmeImporter; 14 import com.jme3.export.OutputCapsule; 15 import com.jme3.math.Quaternion; 16 import com.jme3.math.Vector3f; 17 import com.jme3.renderer.RenderManager; 18 import com.jme3.renderer.ViewPort; 19 import com.jme3.scene.Geometry; 20 import com.jme3.scene.Node; 21 import com.jme3.scene.Spatial; 22 import com.jme3.scene.control.Control; 23 import com.jme3.scene.debug.Arrow; 24 import java.io.IOException; 25 import java.util.Iterator; 26 27 /** 28 * 29 * @author normenhansen 30 */ 31 public class VehicleControl extends PhysicsVehicle implements PhysicsControl { 32 33 protected Spatial spatial; 34 protected boolean enabled = true; 35 protected PhysicsSpace space = null; 36 protected boolean added = false; 37 VehicleControl()38 public VehicleControl() { 39 } 40 41 /** 42 * Creates a new PhysicsNode with the supplied collision shape 43 * @param shape 44 */ VehicleControl(CollisionShape shape)45 public VehicleControl(CollisionShape shape) { 46 super(shape); 47 } 48 VehicleControl(CollisionShape shape, float mass)49 public VehicleControl(CollisionShape shape, float mass) { 50 super(shape, mass); 51 } 52 isApplyPhysicsLocal()53 public boolean isApplyPhysicsLocal() { 54 return motionState.isApplyPhysicsLocal(); 55 } 56 57 /** 58 * When set to true, the physics coordinates will be applied to the local 59 * translation of the Spatial 60 * @param applyPhysicsLocal 61 */ setApplyPhysicsLocal(boolean applyPhysicsLocal)62 public void setApplyPhysicsLocal(boolean applyPhysicsLocal) { 63 motionState.setApplyPhysicsLocal(applyPhysicsLocal); 64 for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { 65 VehicleWheel vehicleWheel = it.next(); 66 vehicleWheel.setApplyLocal(applyPhysicsLocal); 67 } 68 } 69 getSpatialTranslation()70 private Vector3f getSpatialTranslation(){ 71 if(motionState.isApplyPhysicsLocal()){ 72 return spatial.getLocalTranslation(); 73 } 74 return spatial.getWorldTranslation(); 75 } 76 getSpatialRotation()77 private Quaternion getSpatialRotation(){ 78 if(motionState.isApplyPhysicsLocal()){ 79 return spatial.getLocalRotation(); 80 } 81 return spatial.getWorldRotation(); 82 } 83 cloneForSpatial(Spatial spatial)84 public Control cloneForSpatial(Spatial spatial) { 85 VehicleControl control = new VehicleControl(collisionShape, mass); 86 control.setAngularFactor(getAngularFactor()); 87 control.setAngularSleepingThreshold(getAngularSleepingThreshold()); 88 control.setAngularVelocity(getAngularVelocity()); 89 control.setCcdMotionThreshold(getCcdMotionThreshold()); 90 control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); 91 control.setCollideWithGroups(getCollideWithGroups()); 92 control.setCollisionGroup(getCollisionGroup()); 93 control.setDamping(getLinearDamping(), getAngularDamping()); 94 control.setFriction(getFriction()); 95 control.setGravity(getGravity()); 96 control.setKinematic(isKinematic()); 97 control.setLinearSleepingThreshold(getLinearSleepingThreshold()); 98 control.setLinearVelocity(getLinearVelocity()); 99 control.setPhysicsLocation(getPhysicsLocation()); 100 control.setPhysicsRotation(getPhysicsRotationMatrix()); 101 control.setRestitution(getRestitution()); 102 103 control.setFrictionSlip(getFrictionSlip()); 104 control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm()); 105 control.setSuspensionStiffness(getSuspensionStiffness()); 106 control.setSuspensionCompression(tuning.suspensionCompression); 107 control.setSuspensionDamping(tuning.suspensionDamping); 108 control.setMaxSuspensionForce(getMaxSuspensionForce()); 109 110 for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { 111 VehicleWheel wheel = it.next(); 112 VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel()); 113 newWheel.setFrictionSlip(wheel.getFrictionSlip()); 114 newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm()); 115 newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness()); 116 newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression()); 117 newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation()); 118 newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce()); 119 120 //TODO: bad way finding children! 121 if (spatial instanceof Node) { 122 Node node = (Node) spatial; 123 Spatial wheelSpat = node.getChild(wheel.getWheelSpatial().getName()); 124 if (wheelSpat != null) { 125 newWheel.setWheelSpatial(wheelSpat); 126 } 127 } 128 } 129 control.setApplyPhysicsLocal(isApplyPhysicsLocal()); 130 131 control.setSpatial(spatial); 132 return control; 133 } 134 setSpatial(Spatial spatial)135 public void setSpatial(Spatial spatial) { 136 if (getUserObject() == null || getUserObject() == this.spatial) { 137 setUserObject(spatial); 138 } 139 this.spatial = spatial; 140 if (spatial == null) { 141 if (getUserObject() == spatial) { 142 setUserObject(null); 143 } 144 this.spatial = null; 145 this.collisionShape = null; 146 return; 147 } 148 setPhysicsLocation(getSpatialTranslation()); 149 setPhysicsRotation(getSpatialRotation()); 150 } 151 setEnabled(boolean enabled)152 public void setEnabled(boolean enabled) { 153 this.enabled = enabled; 154 if (space != null) { 155 if (enabled && !added) { 156 if(spatial!=null){ 157 setPhysicsLocation(getSpatialTranslation()); 158 setPhysicsRotation(getSpatialRotation()); 159 } 160 space.addCollisionObject(this); 161 added = true; 162 } else if (!enabled && added) { 163 space.removeCollisionObject(this); 164 added = false; 165 } 166 } 167 } 168 isEnabled()169 public boolean isEnabled() { 170 return enabled; 171 } 172 update(float tpf)173 public void update(float tpf) { 174 if (enabled && spatial != null) { 175 if (getMotionState().applyTransform(spatial)) { 176 spatial.getWorldTransform(); 177 applyWheelTransforms(); 178 } 179 } else if (enabled) { 180 applyWheelTransforms(); 181 } 182 } 183 184 @Override getDebugShape()185 protected Spatial getDebugShape() { 186 return super.getDebugShape(); 187 } 188 render(RenderManager rm, ViewPort vp)189 public void render(RenderManager rm, ViewPort vp) { 190 if (enabled && space != null && space.getDebugManager() != null) { 191 if (debugShape == null) { 192 attachDebugShape(space.getDebugManager()); 193 } 194 Node debugNode = (Node) debugShape; 195 debugShape.setLocalTranslation(spatial.getWorldTranslation()); 196 debugShape.setLocalRotation(spatial.getWorldRotation()); 197 int i = 0; 198 for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { 199 VehicleWheel physicsVehicleWheel = it.next(); 200 Vector3f location = physicsVehicleWheel.getLocation().clone(); 201 Vector3f direction = physicsVehicleWheel.getDirection().clone(); 202 Vector3f axle = physicsVehicleWheel.getAxle().clone(); 203 float restLength = physicsVehicleWheel.getRestLength(); 204 float radius = physicsVehicleWheel.getRadius(); 205 206 Geometry locGeom = (Geometry) debugNode.getChild("WheelLocationDebugShape" + i); 207 Geometry dirGeom = (Geometry) debugNode.getChild("WheelDirectionDebugShape" + i); 208 Geometry axleGeom = (Geometry) debugNode.getChild("WheelAxleDebugShape" + i); 209 Geometry wheelGeom = (Geometry) debugNode.getChild("WheelRadiusDebugShape" + i); 210 211 Arrow locArrow = (Arrow) locGeom.getMesh(); 212 locArrow.setArrowExtent(location); 213 Arrow axleArrow = (Arrow) axleGeom.getMesh(); 214 axleArrow.setArrowExtent(axle.normalizeLocal().multLocal(0.3f)); 215 Arrow wheelArrow = (Arrow) wheelGeom.getMesh(); 216 wheelArrow.setArrowExtent(direction.normalizeLocal().multLocal(radius)); 217 Arrow dirArrow = (Arrow) dirGeom.getMesh(); 218 dirArrow.setArrowExtent(direction.normalizeLocal().multLocal(restLength)); 219 220 dirGeom.setLocalTranslation(location); 221 axleGeom.setLocalTranslation(location.addLocal(direction)); 222 wheelGeom.setLocalTranslation(location); 223 i++; 224 } 225 debugShape.updateLogicalState(0); 226 debugShape.updateGeometricState(); 227 rm.renderScene(debugShape, vp); 228 } 229 } 230 setPhysicsSpace(PhysicsSpace space)231 public void setPhysicsSpace(PhysicsSpace space) { 232 createVehicle(space); 233 if (space == null) { 234 if (this.space != null) { 235 this.space.removeCollisionObject(this); 236 added = false; 237 } 238 } else { 239 if(this.space==space) return; 240 space.addCollisionObject(this); 241 added = true; 242 } 243 this.space = space; 244 } 245 getPhysicsSpace()246 public PhysicsSpace getPhysicsSpace() { 247 return space; 248 } 249 250 @Override write(JmeExporter ex)251 public void write(JmeExporter ex) throws IOException { 252 super.write(ex); 253 OutputCapsule oc = ex.getCapsule(this); 254 oc.write(enabled, "enabled", true); 255 oc.write(motionState.isApplyPhysicsLocal(), "applyLocalPhysics", false); 256 oc.write(spatial, "spatial", null); 257 } 258 259 @Override read(JmeImporter im)260 public void read(JmeImporter im) throws IOException { 261 super.read(im); 262 InputCapsule ic = im.getCapsule(this); 263 enabled = ic.readBoolean("enabled", true); 264 spatial = (Spatial) ic.readSavable("spatial", null); 265 motionState.setApplyPhysicsLocal(ic.readBoolean("applyLocalPhysics", false)); 266 setUserObject(spatial); 267 } 268 } 269