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 33 package jme3test.bullet; 34 35 import com.jme3.app.SimpleApplication; 36 import com.jme3.bullet.BulletAppState; 37 import com.jme3.bullet.PhysicsSpace; 38 import com.jme3.bullet.collision.shapes.BoxCollisionShape; 39 import com.jme3.bullet.collision.shapes.CompoundCollisionShape; 40 import com.jme3.bullet.control.VehicleControl; 41 import com.jme3.input.KeyInput; 42 import com.jme3.input.controls.ActionListener; 43 import com.jme3.input.controls.KeyTrigger; 44 import com.jme3.material.Material; 45 import com.jme3.math.ColorRGBA; 46 import com.jme3.math.FastMath; 47 import com.jme3.math.Matrix3f; 48 import com.jme3.math.Vector3f; 49 import com.jme3.scene.Geometry; 50 import com.jme3.scene.Node; 51 import com.jme3.scene.shape.Cylinder; 52 53 public class TestPhysicsCar extends SimpleApplication implements ActionListener { 54 55 private BulletAppState bulletAppState; 56 private VehicleControl vehicle; 57 private final float accelerationForce = 1000.0f; 58 private final float brakeForce = 100.0f; 59 private float steeringValue = 0; 60 private float accelerationValue = 0; 61 private Vector3f jumpForce = new Vector3f(0, 3000, 0); 62 63 public static void main(String[] args) { 64 TestPhysicsCar app = new TestPhysicsCar(); 65 app.start(); 66 } 67 68 @Override 69 public void simpleInitApp() { 70 bulletAppState = new BulletAppState(); 71 stateManager.attach(bulletAppState); 72 bulletAppState.getPhysicsSpace().enableDebug(assetManager); 73 PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); 74 setupKeys(); 75 buildPlayer(); 76 } 77 78 private PhysicsSpace getPhysicsSpace(){ 79 return bulletAppState.getPhysicsSpace(); 80 } 81 82 private void setupKeys() { 83 inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); 84 inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); 85 inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U)); 86 inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J)); 87 inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); 88 inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); 89 inputManager.addListener(this, "Lefts"); 90 inputManager.addListener(this, "Rights"); 91 inputManager.addListener(this, "Ups"); 92 inputManager.addListener(this, "Downs"); 93 inputManager.addListener(this, "Space"); 94 inputManager.addListener(this, "Reset"); 95 } 96 97 private void buildPlayer() { 98 Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); 99 mat.getAdditionalRenderState().setWireframe(true); 100 mat.setColor("Color", ColorRGBA.Red); 101 102 //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0 103 //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0 104 CompoundCollisionShape compoundShape = new CompoundCollisionShape(); 105 BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f)); 106 compoundShape.addChildShape(box, new Vector3f(0, 1, 0)); 107 108 //create vehicle node 109 Node vehicleNode=new Node("vehicleNode"); 110 vehicle = new VehicleControl(compoundShape, 400); 111 vehicleNode.addControl(vehicle); 112 113 //setting suspension values for wheels, this can be a bit tricky 114 //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en 115 float stiffness = 60.0f;//200=f1 car 116 float compValue = .3f; //(should be lower than damp) 117 float dampValue = .4f; 118 vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness)); 119 vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness)); 120 vehicle.setSuspensionStiffness(stiffness); 121 vehicle.setMaxSuspensionForce(10000.0f); 122 123 //Create four wheels and add them at their locations 124 Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0 125 Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0 126 float radius = 0.5f; 127 float restLength = 0.3f; 128 float yOff = 0.5f; 129 float xOff = 1f; 130 float zOff = 2f; 131 132 Cylinder wheelMesh = new Cylinder(16, 16, radius, radius * 0.6f, true); 133 134 Node node1 = new Node("wheel 1 node"); 135 Geometry wheels1 = new Geometry("wheel 1", wheelMesh); 136 node1.attachChild(wheels1); 137 wheels1.rotate(0, FastMath.HALF_PI, 0); 138 wheels1.setMaterial(mat); 139 vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff), 140 wheelDirection, wheelAxle, restLength, radius, true); 141 142 Node node2 = new Node("wheel 2 node"); 143 Geometry wheels2 = new Geometry("wheel 2", wheelMesh); 144 node2.attachChild(wheels2); 145 wheels2.rotate(0, FastMath.HALF_PI, 0); 146 wheels2.setMaterial(mat); 147 vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff), 148 wheelDirection, wheelAxle, restLength, radius, true); 149 150 Node node3 = new Node("wheel 3 node"); 151 Geometry wheels3 = new Geometry("wheel 3", wheelMesh); 152 node3.attachChild(wheels3); 153 wheels3.rotate(0, FastMath.HALF_PI, 0); 154 wheels3.setMaterial(mat); 155 vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff), 156 wheelDirection, wheelAxle, restLength, radius, false); 157 158 Node node4 = new Node("wheel 4 node"); 159 Geometry wheels4 = new Geometry("wheel 4", wheelMesh); 160 node4.attachChild(wheels4); 161 wheels4.rotate(0, FastMath.HALF_PI, 0); 162 wheels4.setMaterial(mat); 163 vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff), 164 wheelDirection, wheelAxle, restLength, radius, false); 165 166 vehicleNode.attachChild(node1); 167 vehicleNode.attachChild(node2); 168 vehicleNode.attachChild(node3); 169 vehicleNode.attachChild(node4); 170 rootNode.attachChild(vehicleNode); 171 172 getPhysicsSpace().add(vehicle); 173 } 174 175 @Override 176 public void simpleUpdate(float tpf) { 177 cam.lookAt(vehicle.getPhysicsLocation(), Vector3f.UNIT_Y); 178 } 179 180 public void onAction(String binding, boolean value, float tpf) { 181 if (binding.equals("Lefts")) { 182 if (value) { 183 steeringValue += .5f; 184 } else { 185 steeringValue += -.5f; 186 } 187 vehicle.steer(steeringValue); 188 } else if (binding.equals("Rights")) { 189 if (value) { 190 steeringValue += -.5f; 191 } else { 192 steeringValue += .5f; 193 } 194 vehicle.steer(steeringValue); 195 } else if (binding.equals("Ups")) { 196 if (value) { 197 accelerationValue += accelerationForce; 198 } else { 199 accelerationValue -= accelerationForce; 200 } 201 vehicle.accelerate(accelerationValue); 202 } else if (binding.equals("Downs")) { 203 if (value) { 204 vehicle.brake(brakeForce); 205 } else { 206 vehicle.brake(0f); 207 } 208 } else if (binding.equals("Space")) { 209 if (value) { 210 vehicle.applyImpulse(jumpForce, Vector3f.ZERO); 211 } 212 } else if (binding.equals("Reset")) { 213 if (value) { 214 System.out.println("Reset"); 215 vehicle.setPhysicsLocation(Vector3f.ZERO); 216 vehicle.setPhysicsRotation(new Matrix3f()); 217 vehicle.setLinearVelocity(Vector3f.ZERO); 218 vehicle.setAngularVelocity(Vector3f.ZERO); 219 vehicle.resetSuspension(); 220 } else { 221 } 222 } 223 } 224 } 225