| /* |
| * To change this template, choose Tools | Templates |
| * and open the template in the editor. |
| */ |
| package com.jme3.bullet.control; |
| |
| import com.jme3.bullet.PhysicsSpace; |
| import com.jme3.bullet.collision.shapes.CollisionShape; |
| import com.jme3.bullet.objects.PhysicsVehicle; |
| import com.jme3.bullet.objects.VehicleWheel; |
| import com.jme3.export.InputCapsule; |
| import com.jme3.export.JmeExporter; |
| import com.jme3.export.JmeImporter; |
| import com.jme3.export.OutputCapsule; |
| import com.jme3.math.Quaternion; |
| import com.jme3.math.Vector3f; |
| import com.jme3.renderer.RenderManager; |
| import com.jme3.renderer.ViewPort; |
| import com.jme3.scene.Geometry; |
| import com.jme3.scene.Node; |
| import com.jme3.scene.Spatial; |
| import com.jme3.scene.control.Control; |
| import com.jme3.scene.debug.Arrow; |
| import java.io.IOException; |
| import java.util.Iterator; |
| |
| /** |
| * |
| * @author normenhansen |
| */ |
| public class VehicleControl extends PhysicsVehicle implements PhysicsControl { |
| |
| protected Spatial spatial; |
| protected boolean enabled = true; |
| protected PhysicsSpace space = null; |
| protected boolean added = false; |
| |
| public VehicleControl() { |
| } |
| |
| /** |
| * Creates a new PhysicsNode with the supplied collision shape |
| * @param shape |
| */ |
| public VehicleControl(CollisionShape shape) { |
| super(shape); |
| } |
| |
| public VehicleControl(CollisionShape shape, float mass) { |
| super(shape, mass); |
| } |
| |
| public boolean isApplyPhysicsLocal() { |
| return motionState.isApplyPhysicsLocal(); |
| } |
| |
| /** |
| * When set to true, the physics coordinates will be applied to the local |
| * translation of the Spatial |
| * @param applyPhysicsLocal |
| */ |
| public void setApplyPhysicsLocal(boolean applyPhysicsLocal) { |
| motionState.setApplyPhysicsLocal(applyPhysicsLocal); |
| for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { |
| VehicleWheel vehicleWheel = it.next(); |
| vehicleWheel.setApplyLocal(applyPhysicsLocal); |
| } |
| } |
| |
| private Vector3f getSpatialTranslation(){ |
| if(motionState.isApplyPhysicsLocal()){ |
| return spatial.getLocalTranslation(); |
| } |
| return spatial.getWorldTranslation(); |
| } |
| |
| private Quaternion getSpatialRotation(){ |
| if(motionState.isApplyPhysicsLocal()){ |
| return spatial.getLocalRotation(); |
| } |
| return spatial.getWorldRotation(); |
| } |
| |
| public Control cloneForSpatial(Spatial spatial) { |
| VehicleControl control = new VehicleControl(collisionShape, mass); |
| control.setAngularFactor(getAngularFactor()); |
| control.setAngularSleepingThreshold(getAngularSleepingThreshold()); |
| control.setAngularVelocity(getAngularVelocity()); |
| control.setCcdMotionThreshold(getCcdMotionThreshold()); |
| control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); |
| control.setCollideWithGroups(getCollideWithGroups()); |
| control.setCollisionGroup(getCollisionGroup()); |
| control.setDamping(getLinearDamping(), getAngularDamping()); |
| control.setFriction(getFriction()); |
| control.setGravity(getGravity()); |
| control.setKinematic(isKinematic()); |
| control.setLinearSleepingThreshold(getLinearSleepingThreshold()); |
| control.setLinearVelocity(getLinearVelocity()); |
| control.setPhysicsLocation(getPhysicsLocation()); |
| control.setPhysicsRotation(getPhysicsRotationMatrix()); |
| control.setRestitution(getRestitution()); |
| |
| control.setFrictionSlip(getFrictionSlip()); |
| control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm()); |
| control.setSuspensionStiffness(getSuspensionStiffness()); |
| control.setSuspensionCompression(tuning.suspensionCompression); |
| control.setSuspensionDamping(tuning.suspensionDamping); |
| control.setMaxSuspensionForce(getMaxSuspensionForce()); |
| |
| for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { |
| VehicleWheel wheel = it.next(); |
| VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel()); |
| newWheel.setFrictionSlip(wheel.getFrictionSlip()); |
| newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm()); |
| newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness()); |
| newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression()); |
| newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation()); |
| newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce()); |
| |
| //TODO: bad way finding children! |
| if (spatial instanceof Node) { |
| Node node = (Node) spatial; |
| Spatial wheelSpat = node.getChild(wheel.getWheelSpatial().getName()); |
| if (wheelSpat != null) { |
| newWheel.setWheelSpatial(wheelSpat); |
| } |
| } |
| } |
| control.setApplyPhysicsLocal(isApplyPhysicsLocal()); |
| |
| control.setSpatial(spatial); |
| return control; |
| } |
| |
| public void setSpatial(Spatial spatial) { |
| if (getUserObject() == null || getUserObject() == this.spatial) { |
| setUserObject(spatial); |
| } |
| this.spatial = spatial; |
| if (spatial == null) { |
| if (getUserObject() == spatial) { |
| setUserObject(null); |
| } |
| this.spatial = null; |
| this.collisionShape = null; |
| return; |
| } |
| setPhysicsLocation(getSpatialTranslation()); |
| setPhysicsRotation(getSpatialRotation()); |
| } |
| |
| public void setEnabled(boolean enabled) { |
| this.enabled = enabled; |
| if (space != null) { |
| if (enabled && !added) { |
| if(spatial!=null){ |
| setPhysicsLocation(getSpatialTranslation()); |
| setPhysicsRotation(getSpatialRotation()); |
| } |
| space.addCollisionObject(this); |
| added = true; |
| } else if (!enabled && added) { |
| space.removeCollisionObject(this); |
| added = false; |
| } |
| } |
| } |
| |
| public boolean isEnabled() { |
| return enabled; |
| } |
| |
| public void update(float tpf) { |
| if (enabled && spatial != null) { |
| if (getMotionState().applyTransform(spatial)) { |
| spatial.getWorldTransform(); |
| applyWheelTransforms(); |
| } |
| } else if (enabled) { |
| applyWheelTransforms(); |
| } |
| } |
| |
| @Override |
| protected Spatial getDebugShape() { |
| return super.getDebugShape(); |
| } |
| |
| public void render(RenderManager rm, ViewPort vp) { |
| if (enabled && space != null && space.getDebugManager() != null) { |
| if (debugShape == null) { |
| attachDebugShape(space.getDebugManager()); |
| } |
| Node debugNode = (Node) debugShape; |
| debugShape.setLocalTranslation(spatial.getWorldTranslation()); |
| debugShape.setLocalRotation(spatial.getWorldRotation()); |
| int i = 0; |
| for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) { |
| VehicleWheel physicsVehicleWheel = it.next(); |
| Vector3f location = physicsVehicleWheel.getLocation().clone(); |
| Vector3f direction = physicsVehicleWheel.getDirection().clone(); |
| Vector3f axle = physicsVehicleWheel.getAxle().clone(); |
| float restLength = physicsVehicleWheel.getRestLength(); |
| float radius = physicsVehicleWheel.getRadius(); |
| |
| Geometry locGeom = (Geometry) debugNode.getChild("WheelLocationDebugShape" + i); |
| Geometry dirGeom = (Geometry) debugNode.getChild("WheelDirectionDebugShape" + i); |
| Geometry axleGeom = (Geometry) debugNode.getChild("WheelAxleDebugShape" + i); |
| Geometry wheelGeom = (Geometry) debugNode.getChild("WheelRadiusDebugShape" + i); |
| |
| Arrow locArrow = (Arrow) locGeom.getMesh(); |
| locArrow.setArrowExtent(location); |
| Arrow axleArrow = (Arrow) axleGeom.getMesh(); |
| axleArrow.setArrowExtent(axle.normalizeLocal().multLocal(0.3f)); |
| Arrow wheelArrow = (Arrow) wheelGeom.getMesh(); |
| wheelArrow.setArrowExtent(direction.normalizeLocal().multLocal(radius)); |
| Arrow dirArrow = (Arrow) dirGeom.getMesh(); |
| dirArrow.setArrowExtent(direction.normalizeLocal().multLocal(restLength)); |
| |
| dirGeom.setLocalTranslation(location); |
| axleGeom.setLocalTranslation(location.addLocal(direction)); |
| wheelGeom.setLocalTranslation(location); |
| i++; |
| } |
| debugShape.updateLogicalState(0); |
| debugShape.updateGeometricState(); |
| rm.renderScene(debugShape, vp); |
| } |
| } |
| |
| public void setPhysicsSpace(PhysicsSpace space) { |
| createVehicle(space); |
| if (space == null) { |
| if (this.space != null) { |
| this.space.removeCollisionObject(this); |
| added = false; |
| } |
| } else { |
| if(this.space==space) return; |
| space.addCollisionObject(this); |
| added = true; |
| } |
| this.space = space; |
| } |
| |
| public PhysicsSpace getPhysicsSpace() { |
| return space; |
| } |
| |
| @Override |
| public void write(JmeExporter ex) throws IOException { |
| super.write(ex); |
| OutputCapsule oc = ex.getCapsule(this); |
| oc.write(enabled, "enabled", true); |
| oc.write(motionState.isApplyPhysicsLocal(), "applyLocalPhysics", false); |
| oc.write(spatial, "spatial", null); |
| } |
| |
| @Override |
| public void read(JmeImporter im) throws IOException { |
| super.read(im); |
| InputCapsule ic = im.getCapsule(this); |
| enabled = ic.readBoolean("enabled", true); |
| spatial = (Spatial) ic.readSavable("spatial", null); |
| motionState.setApplyPhysicsLocal(ic.readBoolean("applyLocalPhysics", false)); |
| setUserObject(spatial); |
| } |
| } |