Home | History | Annotate | Download | only in bullet
      1 /*
      2  * Copyright (c) 2009-2012 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.bullet.PhysicsSpace;
     35 import com.jme3.bullet.PhysicsTickListener;
     36 import com.jme3.bullet.collision.shapes.CollisionShape;
     37 import com.jme3.bullet.control.PhysicsControl;
     38 import com.jme3.bullet.objects.PhysicsVehicle;
     39 import com.jme3.export.InputCapsule;
     40 import com.jme3.export.JmeExporter;
     41 import com.jme3.export.JmeImporter;
     42 import com.jme3.export.OutputCapsule;
     43 import com.jme3.math.FastMath;
     44 import com.jme3.math.Vector3f;
     45 import com.jme3.renderer.RenderManager;
     46 import com.jme3.renderer.ViewPort;
     47 import com.jme3.scene.Spatial;
     48 import com.jme3.scene.control.Control;
     49 import java.io.IOException;
     50 
     51 /**
     52  * PhysicsHoverControl uses a RayCast Vehicle with "slippery wheels" to simulate a hovering tank
     53  * @author normenhansen
     54  */
     55 public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener {
     56 
     57     protected Spatial spatial;
     58     protected boolean enabled = true;
     59     protected PhysicsSpace space = null;
     60     protected float steeringValue = 0;
     61     protected float accelerationValue = 0;
     62     protected int xw = 3;
     63     protected int zw = 5;
     64     protected int yw = 2;
     65     protected Vector3f HOVER_HEIGHT_LF_START = new Vector3f(xw, 1, zw);
     66     protected Vector3f HOVER_HEIGHT_RF_START = new Vector3f(-xw, 1, zw);
     67     protected Vector3f HOVER_HEIGHT_LR_START = new Vector3f(xw, 1, -zw);
     68     protected Vector3f HOVER_HEIGHT_RR_START = new Vector3f(-xw, 1, -zw);
     69     protected Vector3f HOVER_HEIGHT_LF = new Vector3f(xw, -yw, zw);
     70     protected Vector3f HOVER_HEIGHT_RF = new Vector3f(-xw, -yw, zw);
     71     protected Vector3f HOVER_HEIGHT_LR = new Vector3f(xw, -yw, -zw);
     72     protected Vector3f HOVER_HEIGHT_RR = new Vector3f(-xw, -yw, -zw);
     73     protected Vector3f tempVect1 = new Vector3f(0, 0, 0);
     74     protected Vector3f tempVect2 = new Vector3f(0, 0, 0);
     75     protected Vector3f tempVect3 = new Vector3f(0, 0, 0);
     76 //    protected float rotationCounterForce = 10000f;
     77 //    protected float speedCounterMult = 2000f;
     78 //    protected float multiplier = 1000f;
     79 
     80     public PhysicsHoverControl() {
     81     }
     82 
     83     /**
     84      * Creates a new PhysicsNode with the supplied collision shape
     85      * @param shape
     86      */
     87     public PhysicsHoverControl(CollisionShape shape) {
     88         super(shape);
     89         createWheels();
     90     }
     91 
     92     public PhysicsHoverControl(CollisionShape shape, float mass) {
     93         super(shape, mass);
     94         createWheels();
     95     }
     96 
     97     public Control cloneForSpatial(Spatial spatial) {
     98         throw new UnsupportedOperationException("Not supported yet.");
     99     }
    100 
    101     public void setSpatial(Spatial spatial) {
    102         this.spatial = spatial;
    103         setUserObject(spatial);
    104         if (spatial == null) {
    105             return;
    106         }
    107         setPhysicsLocation(spatial.getWorldTranslation());
    108         setPhysicsRotation(spatial.getWorldRotation().toRotationMatrix());
    109     }
    110 
    111     public void setEnabled(boolean enabled) {
    112         this.enabled = enabled;
    113     }
    114 
    115     public boolean isEnabled() {
    116         return enabled;
    117     }
    118 
    119     private void createWheels() {
    120         addWheel(HOVER_HEIGHT_LF_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false);
    121         addWheel(HOVER_HEIGHT_RF_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false);
    122         addWheel(HOVER_HEIGHT_LR_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false);
    123         addWheel(HOVER_HEIGHT_RR_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false);
    124         for (int i = 0; i < 4; i++) {
    125             getWheel(i).setFrictionSlip(0.001f);
    126         }
    127     }
    128 
    129     public void prePhysicsTick(PhysicsSpace space, float f) {
    130         Vector3f angVel = getAngularVelocity();
    131         float rotationVelocity = angVel.getY();
    132         Vector3f dir = getForwardVector(tempVect2).multLocal(1, 0, 1).normalizeLocal();
    133         getLinearVelocity(tempVect3);
    134         Vector3f linearVelocity = tempVect3.multLocal(1, 0, 1);
    135 
    136         if (steeringValue != 0) {
    137             if (rotationVelocity < 1 && rotationVelocity > -1) {
    138                 applyTorque(tempVect1.set(0, steeringValue, 0));
    139             }
    140         } else {
    141             // counter the steering value!
    142             if (rotationVelocity > 0.2f) {
    143                 applyTorque(tempVect1.set(0, -mass * 20, 0));
    144             } else if (rotationVelocity < -0.2f) {
    145                 applyTorque(tempVect1.set(0, mass * 20, 0));
    146             }
    147         }
    148         if (accelerationValue > 0) {
    149             // counter force that will adjust velocity
    150             // if we are not going where we want to go.
    151             // this will prevent "drifting" and thus improve control
    152             // of the vehicle
    153             float d = dir.dot(linearVelocity.normalize());
    154             Vector3f counter = dir.project(linearVelocity).normalizeLocal().negateLocal().multLocal(1 - d);
    155             applyForce(counter.multLocal(mass * 10), Vector3f.ZERO);
    156 
    157             if (linearVelocity.length() < 30) {
    158                 applyForce(dir.multLocal(accelerationValue), Vector3f.ZERO);
    159             }
    160         } else {
    161             // counter the acceleration value
    162             if (linearVelocity.length() > FastMath.ZERO_TOLERANCE) {
    163                 linearVelocity.normalizeLocal().negateLocal();
    164                 applyForce(linearVelocity.mult(mass * 10), Vector3f.ZERO);
    165             }
    166         }
    167     }
    168 
    169     public void physicsTick(PhysicsSpace space, float f) {
    170     }
    171 
    172     public void update(float tpf) {
    173         if (enabled && spatial != null) {
    174             getMotionState().applyTransform(spatial);
    175         }
    176     }
    177 
    178     public void render(RenderManager rm, ViewPort vp) {
    179         if (enabled && space != null && space.getDebugManager() != null) {
    180             if (debugShape == null) {
    181                 attachDebugShape(space.getDebugManager());
    182             }
    183             debugShape.setLocalTranslation(motionState.getWorldLocation());
    184             debugShape.setLocalRotation(motionState.getWorldRotation());
    185             debugShape.updateLogicalState(0);
    186             debugShape.updateGeometricState();
    187             rm.renderScene(debugShape, vp);
    188         }
    189     }
    190 
    191     public void setPhysicsSpace(PhysicsSpace space) {
    192         if (space == null) {
    193             if (this.space != null) {
    194                 this.space.removeCollisionObject(this);
    195                 this.space.removeTickListener(this);
    196             }
    197             this.space = space;
    198         } else {
    199             space.addCollisionObject(this);
    200             space.addTickListener(this);
    201         }
    202         this.space = space;
    203     }
    204 
    205     public PhysicsSpace getPhysicsSpace() {
    206         return space;
    207     }
    208 
    209     @Override
    210     public void write(JmeExporter ex) throws IOException {
    211         super.write(ex);
    212         OutputCapsule oc = ex.getCapsule(this);
    213         oc.write(enabled, "enabled", true);
    214         oc.write(spatial, "spatial", null);
    215     }
    216 
    217     @Override
    218     public void read(JmeImporter im) throws IOException {
    219         super.read(im);
    220         InputCapsule ic = im.getCapsule(this);
    221         enabled = ic.readBoolean("enabled", true);
    222         spatial = (Spatial) ic.readSavable("spatial", null);
    223     }
    224 
    225     /**
    226      * @param steeringValue the steeringValue to set
    227      */
    228     @Override
    229     public void steer(float steeringValue) {
    230         this.steeringValue = steeringValue * getMass();
    231     }
    232 
    233     /**
    234      * @param accelerationValue the accelerationValue to set
    235      */
    236     @Override
    237     public void accelerate(float accelerationValue) {
    238         this.accelerationValue = accelerationValue * getMass();
    239     }
    240 }
    241