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 */
32package jme3test.bullet;
33
34import com.jme3.animation.AnimChannel;
35import com.jme3.animation.AnimControl;
36import com.jme3.animation.AnimEventListener;
37import com.jme3.animation.LoopMode;
38import com.jme3.app.SimpleApplication;
39import com.jme3.asset.TextureKey;
40import com.jme3.bullet.BulletAppState;
41import com.jme3.bullet.PhysicsSpace;
42import com.jme3.bullet.control.KinematicRagdollControl;
43import com.jme3.bullet.control.RigidBodyControl;
44import com.jme3.input.KeyInput;
45import com.jme3.input.controls.ActionListener;
46import com.jme3.input.controls.KeyTrigger;
47import com.jme3.light.DirectionalLight;
48import com.jme3.material.Material;
49import com.jme3.math.ColorRGBA;
50import com.jme3.math.Vector2f;
51import com.jme3.math.Vector3f;
52import com.jme3.renderer.queue.RenderQueue.ShadowMode;
53import com.jme3.scene.Geometry;
54import com.jme3.scene.Node;
55import com.jme3.scene.shape.Box;
56import com.jme3.texture.Texture;
57
58/**
59 * @author normenhansen
60 */
61public 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