* Fix crash in TestWalkingChar
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9707 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
		
							parent
							
								
									3c4405868a
								
							
						
					
					
						commit
						6cddcf8f1d
					
				| @ -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) { | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user