Picking

You already found out how to create a world block and modify it from your code. But wouldn’t it be nice to have a “click-and-build functionality? (Minecraft says hello)

The framework helps you to get the block location which is e.g. pointed by your mouse - When receiving the coordinates, you can use them to add or remove a block there.

BlockNavigator

The BlockNavigator class contains various methods to help you navigate through your blockworld without having to trouble with coordinates, type casts or chunks. The method we need for (mouse) picking is this one:

public static Vector3Int getPointedBlockLocation(BlockTerrain blockTerrain, Vector3f collisionContactPoint, boolean getNeighborLocation){
    //Some mysterious code that returns the location
    //of the block in the terrain, which is placed
    //at the specified collisionContactPoint (world coordinates)
    //If you set getNeighborLocation to true, you can
    //get the empty block gap, in the direction towards you
    //(e.g. if you want to add a block to the block you've clicked)
}

Get the cursor-pointed location / RayCasting

So, the above method needs a collisionContactPoint - This is the point you’ve clicked in your world. Luckily, jMonkeyEngine offers raycasting, which lets you get exactly this point.

I recommend to read the Hello Picking tutorial first, since the rest of this chapter has nothing to do with the “Cubes framework itself.

This is a method I’ve created while creating a test case for mouse picking in the blockworld - It returns the CollisionResults of the mouse cursor and a specified node: (Generally, this will be the BlockTerrain’s node)

private CollisionResults getRayCastingResults(Node node){
    Vector3f origin = cam.getWorldCoordinates(new Vector2f((settings.getWidth() / 2), (settings.getHeight() / 2)), 0.0f);
    Vector3f direction = cam.getWorldCoordinates(new Vector2f((settings.getWidth() / 2), (settings.getHeight() / 2)), 0.3f);
    direction.subtractLocal(origin).normalizeLocal();
    Ray ray = new Ray(origin, direction);
    CollisionResults results = new CollisionResults();
    node.collideWith(ray, results);
    return results;
}

You can use the closest CollisionResult to receive the collisionContactPoint with your BlockTerrain and to finally get the “pointed block location:

private Vector3Int getCurrentPointedBlockLocation(boolean getNeighborLocation){
    CollisionResults results = getRayCastingResults(terrainNode);
    if(results.size() > 0){
        Vector3f collisionContactPoint = results.getClosestCollision().getContactPoint();
        return BlockNavigator.getPointedBlockLocation(blockTerrain, collisionContactPoint, getNeighborLocation);
    }
    return null;
}

Time to sum up: You can now get the current block location that you point with your mouse at any time you want. :)

Woah - Let’s build Minecraft!

One nice example would be to register a mouse-listener (See Hello Input) and to execute the following code when the user clicks:

//Get the free block gap, to which the user is loooking...
Vector3Int blockLocation = getCurrentPointedBlockLocation(true);
//(The block location is null, if the user looks in the sky or out of the map)
if(blockLocation != null){
    //... and place a block there :)
    blockTerrain.setBlock(blockLocation, CubesTestAssets.BLOCK_WOOD);
}

And that’s it - You just created your own minecraft-like blockworld-editor. Give yourself a challenge and implement the other mouse button to remove the pointed block (Look out for the getNeighborLocation parameter).

test_picking.png

Further improvements

  • Create different types of interactions between player and block (Open a door, turn a switch, destroy a block, …) and a way to define own interactions