OSDN Git Service

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