• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 jme3test.bullet;
33 
34 import com.jme3.app.SimpleApplication;
35 import com.jme3.bounding.BoundingBox;
36 import com.jme3.bullet.BulletAppState;
37 import com.jme3.bullet.PhysicsSpace;
38 import com.jme3.bullet.collision.shapes.CollisionShape;
39 import com.jme3.bullet.control.VehicleControl;
40 import com.jme3.bullet.objects.VehicleWheel;
41 import com.jme3.bullet.util.CollisionShapeFactory;
42 import com.jme3.input.KeyInput;
43 import com.jme3.input.controls.ActionListener;
44 import com.jme3.input.controls.KeyTrigger;
45 import com.jme3.light.DirectionalLight;
46 import com.jme3.math.FastMath;
47 import com.jme3.math.Matrix3f;
48 import com.jme3.math.Vector3f;
49 import com.jme3.renderer.queue.RenderQueue.ShadowMode;
50 import com.jme3.scene.Geometry;
51 import com.jme3.scene.Node;
52 import com.jme3.scene.Spatial;
53 import com.jme3.shadow.BasicShadowRenderer;
54 
55 public class TestFancyCar extends SimpleApplication implements ActionListener {
56 
57     private BulletAppState bulletAppState;
58     private VehicleControl player;
59     private VehicleWheel fr, fl, br, bl;
60     private Node node_fr, node_fl, node_br, node_bl;
61     private float wheelRadius;
62     private float steeringValue = 0;
63     private float accelerationValue = 0;
64     private Node carNode;
65 
main(String[] args)66     public static void main(String[] args) {
67         TestFancyCar app = new TestFancyCar();
68         app.start();
69     }
70 
setupKeys()71     private void setupKeys() {
72         inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H));
73         inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K));
74         inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U));
75         inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J));
76         inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE));
77         inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN));
78         inputManager.addListener(this, "Lefts");
79         inputManager.addListener(this, "Rights");
80         inputManager.addListener(this, "Ups");
81         inputManager.addListener(this, "Downs");
82         inputManager.addListener(this, "Space");
83         inputManager.addListener(this, "Reset");
84     }
85 
86     @Override
simpleInitApp()87     public void simpleInitApp() {
88         bulletAppState = new BulletAppState();
89         stateManager.attach(bulletAppState);
90 //        bulletAppState.getPhysicsSpace().enableDebug(assetManager);
91         if (settings.getRenderer().startsWith("LWJGL")) {
92             BasicShadowRenderer bsr = new BasicShadowRenderer(assetManager, 512);
93             bsr.setDirection(new Vector3f(-0.5f, -0.3f, -0.3f).normalizeLocal());
94             viewPort.addProcessor(bsr);
95         }
96         cam.setFrustumFar(150f);
97         flyCam.setMoveSpeed(10);
98 
99         setupKeys();
100         PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
101 //        setupFloor();
102         buildPlayer();
103 
104         DirectionalLight dl = new DirectionalLight();
105         dl.setDirection(new Vector3f(-0.5f, -1f, -0.3f).normalizeLocal());
106         rootNode.addLight(dl);
107 
108         dl = new DirectionalLight();
109         dl.setDirection(new Vector3f(0.5f, -0.1f, 0.3f).normalizeLocal());
110         rootNode.addLight(dl);
111     }
112 
getPhysicsSpace()113     private PhysicsSpace getPhysicsSpace() {
114         return bulletAppState.getPhysicsSpace();
115     }
116 
117 //    public void setupFloor() {
118 //        Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
119 //        mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
120 ////        mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
121 ////        mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
122 //
123 //        Box floor = new Box(Vector3f.ZERO, 140, 1f, 140);
124 //        floor.scaleTextureCoordinates(new Vector2f(112.0f, 112.0f));
125 //        Geometry floorGeom = new Geometry("Floor", floor);
126 //        floorGeom.setShadowMode(ShadowMode.Receive);
127 //        floorGeom.setMaterial(mat);
128 //
129 //        PhysicsNode tb = new PhysicsNode(floorGeom, new MeshCollisionShape(floorGeom.getMesh()), 0);
130 //        tb.setLocalTranslation(new Vector3f(0f, -6, 0f));
131 ////        tb.attachDebugShape(assetManager);
132 //        rootNode.attachChild(tb);
133 //        getPhysicsSpace().add(tb);
134 //    }
135 
findGeom(Spatial spatial, String name)136     private Geometry findGeom(Spatial spatial, String name) {
137         if (spatial instanceof Node) {
138             Node node = (Node) spatial;
139             for (int i = 0; i < node.getQuantity(); i++) {
140                 Spatial child = node.getChild(i);
141                 Geometry result = findGeom(child, name);
142                 if (result != null) {
143                     return result;
144                 }
145             }
146         } else if (spatial instanceof Geometry) {
147             if (spatial.getName().startsWith(name)) {
148                 return (Geometry) spatial;
149             }
150         }
151         return null;
152     }
153 
buildPlayer()154     private void buildPlayer() {
155         float stiffness = 120.0f;//200=f1 car
156         float compValue = 0.2f; //(lower than damp!)
157         float dampValue = 0.3f;
158         final float mass = 400;
159 
160         //Load model and get chassis Geometry
161         carNode = (Node)assetManager.loadModel("Models/Ferrari/Car.scene");
162         carNode.setShadowMode(ShadowMode.Cast);
163         Geometry chasis = findGeom(carNode, "Car");
164         BoundingBox box = (BoundingBox) chasis.getModelBound();
165 
166         //Create a hull collision shape for the chassis
167         CollisionShape carHull = CollisionShapeFactory.createDynamicMeshShape(chasis);
168 
169         //Create a vehicle control
170         player = new VehicleControl(carHull, mass);
171         carNode.addControl(player);
172 
173         //Setting default values for wheels
174         player.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
175         player.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
176         player.setSuspensionStiffness(stiffness);
177         player.setMaxSuspensionForce(10000);
178 
179         //Create four wheels and add them at their locations
180         //note that our fancy car actually goes backwards..
181         Vector3f wheelDirection = new Vector3f(0, -1, 0);
182         Vector3f wheelAxle = new Vector3f(-1, 0, 0);
183 
184         Geometry wheel_fr = findGeom(carNode, "WheelFrontRight");
185         wheel_fr.center();
186         box = (BoundingBox) wheel_fr.getModelBound();
187         wheelRadius = box.getYExtent();
188         float back_wheel_h = (wheelRadius * 1.7f) - 1f;
189         float front_wheel_h = (wheelRadius * 1.9f) - 1f;
190         player.addWheel(wheel_fr.getParent(), box.getCenter().add(0, -front_wheel_h, 0),
191                 wheelDirection, wheelAxle, 0.2f, wheelRadius, true);
192 
193         Geometry wheel_fl = findGeom(carNode, "WheelFrontLeft");
194         wheel_fl.center();
195         box = (BoundingBox) wheel_fl.getModelBound();
196         player.addWheel(wheel_fl.getParent(), box.getCenter().add(0, -front_wheel_h, 0),
197                 wheelDirection, wheelAxle, 0.2f, wheelRadius, true);
198 
199         Geometry wheel_br = findGeom(carNode, "WheelBackRight");
200         wheel_br.center();
201         box = (BoundingBox) wheel_br.getModelBound();
202         player.addWheel(wheel_br.getParent(), box.getCenter().add(0, -back_wheel_h, 0),
203                 wheelDirection, wheelAxle, 0.2f, wheelRadius, false);
204 
205         Geometry wheel_bl = findGeom(carNode, "WheelBackLeft");
206         wheel_bl.center();
207         box = (BoundingBox) wheel_bl.getModelBound();
208         player.addWheel(wheel_bl.getParent(), box.getCenter().add(0, -back_wheel_h, 0),
209                 wheelDirection, wheelAxle, 0.2f, wheelRadius, false);
210 
211         player.getWheel(2).setFrictionSlip(4);
212         player.getWheel(3).setFrictionSlip(4);
213 
214         rootNode.attachChild(carNode);
215         getPhysicsSpace().add(player);
216     }
217 
onAction(String binding, boolean value, float tpf)218     public void onAction(String binding, boolean value, float tpf) {
219         if (binding.equals("Lefts")) {
220             if (value) {
221                 steeringValue += .5f;
222             } else {
223                 steeringValue += -.5f;
224             }
225             player.steer(steeringValue);
226         } else if (binding.equals("Rights")) {
227             if (value) {
228                 steeringValue += -.5f;
229             } else {
230                 steeringValue += .5f;
231             }
232             player.steer(steeringValue);
233         } //note that our fancy car actually goes backwards..
234         else if (binding.equals("Ups")) {
235             if (value) {
236                 accelerationValue -= 800;
237             } else {
238                 accelerationValue += 800;
239             }
240             player.accelerate(accelerationValue);
241             player.setCollisionShape(CollisionShapeFactory.createDynamicMeshShape(findGeom(carNode, "Car")));
242         } else if (binding.equals("Downs")) {
243             if (value) {
244                 player.brake(40f);
245             } else {
246                 player.brake(0f);
247             }
248         } else if (binding.equals("Reset")) {
249             if (value) {
250                 System.out.println("Reset");
251                 player.setPhysicsLocation(Vector3f.ZERO);
252                 player.setPhysicsRotation(new Matrix3f());
253                 player.setLinearVelocity(Vector3f.ZERO);
254                 player.setAngularVelocity(Vector3f.ZERO);
255                 player.resetSuspension();
256             } else {
257             }
258         }
259     }
260 
261     @Override
simpleUpdate(float tpf)262     public void simpleUpdate(float tpf) {
263         cam.lookAt(carNode.getWorldTranslation(), Vector3f.UNIT_Y);
264     }
265 }
266