2012-01-25 10 views
6

Estoy aprendiendo JME3 y logré crear mi propio mapa de altura y modificar algunos de los códigos de ejemplo, etc. Ahora, creé una habitación sin techo de 4 paredes muy simple con Blender, exportado como un archivo Wavefront OBJ y la cargó a mi escena (I atacó al nodo terrain.JMonkeyEngine: detección de colisión en modelos cargados dinámicamente

Ahora, mi terrain tiene una detección de colisiones aplicado por lo que el jugador puede mover y saltar alrededor, pero también puede caminar a la derecha a través de las paredes de mi modelo. Todos los ejemplos que puedo encontrar cargan una escena ya preconstruida, y todavía no tengo ni idea de por qué el jugador va directamente a través del modelo cargado?

Sor para el gran código, pero no pude ver de qué otra manera podría hacerlo. La física se aplica en la sección /** 6. Add physics: */:

public class Main extends SimpleApplication 
     implements ActionListener { 

    private BulletAppState bulletAppState; 
    private RigidBodyControl landscape; 
    private CharacterControl player; 
    private Vector3f walkDirection = new Vector3f(); 
    private boolean left = false, right = false, up = false, down = false; 
    private TerrainQuad terrain; 
    private Material mat_terrain; 

    public static void main(String[] args) { 
     AppSettings settings = new AppSettings(true); 
     settings.setResolution(1366, 768); 
     settings.setFullscreen(true); 

     Main app = new Main(); 
     app.setSettings(settings); 
     app.setShowSettings(false); 
     app.start(); 
    } 

    @Override 
    public void simpleInitApp() { 
     /** Set up Physics */ 
     bulletAppState = new BulletAppState(); 
     stateManager.attach(bulletAppState); 
     //bulletAppState.getPhysicsSpace().enableDebug(assetManager); 

     flyCam.setMoveSpeed(200); 
     setUpKeys(); 

     /** 1. Create terrain material and load four textures into it. */ 
     mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md"); 

     /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */ 
     mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/terrain/island_1_alpha1.png")); 

     /** 1.2) Add GRASS texture into the red layer (Tex1). */ 
     Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); 
     grass.setWrap(WrapMode.Repeat); 
     mat_terrain.setTexture("Tex1", grass); 
     mat_terrain.setFloat("Tex1Scale", 64f); 

     /** 1.3) Add DIRT texture into the green layer (Tex2) */ 
     Texture dirt = assetManager.loadTexture("Textures/rocks.jpg"); 
     dirt.setWrap(WrapMode.Repeat); 
     mat_terrain.setTexture("Tex2", dirt); 
     mat_terrain.setFloat("Tex2Scale", 32f); 

     /** 1.4) Add ROAD texture into the blue layer (Tex3) */ 
     Texture rock = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); 
     rock.setWrap(WrapMode.Repeat); 
     mat_terrain.setTexture("Tex3", rock); 
     mat_terrain.setFloat("Tex3Scale", 128f); 

     /** 2. Create the height map */ 
     AbstractHeightMap heightmap = null; 
     Texture heightMapImage = assetManager.loadTexture("Textures/terrain/island_1.png"); 
     heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); 
     heightmap.load(); 

     /** 3. We have prepared material and heightmap. 
     * Now we create the actual terrain: 
     * 3.1) Create a TerrainQuad and name it "my terrain". 
     * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65. 
     * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513. 
     * 3.4) As LOD step scale we supply Vector3f(1,1,1). 
     * 3.5) We supply the prepared heightmap itself. 
     */ 
     terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap()); 

     /** 4. We give the terrain its material, position & scale it, and attach it. */ 
     terrain.setMaterial(mat_terrain); 
     terrain.setLocalTranslation(0, -170, 0); 
     terrain.setLocalScale(2f, 1f, 2f); 
     rootNode.attachChild(terrain); 

     /** 4.5. Load some models */ 
     Spatial building = assetManager.loadModel("Models/building1.obj"); 
     Material mat_default = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); 
     building.setMaterial(mat_default); 
     building.setLocalTranslation(90, 117, 90); 
     building.setLocalScale(5f, 5f, 5f); 
     terrain.attachChild(building); 


     /** 4.6. Load Sky */ 
     rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false)); 

     /** 4.7. Load water */ 

     // we create a water processor 
     SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager); 
     waterProcessor.setReflectionScene(rootNode); 

     // we set the water plane 
     Vector3f waterLocation = new Vector3f(0, -58, 0); 
     waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y))); 
     viewPort.addProcessor(waterProcessor); 

     // we set wave properties 
     waterProcessor.setWaterDepth(50);   // transparency of water 
     waterProcessor.setDistortionScale(0.05f); // strength of waves 
     waterProcessor.setWaveSpeed(0.05f);  // speed of waves 

     // we define the wave size by setting the size of the texture coordinates 
     Quad quad = new Quad(1000, 1000); 
     quad.scaleTextureCoordinates(new Vector2f(10f, 10f)); 

     // we create the water geometry from the quad 
     Geometry water = new Geometry("water", quad); 
     water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); 
     water.setLocalTranslation(-500, -58, 500); 
     water.setShadowMode(ShadowMode.Receive); 
     water.setMaterial(waterProcessor.getMaterial()); 
     rootNode.attachChild(water); 

     /** 5. The LOD (level of detail) depends on were the camera is: */ 
     List<Camera> cameras = new ArrayList<Camera>(); 
     cameras.add(getCamera()); 
     TerrainLodControl control = new TerrainLodControl(terrain, cameras); 
     terrain.addControl(control); 

     /** 6. Add physics: */ 
     // We set up collision detection for the scene by creating a 
     // compound collision shape and a static RigidBodyControl with mass zero.*/ 
     CollisionShape terrainShape = CollisionShapeFactory.createMeshShape(terrain); 
     landscape = new RigidBodyControl(terrainShape, 0); 
     terrain.addControl(landscape); 
     terrain.addControl(new RigidBodyControl(CollisionShapeFactory.createMeshShape(building), 0)); 

     // We set up collision detection for the player by creating 
     // a capsule collision shape and a CharacterControl. 
     // The CharacterControl offers extra settings for 
     // size, stepheight, jumping, falling, and gravity. 
     // We also put the player in its starting position. 
     CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1); 
     player = new CharacterControl(capsuleShape, 0.05f); 
     player.setJumpSpeed(50); 
     player.setFallSpeed(70); 
     player.setGravity(100); 
     player.setPhysicsLocation(new Vector3f(50, 100, 100)); 

     // We attach the scene and the player to the rootnode and the physics space, 
     // to make them appear in the game world. 
     bulletAppState.getPhysicsSpace().add(terrain); 
     bulletAppState.getPhysicsSpace().add(player); 


    } 

    /** We over-write some navigational key mappings here, so we can 
    * add physics-controlled walking and jumping: */ 
    private void setUpKeys() { 
     inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A)); 
     inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D)); 
     inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W)); 
     inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S)); 
     inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE)); 
     inputManager.addListener(this, "Left"); 
     inputManager.addListener(this, "Right"); 
     inputManager.addListener(this, "Up"); 
     inputManager.addListener(this, "Down"); 
     inputManager.addListener(this, "Jump"); 
    } 

    /** These are our custom actions triggered by key presses. 
     * We do not walk yet, we just keep track of the direction the user pressed. */ 
    public void onAction(String binding, boolean value, float tpf) { 
     if (binding.equals("Left")) { 
      if (value) { 
       left = true; 
      } else { 
       left = false; 
      } 
     } else if (binding.equals("Right")) { 
      if (value) { 
       right = true; 
      } else { 
       right = false; 
      } 
     } else if (binding.equals("Up")) { 
      if (value) { 
       up = true; 
      } else { 
       up = false; 
      } 
     } else if (binding.equals("Down")) { 
      if (value) { 
       down = true; 
      } else { 
       down = false; 
      } 
     } else if (binding.equals("Jump")) { 
      player.jump(); 
     } 
    } 

    /** 
    * This is the main event loop--walking happens here. 
    * We check in which direction the player is walking by interpreting 
    * the camera direction forward (camDir) and to the side (camLeft). 
    * The setWalkDirection() command is what lets a physics-controlled player walk. 
    * We also make sure here that the camera moves with player. 
    */ 
    @Override 
    public void simpleUpdate(float tpf) { 
     Vector3f camDir = cam.getDirection().clone().multLocal(0.6f); 
     Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f); 
     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()); 
     } 
     player.setWalkDirection(walkDirection); 
     cam.setLocation(player.getPhysicsLocation()); 
    } 
} 

Así que, ¿por qué no está mi modelo aplicado a la detección de la colisión?

Respuesta

6

He encontrado la respuesta, here. La solución al problema es el siguiente:

  1. Crear una CollisionShape. Cree un PhysicsControl suministrando
  2. CollisionShape y masa. P.ej. com.jme3.bullet.control.RigidBodyControl
  3. Agregue el PhysicsControl al Spatial. Agregue el PhysicsControl al
  4. objeto physicsSpace. Adjunte el Spatial al rootNode, como de costumbre.
  5. (Opcional) Implemente la interfaz PhysicsCollisionListener para responder a PhysicsCollisionEvents si lo desea.

Por lo tanto, reemplazar

terrain.attachChild(building); 

por

rootNode.attachChild(building); 

y añadiendo

bulletAppState.getPhysicsSpace().add(building); 
Cuestiones relacionadas