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.animation.AnimChannel; 35 import com.jme3.animation.AnimControl; 36 import com.jme3.animation.AnimEventListener; 37 import com.jme3.animation.LoopMode; 38 import com.jme3.app.SimpleApplication; 39 import com.jme3.asset.TextureKey; 40 import com.jme3.bullet.BulletAppState; 41 import com.jme3.bullet.PhysicsSpace; 42 import com.jme3.bullet.control.KinematicRagdollControl; 43 import com.jme3.bullet.control.RigidBodyControl; 44 import com.jme3.input.KeyInput; 45 import com.jme3.input.controls.ActionListener; 46 import com.jme3.input.controls.KeyTrigger; 47 import com.jme3.light.DirectionalLight; 48 import com.jme3.material.Material; 49 import com.jme3.math.ColorRGBA; 50 import com.jme3.math.Vector2f; 51 import com.jme3.math.Vector3f; 52 import com.jme3.renderer.queue.RenderQueue.ShadowMode; 53 import com.jme3.scene.Geometry; 54 import com.jme3.scene.Node; 55 import com.jme3.scene.shape.Box; 56 import com.jme3.texture.Texture; 57 58 /** 59 * @author normenhansen 60 */ 61 public class TestRagdollCharacter extends SimpleApplication implements AnimEventListener, ActionListener { 62 63 BulletAppState bulletAppState; 64 Node model; 65 KinematicRagdollControl ragdoll; 66 boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, 67 leftRotate = false, rightRotate = false; 68 AnimControl animControl; 69 AnimChannel animChannel; 70 71 public static void main(String[] args) { 72 TestRagdollCharacter app = new TestRagdollCharacter(); 73 app.start(); 74 } 75 76 public void simpleInitApp() { 77 setupKeys(); 78 79 bulletAppState = new BulletAppState(); 80 bulletAppState.setEnabled(true); 81 stateManager.attach(bulletAppState); 82 83 84 // bulletAppState.getPhysicsSpace().enableDebug(assetManager); 85 PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); 86 initWall(2,1,1); 87 setupLight(); 88 89 cam.setLocation(new Vector3f(-8,0,-4)); 90 cam.lookAt(new Vector3f(4,0,-7), Vector3f.UNIT_Y); 91 92 model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); 93 model.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y); 94 model.setLocalTranslation(4, 0, -7f); 95 96 ragdoll = new KinematicRagdollControl(0.5f); 97 model.addControl(ragdoll); 98 99 getPhysicsSpace().add(ragdoll); 100 speed = 1.3f; 101 102 rootNode.attachChild(model); 103 104 105 AnimControl control = model.getControl(AnimControl.class); 106 animChannel = control.createChannel(); 107 animChannel.setAnim("IdleTop"); 108 control.addListener(this); 109 110 } 111 112 private void setupLight() { 113 DirectionalLight dl = new DirectionalLight(); 114 dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); 115 dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); 116 rootNode.addLight(dl); 117 } 118 119 private PhysicsSpace getPhysicsSpace() { 120 return bulletAppState.getPhysicsSpace(); 121 } 122 123 private void setupKeys() { 124 inputManager.addMapping("Rotate Left", 125 new KeyTrigger(KeyInput.KEY_H)); 126 inputManager.addMapping("Rotate Right", 127 new KeyTrigger(KeyInput.KEY_K)); 128 inputManager.addMapping("Walk Forward", 129 new KeyTrigger(KeyInput.KEY_U)); 130 inputManager.addMapping("Walk Backward", 131 new KeyTrigger(KeyInput.KEY_J)); 132 inputManager.addMapping("Slice", 133 new KeyTrigger(KeyInput.KEY_SPACE), 134 new KeyTrigger(KeyInput.KEY_RETURN)); 135 inputManager.addListener(this, "Strafe Left", "Strafe Right"); 136 inputManager.addListener(this, "Rotate Left", "Rotate Right"); 137 inputManager.addListener(this, "Walk Forward", "Walk Backward"); 138 inputManager.addListener(this, "Slice"); 139 } 140 141 public void initWall(float bLength, float bWidth, float bHeight) { 142 Box brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth); 143 brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); 144 Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); 145 TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); 146 key.setGenerateMips(true); 147 Texture tex = assetManager.loadTexture(key); 148 mat2.setTexture("ColorMap", tex); 149 150 float startpt = bLength / 4; 151 float height = -5; 152 for (int j = 0; j < 15; j++) { 153 for (int i = 0; i < 4; i++) { 154 Vector3f ori = new Vector3f(i * bLength * 2 + startpt, bHeight + height, -10); 155 Geometry reBoxg = new Geometry("brick", brick); 156 reBoxg.setMaterial(mat2); 157 reBoxg.setLocalTranslation(ori); 158 //for geometry with sphere mesh the physics system automatically uses a sphere collision shape 159 reBoxg.addControl(new RigidBodyControl(1.5f)); 160 reBoxg.setShadowMode(ShadowMode.CastAndReceive); 161 reBoxg.getControl(RigidBodyControl.class).setFriction(0.6f); 162 this.rootNode.attachChild(reBoxg); 163 this.getPhysicsSpace().add(reBoxg); 164 } 165 startpt = -startpt; 166 height += 2 * bHeight; 167 } 168 } 169 170 public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { 171 172 if (channel.getAnimationName().equals("SliceHorizontal")) { 173 channel.setLoopMode(LoopMode.DontLoop); 174 channel.setAnim("IdleTop", 5); 175 channel.setLoopMode(LoopMode.Loop); 176 } 177 178 } 179 180 public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { 181 } 182 183 public void onAction(String binding, boolean value, float tpf) { 184 if (binding.equals("Rotate Left")) { 185 if (value) { 186 leftRotate = true; 187 } else { 188 leftRotate = false; 189 } 190 } else if (binding.equals("Rotate Right")) { 191 if (value) { 192 rightRotate = true; 193 } else { 194 rightRotate = false; 195 } 196 } else if (binding.equals("Walk Forward")) { 197 if (value) { 198 forward = true; 199 } else { 200 forward = false; 201 } 202 } else if (binding.equals("Walk Backward")) { 203 if (value) { 204 backward = true; 205 } else { 206 backward = false; 207 } 208 } else if (binding.equals("Slice")) { 209 if (value) { 210 animChannel.setAnim("SliceHorizontal"); 211 animChannel.setSpeed(0.3f); 212 } 213 } 214 } 215 216 @Override 217 public void simpleUpdate(float tpf) { 218 if(forward){ 219 model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(tpf)); 220 }else if(backward){ 221 model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(-tpf)); 222 }else if(leftRotate){ 223 model.rotate(0, tpf, 0); 224 }else if(rightRotate){ 225 model.rotate(0, -tpf, 0); 226 } 227 fpsText.setText(cam.getLocation() + "/" + cam.getRotation()); 228 } 229 230 } 231