From 59b00bbae9c5ff09f97bbfb0f9d6128de6da66e1 Mon Sep 17 00:00:00 2001 From: "roo..li" Date: Sat, 6 Aug 2011 14:45:36 +0000 Subject: [PATCH] Added CameraNode and new navigation to TestPhysicsCharacter. Added a variant of createPhysicsTestWorld with more spheres. Changed the size of golem in TestWalkingCharacter to fit step length. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7983 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../jme3test/bullet/PhysicsTestHelper.java | 44 +++ .../jme3test/bullet/TestPhysicsCharacter.java | 252 +++++++++++------- .../test/jme3test/bullet/TestWalkingChar.java | 15 +- 3 files changed, 201 insertions(+), 110 deletions(-) diff --git a/engine/src/test/jme3test/bullet/PhysicsTestHelper.java b/engine/src/test/jme3test/bullet/PhysicsTestHelper.java index c3a28d7a0..dde39fe55 100644 --- a/engine/src/test/jme3test/bullet/PhysicsTestHelper.java +++ b/engine/src/test/jme3test/bullet/PhysicsTestHelper.java @@ -17,6 +17,7 @@ import com.jme3.input.controls.MouseButtonTrigger; import com.jme3.light.AmbientLight; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -78,6 +79,49 @@ public class PhysicsTestHelper { space.add(sphereGeometry); } + + public static void createPhysicsTestWorldSoccer(Node rootNode, AssetManager assetManager, PhysicsSpace space) { + AmbientLight light = new AmbientLight(); + light.setColor(ColorRGBA.LightGray); + rootNode.addLight(light); + + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + + Box floorBox = new Box(140, 0.25f, 140); + Geometry floorGeometry = new Geometry("Floor", floorBox); + floorGeometry.setMaterial(material); + floorGeometry.setLocalTranslation(0, -0.25f, 0); +// Plane plane = new Plane(); +// plane.setOriginNormal(new Vector3f(0, 0.25f, 0), Vector3f.UNIT_Y); +// floorGeometry.addControl(new RigidBodyControl(new PlaneCollisionShape(plane), 0)); + floorGeometry.addControl(new RigidBodyControl(0)); + rootNode.attachChild(floorGeometry); + space.add(floorGeometry); + + //movable spheres + for (int i = 0; i < 5; i++) { + Sphere sphere = new Sphere(16, 16, .5f); + Geometry ballGeometry = new Geometry("Soccer ball", sphere); + ballGeometry.setMaterial(material); + ballGeometry.setLocalTranslation(i, 2, -3); + //RigidBodyControl automatically uses Sphere collision shapes when attached to single geometry with sphere mesh + ballGeometry.addControl(new RigidBodyControl(.001f)); + ballGeometry.getControl(RigidBodyControl.class).setRestitution(1); + rootNode.attachChild(ballGeometry); + space.add(ballGeometry); + } + + //immovable Box with mesh collision shape + Box box = new Box(1, 1, 1); + Geometry boxGeometry = new Geometry("Box", box); + boxGeometry.setMaterial(material); + boxGeometry.setLocalTranslation(4, 1, 2); + boxGeometry.addControl(new RigidBodyControl(new MeshCollisionShape(box), 0)); + rootNode.attachChild(boxGeometry); + space.add(boxGeometry); + + } /** * creates a box geometry with a RigidBodyControl diff --git a/engine/src/test/jme3test/bullet/TestPhysicsCharacter.java b/engine/src/test/jme3test/bullet/TestPhysicsCharacter.java index dfb114d1d..2e7cc8698 100644 --- a/engine/src/test/jme3test/bullet/TestPhysicsCharacter.java +++ b/engine/src/test/jme3test/bullet/TestPhysicsCharacter.java @@ -1,33 +1,26 @@ /* - * Copyright (c) 2009-2010 jMonkeyEngine - * All rights reserved. - * + * 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 + * 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. + * 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; @@ -35,123 +28,180 @@ import com.jme3.bullet.BulletAppState; import com.jme3.app.SimpleApplication; import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; -import com.jme3.bullet.collision.shapes.SphereCollisionShape; import com.jme3.bullet.control.CharacterControl; import com.jme3.input.KeyInput; import com.jme3.input.MouseInput; import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.KeyTrigger; import com.jme3.input.controls.MouseButtonTrigger; -import com.jme3.material.Material; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.scene.shape.Sphere; -import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.scene.control.CameraControl.ControlDirection; /** - * - * @author normenhansen + * A walking physical character followed by a 3rd person camera. (No animation.) + * @author normenhansen, zathras */ public class TestPhysicsCharacter extends SimpleApplication implements ActionListener { - private BulletAppState bulletAppState; - private CharacterControl physicsCharacter; - private Vector3f walkDirection = new Vector3f(); - private Material mat; - private Sphere bullet; - private SphereCollisionShape bulletCollisionShape; + private BulletAppState bulletAppState; + private CharacterControl physicsCharacter; + private Node characterNode; + private CameraNode camNode; + boolean rotate = false; + private Vector3f walkDirection = new Vector3f(0,0,0); + private Vector3f viewDirection = new Vector3f(0,0,0); + boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, + leftRotate = false, rightRotate = false; - public static void main(String[] args) { - TestPhysicsCharacter app = new TestPhysicsCharacter(); - app.start(); - } + public static void main(String[] args) { + TestPhysicsCharacter app = new TestPhysicsCharacter(); + app.start(); + } private void setupKeys() { - inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); - inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); - inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U)); - inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J)); - inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); - inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); - inputManager.addListener(this, "shoot"); - inputManager.addListener(this, "Lefts"); - inputManager.addListener(this, "Rights"); - inputManager.addListener(this, "Ups"); - inputManager.addListener(this, "Downs"); - inputManager.addListener(this, "Space"); - inputManager.addMapping("gc", new KeyTrigger(KeyInput.KEY_X)); - inputManager.addListener(this, "gc"); + inputManager.addMapping("Strafe Left", + new KeyTrigger(KeyInput.KEY_Q), + new KeyTrigger(KeyInput.KEY_Z)); + inputManager.addMapping("Strafe Right", + new KeyTrigger(KeyInput.KEY_E), + new KeyTrigger(KeyInput.KEY_X)); + inputManager.addMapping("Rotate Left", + new KeyTrigger(KeyInput.KEY_A), + new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Rotate Right", + new KeyTrigger(KeyInput.KEY_D), + new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("Walk Forward", + new KeyTrigger(KeyInput.KEY_W), + new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("Walk Backward", + new KeyTrigger(KeyInput.KEY_S), + new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("Jump", + new KeyTrigger(KeyInput.KEY_SPACE), + new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("Shoot", + new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(this, "Strafe Left", "Strafe Right"); + inputManager.addListener(this, "Rotate Left", "Rotate Right"); + inputManager.addListener(this, "Walk Forward", "Walk Backward"); + inputManager.addListener(this, "Jump", "Shoot"); } + @Override + public void simpleInitApp() { + // activate physics + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); - @Override - public void simpleInitApp() { - bulletAppState = new BulletAppState(); - stateManager.attach(bulletAppState); - bullet = new Sphere(32, 32, 0.4f, true, false); - bullet.setTextureMode(TextureMode.Projected); - bulletCollisionShape = new SphereCollisionShape(0.4f); - PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + // init a physical test scene + PhysicsTestHelper.createPhysicsTestWorldSoccer(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + setupKeys(); - setupKeys(); + // Add a physics character to the world + physicsCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f, 1.8f), .1f); + physicsCharacter.setPhysicsLocation(new Vector3f(0, 1, 0)); + characterNode = new Node("character node"); + Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + model.scale(0.25f); + characterNode.addControl(physicsCharacter); + getPhysicsSpace().add(physicsCharacter); + rootNode.attachChild(characterNode); + characterNode.attachChild(model); - // Add a physics character to the world - physicsCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f,1.8f), .1f); - physicsCharacter.setPhysicsLocation(new Vector3f(3, 6, 0)); + // set forward camera node that follows the character + camNode = new CameraNode("CamNode", cam); + camNode.setControlDir(ControlDirection.SpatialToCamera); + camNode.setLocalTranslation(new Vector3f(0, 1, -5)); + camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y); + characterNode.attachChild(camNode); - Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); - model.scale(0.25f); - model.addControl(physicsCharacter); - getPhysicsSpace().add(physicsCharacter); - rootNode.attachChild(model); - } + //disable the default 1st-person flyCam (don't forget this!!) + flyCam.setEnabled(false); - private PhysicsSpace getPhysicsSpace() { - return bulletAppState.getPhysicsSpace(); - } + } - @Override + @Override public void simpleUpdate(float tpf) { + Vector3f camDir = cam.getDirection().mult(0.2f); + Vector3f camLeft = cam.getLeft().mult(0.2f); + camDir.y = 0; + camLeft.y = 0; + viewDirection.set(camDir); + walkDirection.set(0, 0, 0); + if (leftStrafe) { + walkDirection.addLocal(camLeft); + } else + if (rightStrafe) { + walkDirection.addLocal(camLeft.negate()); + } + if (leftRotate) { + viewDirection.addLocal(camLeft.mult(0.02f)); + } else + if (rightRotate) { + viewDirection.addLocal(camLeft.mult(0.02f).negate()); + } + if (forward) { + walkDirection.addLocal(camDir); + } else + if (backward) { + walkDirection.addLocal(camDir.negate()); + } physicsCharacter.setWalkDirection(walkDirection); - physicsCharacter.setViewDirection(walkDirection); - cam.lookAt(physicsCharacter.getPhysicsLocation(), Vector3f.UNIT_Y); - } - - @Override - public void simpleRender(RenderManager rm) { - //TODO: add render code + physicsCharacter.setViewDirection(viewDirection); } public void onAction(String binding, boolean value, float tpf) { - if (binding.equals("Lefts")) { + if (binding.equals("Strafe Left")) { if (value) { - walkDirection.addLocal(new Vector3f(-.1f, 0, 0)); + leftStrafe = true; } else { - walkDirection.addLocal(new Vector3f(.1f, 0, 0)); + leftStrafe = false; } - } else if (binding.equals("Rights")) { + } else if (binding.equals("Strafe Right")) { if (value) { - walkDirection.addLocal(new Vector3f(.1f, 0, 0)); + rightStrafe = true; } else { - walkDirection.addLocal(new Vector3f(-.1f, 0, 0)); + rightStrafe = false; } - } else if (binding.equals("Ups")) { + } else if (binding.equals("Rotate Left")) { if (value) { - walkDirection.addLocal(new Vector3f(0, 0, -.1f)); + leftRotate = true; } else { - walkDirection.addLocal(new Vector3f(0, 0, .1f)); + leftRotate = false; } - } else if (binding.equals("Downs")) { + } else if (binding.equals("Rotate Right")) { if (value) { - walkDirection.addLocal(new Vector3f(0, 0, .1f)); + rightRotate = true; } else { - walkDirection.addLocal(new Vector3f(0, 0, -.1f)); + rightRotate = false; } - } else if (binding.equals("Space")) { + } else if (binding.equals("Walk Forward")) { + if (value) { + forward = true; + } else { + forward = false; + } + } else if (binding.equals("Walk Backward")) { + if (value) { + backward = true; + } else { + backward = false; + } + } else if (binding.equals("Jump")) { physicsCharacter.jump(); } - if (binding.equals("gc") && !value) { - System.gc(); - } } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } } diff --git a/engine/src/test/jme3test/bullet/TestWalkingChar.java b/engine/src/test/jme3test/bullet/TestWalkingChar.java index 3658f18d3..3d1dbb4b4 100644 --- a/engine/src/test/jme3test/bullet/TestWalkingChar.java +++ b/engine/src/test/jme3test/bullet/TestWalkingChar.java @@ -37,7 +37,6 @@ import com.jme3.animation.AnimEventListener; import com.jme3.animation.LoopMode; import com.jme3.bullet.BulletAppState; import com.jme3.app.SimpleApplication; -import com.jme3.bounding.BoundingBox; import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.collision.PhysicsCollisionEvent; import com.jme3.bullet.collision.PhysicsCollisionListener; @@ -56,8 +55,6 @@ 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.FastMath; -import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; @@ -82,7 +79,7 @@ import java.util.List; import jme3tools.converters.ImageToAwt; /** - * + * 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 { @@ -296,12 +293,12 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener } private void createCharacter() { - CapsuleCollisionShape capsule = new CapsuleCollisionShape(1.5f, 2f); + 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.setLocalScale(0.5f); model.addControl(character); - character.setPhysicsLocation(new Vector3f(-140, 10, -10)); + character.setPhysicsLocation(new Vector3f(-140, 15, -10)); rootNode.attachChild(model); getPhysicsSpace().add(character); } @@ -323,8 +320,8 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener @Override public void simpleUpdate(float tpf) { - Vector3f camDir = cam.getDirection().clone().multLocal(0.2f); - Vector3f camLeft = cam.getLeft().clone().multLocal(0.2f); + 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);