Terrain collision with cubes plugin

I am scratching my head over this for the past 2 hours. I haven’t touched JME for a while (since University) and the coming back if rough.

I have pulled an old working project, along with other supposedly working codes from this forum, and put this example together. The problem is that the player falls through the cubes as if there was nothing.

[java]
public class Main extends SimpleApplication implements ActionListener {

private BulletAppState bulletAppState;
private BetterCharacterControl physicsCharacter;
//private TerrainQuad terrain;
private ChaseCamera chaseCam;
private Node characterNode;
private boolean leftStrafe = false;
private boolean rightStrafe = false;
private boolean left = false, right = false, up = false, down = false;
private Vector3f walkDirection = new Vector3f();
private Vector3f camDir = new Vector3f();
private Vector3f camLeft = new Vector3f();

public final float SPEED = 5.0f;


public static void main(String[] args) {
    AppSettings settings = new AppSettings(true);

    settings.setResolution(800, 600);
    settings.setFullscreen(false);
    //settings.set
    
    Main app = new Main();
    app.setSettings(settings);
    app.setShowSettings(false);
    app.start();
}

public Main() {
    //Skipping Fly Cam
    super(new StatsAppState(),  new DebugKeysAppState());
}

@Override
public void simpleInitApp() {
    this.setDisplayFps(false);
    this.setDisplayStatView(false);
    this.setShowSettings(false);
    this.inputManager.setCursorVisible(false);
    
    // activate physics
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);

    cam.setLocation(new Vector3f(50, 80, 50));

    initCubesEngine();
    initTerrain();
    initPlayer();
    initChaseCamera();
    
    setUpKeys();
}

private void initCubesEngine() {
    //Set cube size
    CubesSettings cubesSettings = new CubesSettings(this);
    cubesSettings.setBlockSize(1);

    CubesTestAssets.registerBlocks();
    CubesTestAssets.initializeEnvironment(this);
    CubesTestAssets.initializeWater(this);
}

private void initTerrain() {
    BlockTerrainControl blockTerrain = new BlockTerrainControl(CubesTestAssets.getSettings(this), new Vector3Int(7, 1, 7));
    //blockTerrain.setBlock(0, 0, 0, Block_Grass.class);
    //blockTerrain.setBlock(0, 0, 1, Block_Stone.class);
    blockTerrain.setBlocksFromNoise(new Vector3Int(0, 0, 0), new Vector3Int(100, 20, 100), 3f, Block_Grass.class);
    //blockTerrain.setBlocksFromHeightmap(new Vector3Int(0, 1, 0), “Textures/cubes/heightmap_australia.jpg”, 10, CubesTestAssets.BLOCK_GRASS);
    
    Node terrainNode = new Node();
    terrainNode.addControl(blockTerrain);
    terrainNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
   
    rootNode.attachChild(terrainNode);

    terrainNode.addControl(new RigidBodyControl(0));

    bulletAppState.getPhysicsSpace().addAll(terrainNode);
}

private void initPlayer() {
    // Create a node for the character model
    characterNode = new Node("Player");
    characterNode.setLocalTranslation(cam.getLocation());
     
    // Add a character control to the node so we can add other things and
    // control the model rotation
    physicsCharacter = new BetterCharacterControl(0.3f, 2.0f, 8f);
    characterNode.addControl(physicsCharacter);

    // Add character node to the rootNode
    rootNode.attachChild(characterNode);
    
    bulletAppState.getPhysicsSpace().add(physicsCharacter);
}

private void initChaseCamera() {
    chaseCam = new ChaseCamera(cam, characterNode, inputManager);
    chaseCam.setMinDistance(0.1f);
    chaseCam.setMaxDistance(0.1f);
    chaseCam.setInvertVerticalAxis(true);
    chaseCam.setDragToRotate(false);
}

private void setUpKeys() {
    inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("Click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
    
    inputManager.addListener(this, "Up");
    inputManager.addListener(this, "Up");
    inputManager.addListener(this, "Down");
    inputManager.addListener(this, "Left");
    inputManager.addListener(this, "Right");
    inputManager.addListener(this, "Click");
    inputManager.addListener(this, "Jump");
}

@Override
public void simpleUpdate(float tpf) {
    camDir.set(cam.getDirection()).multLocal(SPEED, 0.0f, SPEED);
    camLeft.set(cam.getLeft()).multLocal(SPEED);
    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());
    }
    physicsCharacter.setWalkDirection(walkDirection.multLocal(1));
    physicsCharacter.setViewDirection(camDir);
}

@Override
public void onAction(String binding, boolean isPressed, float tpf) {
    switch (binding) {
        case "Left":
            left = isPressed;
            break;
        case "Right":
            right = isPressed;
            break;
        case "Down":
            down = isPressed;
            break;
        case "Up":
            up = isPressed;
            break;
        case "Jump":
            physicsCharacter.jump();
            break;
    }
}

}
[/java]

What am I doing wrong, or what am I missing? All I want is the player to “land” on the “island” and be able to “walk around”.

Your terrain controller needs a collisionShape. “terrainNode.addControl(new RigidBodyControl(0));” doesn’t add a collisionShape, only a mass.

No idea what happens in BlockTerrainControl because we can’t see it’s code.

Your terrain controller needs a collisionShape. “terrainNode.addControl(new RigidBodyControl(0));” doesn’t add a collisionShape, only a mass.
Wrong.

In fact, it creates a fitting collision mesh, the call is therefore right. The timing is just wrong.
The cubes plugin checks every frame, if the terrain has changed and then updates the mesh accordingly - So everytime you update the mesh, you have to generate a new collisionmesh, too. You are generating the collision mesh at the start of the program, when the mesh is still empty (Cubes hasn’t generated any actual terrain yet).
You can hook up a listener, that is called everytime the terrain mesh changes and then generate a new collision mesh.

Take a look at the TestPhysics.java example:
https://code.google.com/p/jmonkeyplatform-contributions/source/browse/trunk/cubes/Cubes/src/com/cubes/test/TestPhysics.java
(The syntax on how to specify the grass-block is slightly different to your version since the svn already contains the newest unpublished version, but this has nothing to do with the way the BlockChunkListener works)

[java]blockTerrain.addChunkListener(new BlockChunkListener(){

@Override
public void onSpatialUpdated(BlockChunkControl blockChunk){
    Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
    RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
    if(rigidBodyControl == null){
        rigidBodyControl = new RigidBodyControl(0);
        optimizedGeometry.addControl(rigidBodyControl);
        bulletAppState.getPhysicsSpace().add(rigidBodyControl);
    }
    rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
}

});[/java]

This method will now be called every time the terrain mesh changes. It checks if there is already an existing physics control (if not, creates and assigns a new one) and updates its collision mesh. :slight_smile:

If there are questions left, feel free to ask.

Sorry :.

It works! Nice!

Now, my camera is looking at the floor, so I need to fix that :slight_smile: