Przeglądaj źródła

* Fix crash in TestWalkingChar

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9707 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Sha..rd 13 lat temu
rodzic
commit
6cddcf8f1d
1 zmienionych plików z 430 dodań i 430 usunięć
  1. 430 430
      engine/src/test/jme3test/bullet/TestWalkingChar.java

+ 430 - 430
engine/src/test/jme3test/bullet/TestWalkingChar.java

@@ -1,430 +1,430 @@
-/*
- * Copyright (c) 2009-2010 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package jme3test.bullet;
-
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.AnimEventListener;
-import com.jme3.animation.LoopMode;
-import com.jme3.app.SimpleApplication;
-import com.jme3.bullet.BulletAppState;
-import com.jme3.bullet.PhysicsSpace;
-import com.jme3.bullet.collision.PhysicsCollisionEvent;
-import com.jme3.bullet.collision.PhysicsCollisionListener;
-import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
-import com.jme3.bullet.collision.shapes.SphereCollisionShape;
-import com.jme3.bullet.control.CharacterControl;
-import com.jme3.bullet.control.RigidBodyControl;
-import com.jme3.bullet.util.CollisionShapeFactory;
-import com.jme3.effect.ParticleEmitter;
-import com.jme3.effect.ParticleMesh.Type;
-import com.jme3.effect.shapes.EmitterSphereShape;
-import com.jme3.input.ChaseCamera;
-import com.jme3.input.KeyInput;
-import com.jme3.input.controls.ActionListener;
-import com.jme3.input.controls.KeyTrigger;
-import com.jme3.light.DirectionalLight;
-import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
-import com.jme3.post.FilterPostProcessor;
-import com.jme3.post.filters.BloomFilter;
-import com.jme3.renderer.Camera;
-import com.jme3.renderer.queue.RenderQueue.ShadowMode;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
-import com.jme3.scene.shape.Box;
-import com.jme3.scene.shape.Sphere;
-import com.jme3.scene.shape.Sphere.TextureMode;
-import com.jme3.terrain.geomipmap.TerrainLodControl;
-import com.jme3.terrain.geomipmap.TerrainQuad;
-import com.jme3.terrain.heightmap.AbstractHeightMap;
-import com.jme3.terrain.heightmap.ImageBasedHeightMap;
-import com.jme3.texture.Texture;
-import com.jme3.texture.Texture.WrapMode;
-import com.jme3.util.SkyFactory;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A walking animated character followed by a 3rd person camera on a terrain with LOD.
- * @author normenhansen
- */
-public class TestWalkingChar extends SimpleApplication implements ActionListener, PhysicsCollisionListener, AnimEventListener {
-
-    private BulletAppState bulletAppState;
-    //character
-    CharacterControl character;
-    Node model;
-    //temp vectors
-    Vector3f walkDirection = new Vector3f();
-    //terrain
-    TerrainQuad terrain;
-    RigidBodyControl terrainPhysicsNode;
-    //Materials
-    Material matRock;
-    Material matBullet;
-    //animation
-    AnimChannel animationChannel;
-    AnimChannel shootingChannel;
-    AnimControl animationControl;
-    float airTime = 0;
-    //camera
-    boolean left = false, right = false, up = false, down = false;
-    ChaseCamera chaseCam;
-    //bullet
-    Sphere bullet;
-    SphereCollisionShape bulletCollisionShape;
-    //explosion
-    ParticleEmitter effect;
-    //brick wall
-    Box brick;
-    float bLength = 0.8f;
-    float bWidth = 0.4f;
-    float bHeight = 0.4f;
-    FilterPostProcessor fpp;
-
-    public static void main(String[] args) {
-        TestWalkingChar app = new TestWalkingChar();
-        app.start();
-    }
-
-    @Override
-    public void simpleInitApp() {
-        bulletAppState = new BulletAppState();
-        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
-        stateManager.attach(bulletAppState);
-        setupKeys();
-        prepareBullet();
-        prepareEffect();
-        createLight();
-        createSky();
-        createTerrain();
-        createWall();
-        createCharacter();
-        setupChaseCamera();
-        setupAnimationController();
-        setupFilter();
-    }
-
-    private void setupFilter() {
-        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
-        BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
-        fpp.addFilter(bloom);
-        viewPort.addProcessor(fpp);
-    }
-
-    private PhysicsSpace getPhysicsSpace() {
-        return bulletAppState.getPhysicsSpace();
-    }
-
-    private void setupKeys() {
-        inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
-        inputManager.addListener(this, "wireframe");
-        inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
-        inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
-        inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
-        inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
-        inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_RETURN));
-        inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_SPACE));
-        inputManager.addListener(this, "CharLeft");
-        inputManager.addListener(this, "CharRight");
-        inputManager.addListener(this, "CharUp");
-        inputManager.addListener(this, "CharDown");
-        inputManager.addListener(this, "CharSpace");
-        inputManager.addListener(this, "CharShoot");
-    }
-
-    private void createWall() {
-        float xOff = -144;
-        float zOff = -40;
-        float startpt = bLength / 4 - xOff;
-        float height = 6.1f;
-        brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
-        brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
-        for (int j = 0; j < 15; j++) {
-            for (int i = 0; i < 4; i++) {
-                Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, zOff);
-                addBrick(vt);
-            }
-            startpt = -startpt;
-            height += 1.01f * bHeight;
-        }
-    }
-
-    private void addBrick(Vector3f ori) {
-        Geometry reBoxg = new Geometry("brick", brick);
-        reBoxg.setMaterial(matBullet);
-        reBoxg.setLocalTranslation(ori);
-        reBoxg.addControl(new RigidBodyControl(1.5f));
-        reBoxg.setShadowMode(ShadowMode.CastAndReceive);
-        this.rootNode.attachChild(reBoxg);
-        this.getPhysicsSpace().add(reBoxg);
-    }
-
-    private void prepareBullet() {
-        bullet = new Sphere(32, 32, 0.4f, true, false);
-        bullet.setTextureMode(TextureMode.Projected);
-        bulletCollisionShape = new SphereCollisionShape(0.4f);
-        matBullet = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
-        matBullet.setColor("Color", ColorRGBA.Green);
-        matBullet.setColor("m_GlowColor", ColorRGBA.Green);
-        getPhysicsSpace().addCollisionListener(this);
-    }
-
-    private void prepareEffect() {
-        int COUNT_FACTOR = 1;
-        float COUNT_FACTOR_F = 1f;
-        effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR);
-        effect.setSelectRandomImage(true);
-        effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));
-        effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
-        effect.setStartSize(1.3f);
-        effect.setEndSize(2f);
-        effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
-        effect.setParticlesPerSec(0);
-        effect.setGravity(0, -5, 0);
-        effect.setLowLife(.4f);
-        effect.setHighLife(.5f);
-        effect.setInitialVelocity(new Vector3f(0, 7, 0));
-        effect.setVelocityVariation(1f);
-        effect.setImagesX(2);
-        effect.setImagesY(2);
-        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
-        mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
-        effect.setMaterial(mat);
-//        effect.setLocalScale(100);
-        rootNode.attachChild(effect);
-    }
-
-    private void createLight() {
-        Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
-        DirectionalLight dl = new DirectionalLight();
-        dl.setDirection(direction);
-        dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
-        rootNode.addLight(dl);
-    }
-
-    private void createSky() {
-        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
-    }
-
-    private void createTerrain() {
-        matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
-        matRock.setBoolean("useTriPlanarMapping", false);
-        matRock.setBoolean("WardIso", true);
-        matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
-        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
-        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
-        grass.setWrap(WrapMode.Repeat);
-        matRock.setTexture("DiffuseMap", grass);
-        matRock.setFloat("DiffuseMap_0_scale", 64);
-        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
-        dirt.setWrap(WrapMode.Repeat);
-        matRock.setTexture("DiffuseMap_1", dirt);
-        matRock.setFloat("DiffuseMap_1_scale", 16);
-        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
-        rock.setWrap(WrapMode.Repeat);
-        matRock.setTexture("DiffuseMap_2", rock);
-        matRock.setFloat("DiffuseMap_2_scale", 128);
-        Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
-        normalMap0.setWrap(WrapMode.Repeat);
-        Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
-        normalMap1.setWrap(WrapMode.Repeat);
-        Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
-        normalMap2.setWrap(WrapMode.Repeat);
-        matRock.setTexture("NormalMap", normalMap0);
-        matRock.setTexture("NormalMap_1", normalMap2);
-        matRock.setTexture("NormalMap_2", normalMap2);
-
-        AbstractHeightMap heightmap = null;
-        try {
-            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
-            heightmap.load();
-
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
-        List<Camera> cameras = new ArrayList<Camera>();
-        cameras.add(getCamera());
-        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
-        terrain.addControl(control);
-        terrain.setMaterial(matRock);
-        terrain.setLocalScale(new Vector3f(2, 2, 2));
-
-        terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);
-        terrain.addControl(terrainPhysicsNode);
-        rootNode.attachChild(terrain);
-        getPhysicsSpace().add(terrainPhysicsNode);
-    }
-
-    private void createCharacter() {
-        CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
-        character = new CharacterControl(capsule, 0.01f);
-        model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
-        //model.setLocalScale(0.5f);
-        model.addControl(character);
-        character.setPhysicsLocation(new Vector3f(-140, 15, -10));
-        rootNode.attachChild(model);
-        getPhysicsSpace().add(character);
-    }
-
-    private void setupChaseCamera() {
-        flyCam.setEnabled(false);
-        chaseCam = new ChaseCamera(cam, model, inputManager);
-    }
-
-    private void setupAnimationController() {
-        animationControl = model.getControl(AnimControl.class);
-        animationControl.addListener(this);
-        animationChannel = animationControl.createChannel();
-        shootingChannel = animationControl.createChannel();
-        shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right"));
-        shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right"));
-        shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right"));
-    }
-
-    @Override
-    public void simpleUpdate(float tpf) {
-        Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
-        Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
-        camDir.y = 0;
-        camLeft.y = 0;
-        walkDirection.set(0, 0, 0);
-        if (left) {
-            walkDirection.addLocal(camLeft);
-        }
-        if (right) {
-            walkDirection.addLocal(camLeft.negate());
-        }
-        if (up) {
-            walkDirection.addLocal(camDir);
-        }
-        if (down) {
-            walkDirection.addLocal(camDir.negate());
-        }
-        if (!character.onGround()) {
-            airTime = airTime + tpf;
-        } else {
-            airTime = 0;
-        }
-        if (walkDirection.length() == 0) {
-            if (!"stand".equals(animationChannel.getAnimationName())) {
-                animationChannel.setAnim("stand", 1f);
-            }
-        } else {
-            character.setViewDirection(walkDirection);
-            if (airTime > .3f) {
-                if (!"stand".equals(animationChannel.getAnimationName())) {
-                    animationChannel.setAnim("stand");
-                }
-            } else if (!"Walk".equals(animationChannel.getAnimationName())) {
-                animationChannel.setAnim("Walk", 0.7f);
-            }
-        }
-        character.setWalkDirection(walkDirection);
-    }
-
-    public void onAction(String binding, boolean value, float tpf) {
-        if (binding.equals("CharLeft")) {
-            if (value) {
-                left = true;
-            } else {
-                left = false;
-            }
-        } else if (binding.equals("CharRight")) {
-            if (value) {
-                right = true;
-            } else {
-                right = false;
-            }
-        } else if (binding.equals("CharUp")) {
-            if (value) {
-                up = true;
-            } else {
-                up = false;
-            }
-        } else if (binding.equals("CharDown")) {
-            if (value) {
-                down = true;
-            } else {
-                down = false;
-            }
-        } else if (binding.equals("CharSpace")) {
-            character.jump();
-        } else if (binding.equals("CharShoot") && !value) {
-            bulletControl();
-        }
-    }
-
-    private void bulletControl() {
-        shootingChannel.setAnim("Dodge", 0.1f);
-        shootingChannel.setLoopMode(LoopMode.DontLoop);
-        Geometry bulletg = new Geometry("bullet", bullet);
-        bulletg.setMaterial(matBullet);
-        bulletg.setShadowMode(ShadowMode.CastAndReceive);
-        bulletg.setLocalTranslation(character.getPhysicsLocation().add(cam.getDirection().mult(5)));
-        RigidBodyControl bulletControl = new BombControl(bulletCollisionShape, 1);
-        bulletControl.setCcdMotionThreshold(0.1f);
-        bulletControl.setLinearVelocity(cam.getDirection().mult(80));
-        bulletg.addControl(bulletControl);
-        rootNode.attachChild(bulletg);
-        getPhysicsSpace().add(bulletControl);
-    }
-
-    public void collision(PhysicsCollisionEvent event) {
-        if (event.getObjectA() instanceof BombControl) {
-            final Spatial node = event.getNodeA();
-            effect.killAllParticles();
-            effect.setLocalTranslation(node.getLocalTranslation());
-            effect.emitAllParticles();
-        } else if (event.getObjectB() instanceof BombControl) {
-            final Spatial node = event.getNodeB();
-            effect.killAllParticles();
-            effect.setLocalTranslation(node.getLocalTranslation());
-            effect.emitAllParticles();
-        }
-    }
-
-    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
-        if (channel == shootingChannel) {
-            channel.setAnim("stand");
-        }
-    }
-
-    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
-    }
-}
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.LoopMode;
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.PhysicsCollisionEvent;
+import com.jme3.bullet.collision.PhysicsCollisionListener;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.util.CollisionShapeFactory;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Sphere.TextureMode;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A walking animated character followed by a 3rd person camera on a terrain with LOD.
+ * @author normenhansen
+ */
+public class TestWalkingChar extends SimpleApplication implements ActionListener, PhysicsCollisionListener, AnimEventListener {
+
+    private BulletAppState bulletAppState;
+    //character
+    CharacterControl character;
+    Node model;
+    //temp vectors
+    Vector3f walkDirection = new Vector3f();
+    //terrain
+    TerrainQuad terrain;
+    RigidBodyControl terrainPhysicsNode;
+    //Materials
+    Material matRock;
+    Material matBullet;
+    //animation
+    AnimChannel animationChannel;
+    AnimChannel shootingChannel;
+    AnimControl animationControl;
+    float airTime = 0;
+    //camera
+    boolean left = false, right = false, up = false, down = false;
+    ChaseCamera chaseCam;
+    //bullet
+    Sphere bullet;
+    SphereCollisionShape bulletCollisionShape;
+    //explosion
+    ParticleEmitter effect;
+    //brick wall
+    Box brick;
+    float bLength = 0.8f;
+    float bWidth = 0.4f;
+    float bHeight = 0.4f;
+    FilterPostProcessor fpp;
+
+    public static void main(String[] args) {
+        TestWalkingChar app = new TestWalkingChar();
+        app.start();
+    }
+
+    @Override
+    public void simpleInitApp() {
+        bulletAppState = new BulletAppState();
+        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
+        stateManager.attach(bulletAppState);
+        setupKeys();
+        prepareBullet();
+        prepareEffect();
+        createLight();
+        createSky();
+        createTerrain();
+        createWall();
+        createCharacter();
+        setupChaseCamera();
+        setupAnimationController();
+        setupFilter();
+    }
+
+    private void setupFilter() {
+        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+        BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
+        fpp.addFilter(bloom);
+        viewPort.addProcessor(fpp);
+    }
+
+    private PhysicsSpace getPhysicsSpace() {
+        return bulletAppState.getPhysicsSpace();
+    }
+
+    private void setupKeys() {
+        inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
+        inputManager.addListener(this, "wireframe");
+        inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
+        inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
+        inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
+        inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
+        inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_RETURN));
+        inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_SPACE));
+        inputManager.addListener(this, "CharLeft");
+        inputManager.addListener(this, "CharRight");
+        inputManager.addListener(this, "CharUp");
+        inputManager.addListener(this, "CharDown");
+        inputManager.addListener(this, "CharSpace");
+        inputManager.addListener(this, "CharShoot");
+    }
+
+    private void createWall() {
+        float xOff = -144;
+        float zOff = -40;
+        float startpt = bLength / 4 - xOff;
+        float height = 6.1f;
+        brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
+        brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
+        for (int j = 0; j < 15; j++) {
+            for (int i = 0; i < 4; i++) {
+                Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, zOff);
+                addBrick(vt);
+            }
+            startpt = -startpt;
+            height += 1.01f * bHeight;
+        }
+    }
+
+    private void addBrick(Vector3f ori) {
+        Geometry reBoxg = new Geometry("brick", brick);
+        reBoxg.setMaterial(matBullet);
+        reBoxg.setLocalTranslation(ori);
+        reBoxg.addControl(new RigidBodyControl(1.5f));
+        reBoxg.setShadowMode(ShadowMode.CastAndReceive);
+        this.rootNode.attachChild(reBoxg);
+        this.getPhysicsSpace().add(reBoxg);
+    }
+
+    private void prepareBullet() {
+        bullet = new Sphere(32, 32, 0.4f, true, false);
+        bullet.setTextureMode(TextureMode.Projected);
+        bulletCollisionShape = new SphereCollisionShape(0.4f);
+        matBullet = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
+        matBullet.setColor("Color", ColorRGBA.Green);
+        matBullet.setColor("GlowColor", ColorRGBA.Green);
+        getPhysicsSpace().addCollisionListener(this);
+    }
+
+    private void prepareEffect() {
+        int COUNT_FACTOR = 1;
+        float COUNT_FACTOR_F = 1f;
+        effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR);
+        effect.setSelectRandomImage(true);
+        effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));
+        effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
+        effect.setStartSize(1.3f);
+        effect.setEndSize(2f);
+        effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
+        effect.setParticlesPerSec(0);
+        effect.setGravity(0, -5, 0);
+        effect.setLowLife(.4f);
+        effect.setHighLife(.5f);
+        effect.setInitialVelocity(new Vector3f(0, 7, 0));
+        effect.setVelocityVariation(1f);
+        effect.setImagesX(2);
+        effect.setImagesY(2);
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+        mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+        effect.setMaterial(mat);
+//        effect.setLocalScale(100);
+        rootNode.attachChild(effect);
+    }
+
+    private void createLight() {
+        Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
+        DirectionalLight dl = new DirectionalLight();
+        dl.setDirection(direction);
+        dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+        rootNode.addLight(dl);
+    }
+
+    private void createSky() {
+        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
+    }
+
+    private void createTerrain() {
+        matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
+        matRock.setBoolean("useTriPlanarMapping", false);
+        matRock.setBoolean("WardIso", true);
+        matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
+        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
+        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+        grass.setWrap(WrapMode.Repeat);
+        matRock.setTexture("DiffuseMap", grass);
+        matRock.setFloat("DiffuseMap_0_scale", 64);
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+        dirt.setWrap(WrapMode.Repeat);
+        matRock.setTexture("DiffuseMap_1", dirt);
+        matRock.setFloat("DiffuseMap_1_scale", 16);
+        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+        rock.setWrap(WrapMode.Repeat);
+        matRock.setTexture("DiffuseMap_2", rock);
+        matRock.setFloat("DiffuseMap_2_scale", 128);
+        Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
+        normalMap0.setWrap(WrapMode.Repeat);
+        Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
+        normalMap1.setWrap(WrapMode.Repeat);
+        Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
+        normalMap2.setWrap(WrapMode.Repeat);
+        matRock.setTexture("NormalMap", normalMap0);
+        matRock.setTexture("NormalMap_1", normalMap2);
+        matRock.setTexture("NormalMap_2", normalMap2);
+
+        AbstractHeightMap heightmap = null;
+        try {
+            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
+            heightmap.load();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
+        List<Camera> cameras = new ArrayList<Camera>();
+        cameras.add(getCamera());
+        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
+        terrain.addControl(control);
+        terrain.setMaterial(matRock);
+        terrain.setLocalScale(new Vector3f(2, 2, 2));
+
+        terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);
+        terrain.addControl(terrainPhysicsNode);
+        rootNode.attachChild(terrain);
+        getPhysicsSpace().add(terrainPhysicsNode);
+    }
+
+    private void createCharacter() {
+        CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
+        character = new CharacterControl(capsule, 0.01f);
+        model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+        //model.setLocalScale(0.5f);
+        model.addControl(character);
+        character.setPhysicsLocation(new Vector3f(-140, 15, -10));
+        rootNode.attachChild(model);
+        getPhysicsSpace().add(character);
+    }
+
+    private void setupChaseCamera() {
+        flyCam.setEnabled(false);
+        chaseCam = new ChaseCamera(cam, model, inputManager);
+    }
+
+    private void setupAnimationController() {
+        animationControl = model.getControl(AnimControl.class);
+        animationControl.addListener(this);
+        animationChannel = animationControl.createChannel();
+        shootingChannel = animationControl.createChannel();
+        shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right"));
+        shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right"));
+        shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right"));
+    }
+
+    @Override
+    public void simpleUpdate(float tpf) {
+        Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
+        Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
+        camDir.y = 0;
+        camLeft.y = 0;
+        walkDirection.set(0, 0, 0);
+        if (left) {
+            walkDirection.addLocal(camLeft);
+        }
+        if (right) {
+            walkDirection.addLocal(camLeft.negate());
+        }
+        if (up) {
+            walkDirection.addLocal(camDir);
+        }
+        if (down) {
+            walkDirection.addLocal(camDir.negate());
+        }
+        if (!character.onGround()) {
+            airTime = airTime + tpf;
+        } else {
+            airTime = 0;
+        }
+        if (walkDirection.length() == 0) {
+            if (!"stand".equals(animationChannel.getAnimationName())) {
+                animationChannel.setAnim("stand", 1f);
+            }
+        } else {
+            character.setViewDirection(walkDirection);
+            if (airTime > .3f) {
+                if (!"stand".equals(animationChannel.getAnimationName())) {
+                    animationChannel.setAnim("stand");
+                }
+            } else if (!"Walk".equals(animationChannel.getAnimationName())) {
+                animationChannel.setAnim("Walk", 0.7f);
+            }
+        }
+        character.setWalkDirection(walkDirection);
+    }
+
+    public void onAction(String binding, boolean value, float tpf) {
+        if (binding.equals("CharLeft")) {
+            if (value) {
+                left = true;
+            } else {
+                left = false;
+            }
+        } else if (binding.equals("CharRight")) {
+            if (value) {
+                right = true;
+            } else {
+                right = false;
+            }
+        } else if (binding.equals("CharUp")) {
+            if (value) {
+                up = true;
+            } else {
+                up = false;
+            }
+        } else if (binding.equals("CharDown")) {
+            if (value) {
+                down = true;
+            } else {
+                down = false;
+            }
+        } else if (binding.equals("CharSpace")) {
+            character.jump();
+        } else if (binding.equals("CharShoot") && !value) {
+            bulletControl();
+        }
+    }
+
+    private void bulletControl() {
+        shootingChannel.setAnim("Dodge", 0.1f);
+        shootingChannel.setLoopMode(LoopMode.DontLoop);
+        Geometry bulletg = new Geometry("bullet", bullet);
+        bulletg.setMaterial(matBullet);
+        bulletg.setShadowMode(ShadowMode.CastAndReceive);
+        bulletg.setLocalTranslation(character.getPhysicsLocation().add(cam.getDirection().mult(5)));
+        RigidBodyControl bulletControl = new BombControl(bulletCollisionShape, 1);
+        bulletControl.setCcdMotionThreshold(0.1f);
+        bulletControl.setLinearVelocity(cam.getDirection().mult(80));
+        bulletg.addControl(bulletControl);
+        rootNode.attachChild(bulletg);
+        getPhysicsSpace().add(bulletControl);
+    }
+
+    public void collision(PhysicsCollisionEvent event) {
+        if (event.getObjectA() instanceof BombControl) {
+            final Spatial node = event.getNodeA();
+            effect.killAllParticles();
+            effect.setLocalTranslation(node.getLocalTranslation());
+            effect.emitAllParticles();
+        } else if (event.getObjectB() instanceof BombControl) {
+            final Spatial node = event.getNodeB();
+            effect.killAllParticles();
+            effect.setLocalTranslation(node.getLocalTranslation());
+            effect.emitAllParticles();
+        }
+    }
+
+    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+        if (channel == shootingChannel) {
+            channel.setAnim("stand");
+        }
+    }
+
+    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+    }
+}