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 */
25package jme3test.bullet;
26
27import com.jme3.app.SimpleApplication;
28import com.jme3.bullet.BulletAppState;
29import com.jme3.bullet.PhysicsSpace;
30import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
31import com.jme3.bullet.control.CharacterControl;
32import com.jme3.input.KeyInput;
33import com.jme3.input.MouseInput;
34import com.jme3.input.controls.ActionListener;
35import com.jme3.input.controls.KeyTrigger;
36import com.jme3.input.controls.MouseButtonTrigger;
37import com.jme3.math.Vector3f;
38import com.jme3.renderer.RenderManager;
39import com.jme3.scene.CameraNode;
40import com.jme3.scene.Node;
41import com.jme3.scene.Spatial;
42import 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 */
48public 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
60  public static void main(String[] args) {
61    TestPhysicsCharacter app = new TestPhysicsCharacter();
62    app.start();
63  }
64
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
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
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
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
199  private PhysicsSpace getPhysicsSpace() {
200    return bulletAppState.getPhysicsSpace();
201  }
202
203  @Override
204  public void simpleRender(RenderManager rm) {
205    //TODO: add render code
206  }
207}
208