Why no collision with terrain? [SOLVED]

Noob question. Why no collision with the terrain/scene? This is the code…

package com.tropicisland.mygame;


import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.util.CollisionShapeFactory;
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.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.CameraNode;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.renderer.RenderManager;


/**
 * 
 * This collision code uses Physics and a custom Action Listener.
 * @author 
 */
public class Char extends SimpleApplication
        implements ActionListener {

  private Spatial model;
  private BulletAppState bulletAppState;
  private RigidBodyControl landscape;
  private CharacterControl playerCharacter;
  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;

  //Temporary vectors used on each frame.
  //They here to avoid instanciating new vectors on each frame
  private Vector3f camDir = new Vector3f();
  private Vector3f camLeft = new Vector3f();

  public static void main(String[] args) {
    Char app = new Char();
    app.start();
  }
   

  public void simpleInitApp() {
    /** Set up Physics */
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    //bulletAppState.setDebugEnabled(true);

    setUpKeys();
    setUpLight();

    // We load the scene from the zip file and adjust its size.
	Spatial sceneModel = assetManager.loadModel("Scenes/Terrain/desert.j3o");
    sceneModel.setLocalTranslation(0, -5.2f, 0);
    sceneModel.setLocalScale(2);
    rootNode.attachChild(sceneModel);
	
    // We set up collision detection for the scene by creating a
    // compound collision shape and a static RigidBodyControl with mass zero.
    CollisionShape sceneShape =
    CollisionShapeFactory.createMeshShape(sceneModel);
    landscape = new RigidBodyControl(sceneShape, 0);
    sceneModel.addControl(landscape);

    // We set up collision detection for the player 
    //
    // Add a physics character to the world
    playerCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f, 1.8f), .1f);
    playerCharacter.setPhysicsLocation(new Vector3f(0, 1, 0));
    characterNode = new Node("character node");
    Spatial model = assetManager.loadModel("Models/v/c.j3o");
    model.scale(0.25f);
    characterNode.addControl(playerCharacter);
    getPhysicsSpace().add(playerCharacter);
    rootNode.attachChild(characterNode);
	characterNode.attachChild(model);
	
    // We attach the scene and the player to the rootnode and the physics space,
    // to make them appear in the game world.
	//
	

    // 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);

    //disable the default 1st-person flyCam (don't forget this!!)
	flyCam.setEnabled(false);

  }

  private void setUpLight() {
    // We add light so we see the scene
	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);
  }

  /** We over-write some navigational key mappings here, so we can
   * add physics-controlled walking and jumping: */
  private void setUpKeys() {
	
        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");
	
	
	
  }

  /** 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("Strafe Left")) {
            if (value) {
                leftStrafe = true;
            } else {
                leftStrafe = false;
            }
        } else if (binding.equals("Strafe Right")) {
            if (value) {
                rightStrafe = true;
            } else {
                rightStrafe = false;
            }
        } else if (binding.equals("Rotate Left")) {
            if (value) {
                leftRotate = true;
            } else {
                leftRotate = false;
            }
        } else if (binding.equals("Rotate Right")) {
            if (value) {
                rightRotate = true;
            } else {
                rightRotate = false;
            }
        } 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")) {
            playerCharacter.jump();
        }
}

  /**
   * This is the main event loop--walking happens here.
   * 
   * 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().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());
        }
        playerCharacter.setWalkDirection(walkDirection);
        playerCharacter.setViewDirection(viewDirection);
}

  private PhysicsSpace getPhysicsSpace() {
    return bulletAppState.getPhysicsSpace();
}

  @Override
  public void simpleRender(RenderManager rm) {
    //TODO: add render code
}

}

Do you add the terrain to the physics space?

No he didn’t !

@melod
Use bulletAppState.setDebugEnabled(true); to see the currently added collision shapes.

Right.
But now why my character model flying? The feet is in the midle of the capsule. How to fix this?

You might need to enable gravity for that model.

Anyway, I would use BetterCharacterControl instead of CharacterControl here.

I try BetterCharacterControl. I do like this…

package com.tropicisland.mygame;


import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.util.CollisionShapeFactory;
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.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.Vector3f;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl.ControlDirection;

import com.jme3.asset.plugins.ZipLocator;

/**
 * A walking physical character followed by a 3rd person camera. (No animation.)
 * @author 
 */
public class TestChar extends SimpleApplication implements ActionListener {

  private BulletAppState bulletAppState;
  private BetterCharacterControl physicsCharacter;
  private RigidBodyControl landscape;  
  private Spatial sceneModel;  
  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) {
    TestChar app = new TestChar();
    app.start();
  }

    private void setupKeys() {
        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);
    bulletAppState.setDebugEnabled(true);

    // init a physical test scene

    setupKeys();

	//Add terrain/scene
	Spatial sceneModel = assetManager.loadModel("Scenes/Terrain/desert2.j3o");
    sceneModel.setLocalTranslation(0, -5.2f, 0);
    sceneModel.setLocalScale(2);
    rootNode.attachChild(sceneModel);
    // We set up collision detection for the scene by creating a
    // compound collision shape and a static RigidBodyControl with mass zero.
    CollisionShape sceneShape =
    CollisionShapeFactory.createMeshShape(sceneModel);
    landscape = new RigidBodyControl(sceneShape, 0);
    sceneModel.addControl(landscape);	
    // We attach the scene to the physics space,
	//
    bulletAppState.getPhysicsSpace().add(landscape);	

    // Create a node for the character model
    characterNode = new Node("character node");
	characterNode.setLocalTranslation(new Vector3f(4, 5, 2));	
	
    // Add a physics character to the world
    // Add a character control to the node so we can add other things and
    // control the model rotation
    physicsCharacter = new BetterCharacterControl(0.3f, 2.5f, .1f);
    characterNode.addControl(physicsCharacter);
	getPhysicsSpace().add(physicsCharacter);

    // Load model, attach to character node
    Node model = (Node) assetManager.loadModel("Models/v/c.j3o");
    model.setLocalScale(1.5f);
	characterNode.attachChild(model);

    // Add character node to the rootNode
	rootNode.attachChild(characterNode);	

    characterNode.attachChild(model);

    // 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);

    //disable the default 1st-person flyCam (don't forget this!!)
    flyCam.setEnabled(false);

  }

   @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(viewDirection);
    }

    public void onAction(String binding, boolean value, float tpf) {
        if (binding.equals("Strafe Left")) {
            if (value) {
                leftStrafe = true;
            } else {
                leftStrafe = false;
            }
        } else if (binding.equals("Strafe Right")) {
            if (value) {
                rightStrafe = true;
            } else {
                rightStrafe = false;
            }
        } else if (binding.equals("Rotate Left")) {
            if (value) {
                leftRotate = true;
            } else {
                leftRotate = false;
            }
        } else if (binding.equals("Rotate Right")) {
            if (value) {
                rightRotate = true;
            } else {
                rightRotate = false;
            }
        } 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();
        }
    }

  private PhysicsSpace getPhysicsSpace() {
    return bulletAppState.getPhysicsSpace();
  }

  @Override
  public void simpleRender(RenderManager rm) {
    //TODO: add render code
  }
}

The character move really slowly. Now the character is too big, twice bigger than I want. And probably I need to ajust the camera higher. How to scale the character and ajust the camera?

Well then multiply your walkDirection vector with a higher value.

Maybe because call the following line: model.setLocalScale(1.5f);

Please do the tutorials!

yeah. I know. :stuck_out_tongue: