| /* |
| * 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.app.SimpleApplication; |
| import com.jme3.bounding.BoundingBox; |
| import com.jme3.bullet.BulletAppState; |
| import com.jme3.bullet.PhysicsSpace; |
| import com.jme3.bullet.collision.PhysicsCollisionObject; |
| import com.jme3.bullet.collision.shapes.BoxCollisionShape; |
| import com.jme3.bullet.collision.shapes.CollisionShape; |
| import com.jme3.bullet.control.RigidBodyControl; |
| import com.jme3.bullet.util.CollisionShapeFactory; |
| import com.jme3.font.BitmapText; |
| import com.jme3.input.ChaseCamera; |
| import com.jme3.input.KeyInput; |
| import com.jme3.input.controls.ActionListener; |
| import com.jme3.input.controls.AnalogListener; |
| import com.jme3.input.controls.KeyTrigger; |
| import com.jme3.light.DirectionalLight; |
| import com.jme3.light.PointLight; |
| import com.jme3.material.Material; |
| import com.jme3.math.*; |
| import com.jme3.renderer.Camera; |
| import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
| import com.jme3.scene.Geometry; |
| import com.jme3.scene.Spatial; |
| import com.jme3.shadow.PssmShadowRenderer; |
| import com.jme3.shadow.PssmShadowRenderer.CompareMode; |
| import com.jme3.shadow.PssmShadowRenderer.FilterMode; |
| 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; |
| |
| public class TestHoveringTank extends SimpleApplication implements AnalogListener, |
| ActionListener { |
| |
| private BulletAppState bulletAppState; |
| private PhysicsHoverControl hoverControl; |
| private Spatial spaceCraft; |
| TerrainQuad terrain; |
| Material matRock; |
| boolean wireframe = false; |
| protected BitmapText hintText; |
| PointLight pl; |
| Geometry lightMdl; |
| Geometry collisionMarker; |
| |
| public static void main(String[] args) { |
| TestHoveringTank app = new TestHoveringTank(); |
| app.start(); |
| } |
| |
| private PhysicsSpace getPhysicsSpace() { |
| return bulletAppState.getPhysicsSpace(); |
| } |
| |
| private void setupKeys() { |
| inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A)); |
| inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D)); |
| inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W)); |
| inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S)); |
| inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); |
| inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); |
| inputManager.addListener(this, "Lefts"); |
| inputManager.addListener(this, "Rights"); |
| inputManager.addListener(this, "Ups"); |
| inputManager.addListener(this, "Downs"); |
| inputManager.addListener(this, "Space"); |
| inputManager.addListener(this, "Reset"); |
| } |
| |
| @Override |
| public void simpleInitApp() { |
| bulletAppState = new BulletAppState(); |
| bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); |
| stateManager.attach(bulletAppState); |
| // bulletAppState.getPhysicsSpace().enableDebug(assetManager); |
| bulletAppState.getPhysicsSpace().setAccuracy(1f/30f); |
| rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false)); |
| |
| PssmShadowRenderer pssmr = new PssmShadowRenderer(assetManager, 2048, 3); |
| pssmr.setDirection(new Vector3f(-0.5f, -0.3f, -0.3f).normalizeLocal()); |
| pssmr.setLambda(0.55f); |
| pssmr.setShadowIntensity(0.6f); |
| pssmr.setCompareMode(CompareMode.Hardware); |
| pssmr.setFilterMode(FilterMode.Bilinear); |
| viewPort.addProcessor(pssmr); |
| |
| setupKeys(); |
| createTerrain(); |
| buildPlayer(); |
| |
| DirectionalLight dl = new DirectionalLight(); |
| dl.setColor(new ColorRGBA(1.0f, 0.94f, 0.8f, 1f).multLocal(1.3f)); |
| dl.setDirection(new Vector3f(-0.5f, -0.3f, -0.3f).normalizeLocal()); |
| rootNode.addLight(dl); |
| |
| Vector3f lightDir2 = new Vector3f(0.70518064f, 0.5902297f, -0.39287305f); |
| DirectionalLight dl2 = new DirectionalLight(); |
| dl2.setColor(new ColorRGBA(0.7f, 0.85f, 1.0f, 1f)); |
| dl2.setDirection(lightDir2); |
| rootNode.addLight(dl2); |
| } |
| |
| private void buildPlayer() { |
| spaceCraft = assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); |
| CollisionShape colShape = CollisionShapeFactory.createDynamicMeshShape(spaceCraft); |
| spaceCraft.setShadowMode(ShadowMode.CastAndReceive); |
| spaceCraft.setLocalTranslation(new Vector3f(-140, 14, -23)); |
| spaceCraft.setLocalRotation(new Quaternion(new float[]{0, 0.01f, 0})); |
| |
| hoverControl = new PhysicsHoverControl(colShape, 500); |
| hoverControl.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_02); |
| |
| spaceCraft.addControl(hoverControl); |
| |
| |
| rootNode.attachChild(spaceCraft); |
| getPhysicsSpace().add(hoverControl); |
| |
| ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); |
| spaceCraft.addControl(chaseCam); |
| |
| flyCam.setEnabled(false); |
| } |
| |
| public void makeMissile() { |
| Vector3f pos = spaceCraft.getWorldTranslation().clone(); |
| Quaternion rot = spaceCraft.getWorldRotation(); |
| Vector3f dir = rot.getRotationColumn(2); |
| |
| Spatial missile = assetManager.loadModel("Models/SpaceCraft/Rocket.mesh.xml"); |
| missile.scale(0.5f); |
| missile.rotate(0, FastMath.PI, 0); |
| missile.updateGeometricState(); |
| |
| BoundingBox box = (BoundingBox) missile.getWorldBound(); |
| final Vector3f extent = box.getExtent(null); |
| |
| BoxCollisionShape boxShape = new BoxCollisionShape(extent); |
| |
| missile.setName("Missile"); |
| missile.rotate(rot); |
| missile.setLocalTranslation(pos.addLocal(0, extent.y * 4.5f, 0)); |
| missile.setLocalRotation(hoverControl.getPhysicsRotation()); |
| missile.setShadowMode(ShadowMode.Cast); |
| RigidBodyControl control = new BombControl(assetManager, boxShape, 20); |
| control.setLinearVelocity(dir.mult(100)); |
| control.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_03); |
| missile.addControl(control); |
| |
| |
| rootNode.attachChild(missile); |
| getPhysicsSpace().add(missile); |
| } |
| |
| public void onAnalog(String binding, float value, float tpf) { |
| } |
| |
| public void onAction(String binding, boolean value, float tpf) { |
| if (binding.equals("Lefts")) { |
| hoverControl.steer(value ? 50f : 0); |
| } else if (binding.equals("Rights")) { |
| hoverControl.steer(value ? -50f : 0); |
| } else if (binding.equals("Ups")) { |
| hoverControl.accelerate(value ? 100f : 0); |
| } else if (binding.equals("Downs")) { |
| hoverControl.accelerate(value ? -100f : 0); |
| } else if (binding.equals("Reset")) { |
| if (value) { |
| System.out.println("Reset"); |
| hoverControl.setPhysicsLocation(new Vector3f(-140, 14, -23)); |
| hoverControl.setPhysicsRotation(new Matrix3f()); |
| hoverControl.clearForces(); |
| } else { |
| } |
| } else if (binding.equals("Space") && value) { |
| makeMissile(); |
| } |
| } |
| |
| public void updateCamera() { |
| rootNode.updateGeometricState(); |
| |
| Vector3f pos = spaceCraft.getWorldTranslation().clone(); |
| Quaternion rot = spaceCraft.getWorldRotation(); |
| Vector3f dir = rot.getRotationColumn(2); |
| |
| // make it XZ only |
| Vector3f camPos = new Vector3f(dir); |
| camPos.setY(0); |
| camPos.normalizeLocal(); |
| |
| // negate and multiply by distance from object |
| camPos.negateLocal(); |
| camPos.multLocal(15); |
| |
| // add Y distance |
| camPos.setY(2); |
| camPos.addLocal(pos); |
| cam.setLocation(camPos); |
| |
| Vector3f lookAt = new Vector3f(dir); |
| lookAt.multLocal(7); // look at dist |
| lookAt.addLocal(pos); |
| cam.lookAt(lookAt, Vector3f.UNIT_Y); |
| } |
| |
| @Override |
| public void simpleUpdate(float tpf) { |
| } |
| |
| 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)); |
| terrain.setLocked(false); // unlock it so we can edit the height |
| |
| terrain.setShadowMode(ShadowMode.CastAndReceive); |
| terrain.addControl(new RigidBodyControl(0)); |
| rootNode.attachChild(terrain); |
| getPhysicsSpace().addAll(terrain); |
| |
| } |
| } |