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