1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine All rights reserved. <p/> 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are met: 5 * 6 * * Redistributions of source code must retain the above copyright notice, 7 * this list of conditions and the following disclaimer. <p/> * Redistributions 8 * in binary form must reproduce the above copyright notice, this list of 9 * conditions and the following disclaimer in the documentation and/or other 10 * materials provided with the distribution. <p/> * Neither the name of 11 * 'jMonkeyEngine' nor the names of its contributors may be used to endorse or 12 * promote products derived from this software without specific prior written 13 * permission. <p/> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 14 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 15 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 16 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 package jme3test.bullet; 26 27 import com.jme3.app.SimpleApplication; 28 import com.jme3.bullet.BulletAppState; 29 import com.jme3.bullet.PhysicsSpace; 30 import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; 31 import com.jme3.bullet.control.CharacterControl; 32 import com.jme3.input.KeyInput; 33 import com.jme3.input.MouseInput; 34 import com.jme3.input.controls.ActionListener; 35 import com.jme3.input.controls.KeyTrigger; 36 import com.jme3.input.controls.MouseButtonTrigger; 37 import com.jme3.math.Vector3f; 38 import com.jme3.renderer.RenderManager; 39 import com.jme3.scene.CameraNode; 40 import com.jme3.scene.Node; 41 import com.jme3.scene.Spatial; 42 import com.jme3.scene.control.CameraControl.ControlDirection; 43 44 /** 45 * A walking physical character followed by a 3rd person camera. (No animation.) 46 * @author normenhansen, zathras 47 */ 48 public class TestPhysicsCharacter extends SimpleApplication implements ActionListener { 49 50 private BulletAppState bulletAppState; 51 private CharacterControl physicsCharacter; 52 private Node characterNode; 53 private CameraNode camNode; 54 boolean rotate = false; 55 private Vector3f walkDirection = new Vector3f(0,0,0); 56 private Vector3f viewDirection = new Vector3f(0,0,0); 57 boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, 58 leftRotate = false, rightRotate = false; 59 main(String[] args)60 public static void main(String[] args) { 61 TestPhysicsCharacter app = new TestPhysicsCharacter(); 62 app.start(); 63 } 64 setupKeys()65 private void setupKeys() { 66 inputManager.addMapping("Strafe Left", 67 new KeyTrigger(KeyInput.KEY_Q), 68 new KeyTrigger(KeyInput.KEY_Z)); 69 inputManager.addMapping("Strafe Right", 70 new KeyTrigger(KeyInput.KEY_E), 71 new KeyTrigger(KeyInput.KEY_X)); 72 inputManager.addMapping("Rotate Left", 73 new KeyTrigger(KeyInput.KEY_A), 74 new KeyTrigger(KeyInput.KEY_LEFT)); 75 inputManager.addMapping("Rotate Right", 76 new KeyTrigger(KeyInput.KEY_D), 77 new KeyTrigger(KeyInput.KEY_RIGHT)); 78 inputManager.addMapping("Walk Forward", 79 new KeyTrigger(KeyInput.KEY_W), 80 new KeyTrigger(KeyInput.KEY_UP)); 81 inputManager.addMapping("Walk Backward", 82 new KeyTrigger(KeyInput.KEY_S), 83 new KeyTrigger(KeyInput.KEY_DOWN)); 84 inputManager.addMapping("Jump", 85 new KeyTrigger(KeyInput.KEY_SPACE), 86 new KeyTrigger(KeyInput.KEY_RETURN)); 87 inputManager.addMapping("Shoot", 88 new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); 89 inputManager.addListener(this, "Strafe Left", "Strafe Right"); 90 inputManager.addListener(this, "Rotate Left", "Rotate Right"); 91 inputManager.addListener(this, "Walk Forward", "Walk Backward"); 92 inputManager.addListener(this, "Jump", "Shoot"); 93 } 94 @Override simpleInitApp()95 public void simpleInitApp() { 96 // activate physics 97 bulletAppState = new BulletAppState(); 98 stateManager.attach(bulletAppState); 99 100 // init a physical test scene 101 PhysicsTestHelper.createPhysicsTestWorldSoccer(rootNode, assetManager, bulletAppState.getPhysicsSpace()); 102 setupKeys(); 103 104 // Add a physics character to the world 105 physicsCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f, 1.8f), .1f); 106 physicsCharacter.setPhysicsLocation(new Vector3f(0, 1, 0)); 107 characterNode = new Node("character node"); 108 Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); 109 model.scale(0.25f); 110 characterNode.addControl(physicsCharacter); 111 getPhysicsSpace().add(physicsCharacter); 112 rootNode.attachChild(characterNode); 113 characterNode.attachChild(model); 114 115 // set forward camera node that follows the character 116 camNode = new CameraNode("CamNode", cam); 117 camNode.setControlDir(ControlDirection.SpatialToCamera); 118 camNode.setLocalTranslation(new Vector3f(0, 1, -5)); 119 camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y); 120 characterNode.attachChild(camNode); 121 122 //disable the default 1st-person flyCam (don't forget this!!) 123 flyCam.setEnabled(false); 124 125 } 126 127 @Override simpleUpdate(float tpf)128 public void simpleUpdate(float tpf) { 129 Vector3f camDir = cam.getDirection().mult(0.2f); 130 Vector3f camLeft = cam.getLeft().mult(0.2f); 131 camDir.y = 0; 132 camLeft.y = 0; 133 viewDirection.set(camDir); 134 walkDirection.set(0, 0, 0); 135 if (leftStrafe) { 136 walkDirection.addLocal(camLeft); 137 } else 138 if (rightStrafe) { 139 walkDirection.addLocal(camLeft.negate()); 140 } 141 if (leftRotate) { 142 viewDirection.addLocal(camLeft.mult(0.02f)); 143 } else 144 if (rightRotate) { 145 viewDirection.addLocal(camLeft.mult(0.02f).negate()); 146 } 147 if (forward) { 148 walkDirection.addLocal(camDir); 149 } else 150 if (backward) { 151 walkDirection.addLocal(camDir.negate()); 152 } 153 physicsCharacter.setWalkDirection(walkDirection); 154 physicsCharacter.setViewDirection(viewDirection); 155 } 156 onAction(String binding, boolean value, float tpf)157 public void onAction(String binding, boolean value, float tpf) { 158 if (binding.equals("Strafe Left")) { 159 if (value) { 160 leftStrafe = true; 161 } else { 162 leftStrafe = false; 163 } 164 } else if (binding.equals("Strafe Right")) { 165 if (value) { 166 rightStrafe = true; 167 } else { 168 rightStrafe = false; 169 } 170 } else if (binding.equals("Rotate Left")) { 171 if (value) { 172 leftRotate = true; 173 } else { 174 leftRotate = false; 175 } 176 } else if (binding.equals("Rotate Right")) { 177 if (value) { 178 rightRotate = true; 179 } else { 180 rightRotate = false; 181 } 182 } else if (binding.equals("Walk Forward")) { 183 if (value) { 184 forward = true; 185 } else { 186 forward = false; 187 } 188 } else if (binding.equals("Walk Backward")) { 189 if (value) { 190 backward = true; 191 } else { 192 backward = false; 193 } 194 } else if (binding.equals("Jump")) { 195 physicsCharacter.jump(); 196 } 197 } 198 getPhysicsSpace()199 private PhysicsSpace getPhysicsSpace() { 200 return bulletAppState.getPhysicsSpace(); 201 } 202 203 @Override simpleRender(RenderManager rm)204 public void simpleRender(RenderManager rm) { 205 //TODO: add render code 206 } 207 } 208