• 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 com.jme3.bullet.objects;
33 
34 import com.jme3.bullet.collision.PhysicsCollisionObject;
35 import com.jme3.export.*;
36 import com.jme3.math.Matrix3f;
37 import com.jme3.math.Quaternion;
38 import com.jme3.math.Vector3f;
39 import com.jme3.scene.Spatial;
40 import java.io.IOException;
41 
42 /**
43  * Stores info about one wheel of a PhysicsVehicle
44  * @author normenhansen
45  */
46 public class VehicleWheel implements Savable {
47 
48     protected long wheelId = 0;
49     protected int wheelIndex = 0;
50     protected boolean frontWheel;
51     protected Vector3f location = new Vector3f();
52     protected Vector3f direction = new Vector3f();
53     protected Vector3f axle = new Vector3f();
54     protected float suspensionStiffness = 20.0f;
55     protected float wheelsDampingRelaxation = 2.3f;
56     protected float wheelsDampingCompression = 4.4f;
57     protected float frictionSlip = 10.5f;
58     protected float rollInfluence = 1.0f;
59     protected float maxSuspensionTravelCm = 500f;
60     protected float maxSuspensionForce = 6000f;
61     protected float radius = 0.5f;
62     protected float restLength = 1f;
63     protected Vector3f wheelWorldLocation = new Vector3f();
64     protected Quaternion wheelWorldRotation = new Quaternion();
65     protected Spatial wheelSpatial;
66     protected Matrix3f tmp_Matrix = new com.jme3.math.Matrix3f();
67     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
68     private boolean applyLocal = false;
69 
VehicleWheel()70     public VehicleWheel() {
71     }
72 
VehicleWheel(Spatial spat, Vector3f location, Vector3f direction, Vector3f axle, float restLength, float radius, boolean frontWheel)73     public VehicleWheel(Spatial spat, Vector3f location, Vector3f direction, Vector3f axle,
74             float restLength, float radius, boolean frontWheel) {
75         this(location, direction, axle, restLength, radius, frontWheel);
76         wheelSpatial = spat;
77     }
78 
VehicleWheel(Vector3f location, Vector3f direction, Vector3f axle, float restLength, float radius, boolean frontWheel)79     public VehicleWheel(Vector3f location, Vector3f direction, Vector3f axle,
80             float restLength, float radius, boolean frontWheel) {
81         this.location.set(location);
82         this.direction.set(direction);
83         this.axle.set(axle);
84         this.frontWheel = frontWheel;
85         this.restLength = restLength;
86         this.radius = radius;
87     }
88 
updatePhysicsState()89     public synchronized void updatePhysicsState() {
90         getWheelLocation(wheelId, wheelIndex, wheelWorldLocation);
91         getWheelRotation(wheelId, wheelIndex, tmp_Matrix);
92         wheelWorldRotation.fromRotationMatrix(tmp_Matrix);
93     }
94 
getWheelLocation(long vehicleId, int wheelId, Vector3f location)95     private native void getWheelLocation(long vehicleId, int wheelId, Vector3f location);
96 
getWheelRotation(long vehicleId, int wheelId, Matrix3f location)97     private native void getWheelRotation(long vehicleId, int wheelId, Matrix3f location);
98 
applyWheelTransform()99     public synchronized void applyWheelTransform() {
100         if (wheelSpatial == null) {
101             return;
102         }
103         Quaternion localRotationQuat = wheelSpatial.getLocalRotation();
104         Vector3f localLocation = wheelSpatial.getLocalTranslation();
105         if (!applyLocal && wheelSpatial.getParent() != null) {
106             localLocation.set(wheelWorldLocation).subtractLocal(wheelSpatial.getParent().getWorldTranslation());
107             localLocation.divideLocal(wheelSpatial.getParent().getWorldScale());
108             tmp_inverseWorldRotation.set(wheelSpatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation);
109 
110             localRotationQuat.set(wheelWorldRotation);
111             tmp_inverseWorldRotation.set(wheelSpatial.getParent().getWorldRotation()).inverseLocal().mult(localRotationQuat, localRotationQuat);
112 
113             wheelSpatial.setLocalTranslation(localLocation);
114             wheelSpatial.setLocalRotation(localRotationQuat);
115         } else {
116             wheelSpatial.setLocalTranslation(wheelWorldLocation);
117             wheelSpatial.setLocalRotation(wheelWorldRotation);
118         }
119     }
120 
getWheelId()121     public long getWheelId() {
122         return wheelId;
123     }
124 
setVehicleId(long vehicleId, int wheelIndex)125     public void setVehicleId(long vehicleId, int wheelIndex) {
126         this.wheelId = vehicleId;
127         this.wheelIndex = wheelIndex;
128         applyInfo();
129     }
130 
isFrontWheel()131     public boolean isFrontWheel() {
132         return frontWheel;
133     }
134 
setFrontWheel(boolean frontWheel)135     public void setFrontWheel(boolean frontWheel) {
136         this.frontWheel = frontWheel;
137         applyInfo();
138     }
139 
getLocation()140     public Vector3f getLocation() {
141         return location;
142     }
143 
getDirection()144     public Vector3f getDirection() {
145         return direction;
146     }
147 
getAxle()148     public Vector3f getAxle() {
149         return axle;
150     }
151 
getSuspensionStiffness()152     public float getSuspensionStiffness() {
153         return suspensionStiffness;
154     }
155 
156     /**
157      * the stiffness constant for the suspension.  10.0 - Offroad buggy, 50.0 - Sports car, 200.0 - F1 Car
158      * @param suspensionStiffness
159      */
setSuspensionStiffness(float suspensionStiffness)160     public void setSuspensionStiffness(float suspensionStiffness) {
161         this.suspensionStiffness = suspensionStiffness;
162         applyInfo();
163     }
164 
getWheelsDampingRelaxation()165     public float getWheelsDampingRelaxation() {
166         return wheelsDampingRelaxation;
167     }
168 
169     /**
170      * the damping coefficient for when the suspension is expanding.
171      * See the comments for setWheelsDampingCompression for how to set k.
172      * @param wheelsDampingRelaxation
173      */
setWheelsDampingRelaxation(float wheelsDampingRelaxation)174     public void setWheelsDampingRelaxation(float wheelsDampingRelaxation) {
175         this.wheelsDampingRelaxation = wheelsDampingRelaxation;
176         applyInfo();
177     }
178 
getWheelsDampingCompression()179     public float getWheelsDampingCompression() {
180         return wheelsDampingCompression;
181     }
182 
183     /**
184      * the damping coefficient for when the suspension is compressed.
185      * Set to k * 2.0 * FastMath.sqrt(m_suspensionStiffness) so k is proportional to critical damping.<br>
186      * k = 0.0 undamped & bouncy, k = 1.0 critical damping<br>
187      * 0.1 to 0.3 are good values
188      * @param wheelsDampingCompression
189      */
setWheelsDampingCompression(float wheelsDampingCompression)190     public void setWheelsDampingCompression(float wheelsDampingCompression) {
191         this.wheelsDampingCompression = wheelsDampingCompression;
192         applyInfo();
193     }
194 
getFrictionSlip()195     public float getFrictionSlip() {
196         return frictionSlip;
197     }
198 
199     /**
200      * the coefficient of friction between the tyre and the ground.
201      * Should be about 0.8 for realistic cars, but can increased for better handling.
202      * Set large (10000.0) for kart racers
203      * @param frictionSlip
204      */
setFrictionSlip(float frictionSlip)205     public void setFrictionSlip(float frictionSlip) {
206         this.frictionSlip = frictionSlip;
207         applyInfo();
208     }
209 
getRollInfluence()210     public float getRollInfluence() {
211         return rollInfluence;
212     }
213 
214     /**
215      * reduces the rolling torque applied from the wheels that cause the vehicle to roll over.
216      * This is a bit of a hack, but it's quite effective. 0.0 = no roll, 1.0 = physical behaviour.
217      * If m_frictionSlip is too high, you'll need to reduce this to stop the vehicle rolling over.
218      * You should also try lowering the vehicle's centre of mass
219      * @param rollInfluence the rollInfluence to set
220      */
setRollInfluence(float rollInfluence)221     public void setRollInfluence(float rollInfluence) {
222         this.rollInfluence = rollInfluence;
223         applyInfo();
224     }
225 
getMaxSuspensionTravelCm()226     public float getMaxSuspensionTravelCm() {
227         return maxSuspensionTravelCm;
228     }
229 
230     /**
231      * the maximum distance the suspension can be compressed (centimetres)
232      * @param maxSuspensionTravelCm
233      */
setMaxSuspensionTravelCm(float maxSuspensionTravelCm)234     public void setMaxSuspensionTravelCm(float maxSuspensionTravelCm) {
235         this.maxSuspensionTravelCm = maxSuspensionTravelCm;
236         applyInfo();
237     }
238 
getMaxSuspensionForce()239     public float getMaxSuspensionForce() {
240         return maxSuspensionForce;
241     }
242 
243     /**
244      * The maximum suspension force, raise this above the default 6000 if your suspension cannot
245      * handle the weight of your vehcile.
246      * @param maxSuspensionTravelCm
247      */
setMaxSuspensionForce(float maxSuspensionForce)248     public void setMaxSuspensionForce(float maxSuspensionForce) {
249         this.maxSuspensionForce = maxSuspensionForce;
250         applyInfo();
251     }
252 
applyInfo()253     private void applyInfo() {
254         if (wheelId == 0) {
255             return;
256         }
257         applyInfo(wheelId, wheelIndex, suspensionStiffness, wheelsDampingRelaxation, wheelsDampingCompression, frictionSlip, rollInfluence, maxSuspensionTravelCm, maxSuspensionForce, radius, frontWheel, restLength);
258     }
259 
applyInfo(long wheelId, int wheelIndex, float suspensionStiffness, float wheelsDampingRelaxation, float wheelsDampingCompression, float frictionSlip, float rollInfluence, float maxSuspensionTravelCm, float maxSuspensionForce, float wheelsRadius, boolean frontWheel, float suspensionRestLength)260     private native void applyInfo(long wheelId, int wheelIndex,
261             float suspensionStiffness,
262             float wheelsDampingRelaxation,
263             float wheelsDampingCompression,
264             float frictionSlip,
265             float rollInfluence,
266             float maxSuspensionTravelCm,
267             float maxSuspensionForce,
268             float wheelsRadius,
269             boolean frontWheel,
270             float suspensionRestLength);
271 
getRadius()272     public float getRadius() {
273         return radius;
274     }
275 
setRadius(float radius)276     public void setRadius(float radius) {
277         this.radius = radius;
278         applyInfo();
279     }
280 
getRestLength()281     public float getRestLength() {
282         return restLength;
283     }
284 
setRestLength(float restLength)285     public void setRestLength(float restLength) {
286         this.restLength = restLength;
287         applyInfo();
288     }
289 
290     /**
291      * returns the object this wheel is in contact with or null if no contact
292      * @return the PhysicsCollisionObject (PhysicsRigidBody, PhysicsGhostObject)
293      */
getGroundObject()294     public PhysicsCollisionObject getGroundObject() {
295 //        if (wheelInfo.raycastInfo.groundObject == null) {
296 //            return null;
297 //        } else if (wheelInfo.raycastInfo.groundObject instanceof RigidBody) {
298 //            System.out.println("RigidBody");
299 //            return (PhysicsRigidBody) ((RigidBody) wheelInfo.raycastInfo.groundObject).getUserPointer();
300 //        } else {
301         return null;
302 //        }
303     }
304 
305     /**
306      * returns the location where the wheel collides with the ground (world space)
307      */
getCollisionLocation(Vector3f vec)308     public Vector3f getCollisionLocation(Vector3f vec) {
309         getCollisionLocation(wheelId, wheelIndex, vec);
310         return vec;
311     }
312 
getCollisionLocation(long wheelId, int wheelIndex, Vector3f vec)313     private native void getCollisionLocation(long wheelId, int wheelIndex, Vector3f vec);
314 
315     /**
316      * returns the location where the wheel collides with the ground (world space)
317      */
getCollisionLocation()318     public Vector3f getCollisionLocation() {
319         Vector3f vec = new Vector3f();
320         getCollisionLocation(wheelId, wheelIndex, vec);
321         return vec;
322     }
323 
324     /**
325      * returns the normal where the wheel collides with the ground (world space)
326      */
getCollisionNormal(Vector3f vec)327     public Vector3f getCollisionNormal(Vector3f vec) {
328         getCollisionNormal(wheelId, wheelIndex, vec);
329         return vec;
330     }
331 
getCollisionNormal(long wheelId, int wheelIndex, Vector3f vec)332     private native void getCollisionNormal(long wheelId, int wheelIndex, Vector3f vec);
333 
334     /**
335      * returns the normal where the wheel collides with the ground (world space)
336      */
getCollisionNormal()337     public Vector3f getCollisionNormal() {
338         Vector3f vec = new Vector3f();
339         getCollisionNormal(wheelId, wheelIndex, vec);
340         return vec;
341     }
342 
343     /**
344      * returns how much the wheel skids on the ground (for skid sounds/smoke etc.)<br>
345      * 0.0 = wheels are sliding, 1.0 = wheels have traction.
346      */
getSkidInfo()347     public float getSkidInfo() {
348         return getSkidInfo(wheelId, wheelIndex);
349     }
350 
getSkidInfo(long wheelId, int wheelIndex)351     public native float getSkidInfo(long wheelId, int wheelIndex);
352 
353     /**
354      * returns how many degrees the wheel has turned since the last physics
355      * step.
356      */
getDeltaRotation()357     public float getDeltaRotation() {
358         return getDeltaRotation(wheelId, wheelIndex);
359     }
360 
getDeltaRotation(long wheelId, int wheelIndex)361     public native float getDeltaRotation(long wheelId, int wheelIndex);
362 
363     @Override
read(JmeImporter im)364     public void read(JmeImporter im) throws IOException {
365         InputCapsule capsule = im.getCapsule(this);
366         wheelSpatial = (Spatial) capsule.readSavable("wheelSpatial", null);
367         frontWheel = capsule.readBoolean("frontWheel", false);
368         location = (Vector3f) capsule.readSavable("wheelLocation", new Vector3f());
369         direction = (Vector3f) capsule.readSavable("wheelDirection", new Vector3f());
370         axle = (Vector3f) capsule.readSavable("wheelAxle", new Vector3f());
371         suspensionStiffness = capsule.readFloat("suspensionStiffness", 20.0f);
372         wheelsDampingRelaxation = capsule.readFloat("wheelsDampingRelaxation", 2.3f);
373         wheelsDampingCompression = capsule.readFloat("wheelsDampingCompression", 4.4f);
374         frictionSlip = capsule.readFloat("frictionSlip", 10.5f);
375         rollInfluence = capsule.readFloat("rollInfluence", 1.0f);
376         maxSuspensionTravelCm = capsule.readFloat("maxSuspensionTravelCm", 500f);
377         maxSuspensionForce = capsule.readFloat("maxSuspensionForce", 6000f);
378         radius = capsule.readFloat("wheelRadius", 0.5f);
379         restLength = capsule.readFloat("restLength", 1f);
380     }
381 
382     @Override
write(JmeExporter ex)383     public void write(JmeExporter ex) throws IOException {
384         OutputCapsule capsule = ex.getCapsule(this);
385         capsule.write(wheelSpatial, "wheelSpatial", null);
386         capsule.write(frontWheel, "frontWheel", false);
387         capsule.write(location, "wheelLocation", new Vector3f());
388         capsule.write(direction, "wheelDirection", new Vector3f());
389         capsule.write(axle, "wheelAxle", new Vector3f());
390         capsule.write(suspensionStiffness, "suspensionStiffness", 20.0f);
391         capsule.write(wheelsDampingRelaxation, "wheelsDampingRelaxation", 2.3f);
392         capsule.write(wheelsDampingCompression, "wheelsDampingCompression", 4.4f);
393         capsule.write(frictionSlip, "frictionSlip", 10.5f);
394         capsule.write(rollInfluence, "rollInfluence", 1.0f);
395         capsule.write(maxSuspensionTravelCm, "maxSuspensionTravelCm", 500f);
396         capsule.write(maxSuspensionForce, "maxSuspensionForce", 6000f);
397         capsule.write(radius, "wheelRadius", 0.5f);
398         capsule.write(restLength, "restLength", 1f);
399     }
400 
401     /**
402      * @return the wheelSpatial
403      */
getWheelSpatial()404     public Spatial getWheelSpatial() {
405         return wheelSpatial;
406     }
407 
408     /**
409      * @param wheelSpatial the wheelSpatial to set
410      */
setWheelSpatial(Spatial wheelSpatial)411     public void setWheelSpatial(Spatial wheelSpatial) {
412         this.wheelSpatial = wheelSpatial;
413     }
414 
isApplyLocal()415     public boolean isApplyLocal() {
416         return applyLocal;
417     }
418 
setApplyLocal(boolean applyLocal)419     public void setApplyLocal(boolean applyLocal) {
420         this.applyLocal = applyLocal;
421     }
422 
423 }
424