Cubes – A Block World Framework [Update Preview]

@Eliwood said: Oh, are you doing picking already?

The way I do it is to find the surface normal and compare it to a face. If it’s close enough, I add the surface normal to it divided by 2 (the sides of the block are at 0.5-ish, yeah?) and the result is the right block placement.

As for picking the block itself, you just subtract the surface normal divided by 2, doing floating point division, and then round the number.


It worked beautifully! This is really great… No more horrible offset! =D

That’s very odd. Would you mind posting your code? My own code (that I described above) seems to have a very hard time doing what I want it to do. Not even sure why.

Absolutely!

I have this broken down into several functions, so bear with me.

I’ll start with my picking tools:
[java]
//all this takes place inside an actionListener
if(name.equals(“Shoot”) && keyPressed)
{

            //pick
            CollisionResults picks =  pick(terrainNode);
            if (picks.size() > 0)
            {
                //get picked coordinates
                Vector3f closestCoords = picks.getCollision(0).getContactPoint();
                //get a normalised contact normal; this should always return a vector consisting of zeros and ones.
                Vector3f face = picks.getCollision(0).getContactNormal().normalize();
                //For adjacent blocks, use add/2
                closestCoords.addLocal(face.x / 2, face.y / 2, face.z / 2);
                //get the coordinates translated to block world coordinates
                Vector3Int translatedCoords = blockTerrain.getBlockLocation(closestCoords);
                //setblock
                blockTerrain.setBlock(translatedCoords, Block_Wood.class);
            } else
            {
                
            }
        }
        if(name.equals("Remove") && keyPressed)
        {
            //remove is similar, but subtract/2 and removeBlock
            CollisionResults picks =  pick(terrainNode);
            
            if (picks.size() > 0)
            {
                Vector3f closestCoords = picks.getCollision(0).getContactPoint();
                Vector3Int translatedCoords = blockTerrain.getBlockLocation(closestCoords);
                Vector3f face = picks.getCollision(0).getContactNormal().normalize();
                translatedCoords.subtractLocal(Math.round(face.x / 2), Math.round(face.y / 2), Math.round(face.z / 2));
                
                blockTerrain.removeBlock(translatedCoords);
            } else
            {
              
            }
        }

[/java]

my actual picking function
[java]
public CollisionResults pick(Node from)
{
CollisionResults picks = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());

    from.collideWith(ray, picks);
    return picks;
}

[/java]

and, finally, the translation code inside my blockTerrainControl. I use the built-in Cubes float-compensation function… which is another way of saying “I use this function, but have no idea what it does, only that it fixed some of my problems.”
[java]
public Vector3Int getBlockLocation(Vector3f loc)
{
loc = Util.compensateFloatRoundingErrors(loc);
int x = (int) Math.floor((float)loc.x / settings.getBlockSize());
int y = (int) Math.floor((float)loc.y / settings.getBlockSize());
int z = (int) Math.floor((float)loc.z / settings.getBlockSize());
return new Vector3Int(x, y, z);
}

[/java]

Happy to help!

EDIT: evidence suggests that I’m good at leaving out important bits and pieces, so if I’m missing something, tell me and I can add it.

1 Like

Mmm, I see. Thank you for that, now my own code works well!

Don’t worry, I use that function without knowing properly what it does, too.

This is rapidly becoming a very furnished engine on my end.

The builders work excellently, and I changed them so that you can assign them to multiple build instances - when they finish with one, they move onto the next.

Perhaps I’ll create a registry for builds, that will store all of them as instances, instead of each builder having its own instances, and give the builds assignable strings.

The interaction with some blocks is coming along all right. My version of Metadata is a hashmap of values assigned to a specific location in the grid. I’ll need to make this update-able, but it works well.

Another choice I’ve made is that there will be no GUI’s. Not sure how I’m gonna do that.

1 Like
@ulfgur said: Absolutely!

I have this broken down into several functions, so bear with me.

Nice guys, this works very well, feels so good to remove my ugly logic code for some clean Math!

Thanks!!! 8)

Im currently playing with the newest version and its pretty cool.

But I only can change the Block size by manually changing it in CubesSettings

This didnt work:

[java]CubesTestAssets.getSettings(app).setBlockSize(5); [/java]

or

[java]CubesSettings settings = new CubesSettings(app);
settings.setBlockSize(1);[/java]

Also, how can I apply a texture with better resolution?

The order in which you create your cube settings relative to the rest of the framework is important.

Is yours in the following order?

  1. create your cube settings
  2. assign your cube settings variables, like block size
  3. create your BlockTerrainControl

I don’t know about the textures, but if you figure it out, I’d be happy to know.

@ulfgur said: The order in which you create your cube settings relative to the rest of the framework is important.

Is yours in the following order?

  1. create your cube settings
  2. assign your cube settings variables, like block size
  3. create your BlockTerrainControl

I don’t know about the textures, but if you figure it out, I’d be happy to know.

Yes I think I did here is the code

[java]package com.cubes.test;

import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.app.SimpleApplication;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.cubes.*;

public class TestAustralia extends SimpleApplication{

public static SimpleApplication app;

public static void main(String[] args){
    Logger.getLogger("").setLevel(Level.SEVERE);
    TestAustralia app = new TestAustralia();
    TestAustralia.app = app;
    app.start();
}

public TestAustralia(){
    settings = new AppSettings(true);
    settings.setWidth(1280);
    settings.setHeight(720);
    settings.setTitle("Cubes Demo - Heightmap (Australia)");
}

@Override
public void simpleInitApp(){
    
    //Disable default Cam
    flyCam.setEnabled(false);
    
    //Enable custom cam
    SceneCameraController cameraController = new SceneCameraController(cam, inputManager);
   
    //Set cube size
    CubesSettings settings = new CubesSettings(app);
    settings.setBlockSize(1);
    
    CubesTestAssets.registerBlocks();
    CubesTestAssets.initializeEnvironment(this);
    CubesTestAssets.initializeWater(this);
    
    BlockTerrainControl blockTerrain = new BlockTerrainControl(CubesTestAssets.getSettings(this), new Vector3Int(7, 1, 7));
    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);
  
}

}[/java]

Oooooh! I made that mistake, too. On this line of code:

[java]BlockTerrainControl blockTerrain = new BlockTerrainControl(CubesTestAssets.getSettings(this), new Vector3Int(7, 1, 7));[/java]

You’re initializing your BlockTerrainControl with the settings provided by CubeTestAssets instead of the settings you created. So, if you replace that line with one that looks like this:

[java]BlockTerrainControl blockTerrain = new BlockTerrainControl(settings, new Vector3Int(7, 1, 7));[/java]

It should, in theory, work.

@ulfgur said: Oooooh! I made that mistake, too. On this line of code:

[java]BlockTerrainControl blockTerrain = new BlockTerrainControl(CubesTestAssets.getSettings(this), new Vector3Int(7, 1, 7));[/java]

You’re initializing your BlockTerrainControl with the settings provided by CubeTestAssets instead of the settings you created. So, if you replace that line with one that looks like this:

[java]BlockTerrainControl blockTerrain = new BlockTerrainControl(settings, new Vector3Int(7, 1, 7));[/java]

It should, in theory, work.

I get this error

[java]run:
Sep 27, 2014 11:30:17 AM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalStateException: No material is set for Geometry:
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:689)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:683)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:683)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:683)
at com.jme3.renderer.RenderManager.renderScene(RenderManager.java:658)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:992)
at com.jme3.water.WaterFilter.preFrame(WaterFilter.java:170)
at com.jme3.post.FilterPostProcessor.preFrame(FilterPostProcessor.java:331)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:975)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1047)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:252)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

BUILD SUCCESSFUL (total time: 40 seconds)[/java]

OK, two things:

You may not have registered your blocks. This can be accomplished with CubesTestAssets.registerBlocks();

Secondly, it looks like your error is coming from the water filter. I’d try to run something that doesn’t involve water first, to get it working before you include water. I may be able to help up until that point; once you get into water and other (what’s the term… filter? post-processor effect?) you’ll need someone more experienced to help you.

To help you along, I’ve included my blockTerrainControl initialization code:

[java]CubesTestAssets.registerBlocks();

    terrainNode = new Node("Terrain");
    
    rootNode.attachChild(terrainNode);
    
    //create cube settings
    blockSettings = new CubesSettings(app);
    blockSettings.setBlockSize(worldScale);
    blockSettings.setChunkSizeX(chunkCubeSise);
    blockSettings.setChunkSizeY(chunkCubeSise);
    blockSettings.setChunkSizeZ(chunkCubeSise);
    Material tempMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
    blockSettings.setDefaultBlockMaterial("Textures/cubes/terrain.png");
    
    
    //create a terrain node and add the control
    
    blockTerrain = new BlockTerrainControl(blockSettings);
    terrainNode.addControl(blockTerrain);[/java] 

I hate to be “that guy”, but… have you checked the wiki? There are some tutorials in it to help set up the basic world. It may even link to some working files you can look at.

@ulfgur said:

I hate to be “that guy”, but… have you checked the wiki? There are some tutorials in it to help set up the basic world. It may even link to some working files you can look at.

You seem to be at another version, Im compiling my version directly from the updated svn source. Yes I know the wiki :slight_smile: I dont think basics are the problem here, I get the water error because there is no material in some geometry but that isnt the point, my code is just TestAustralia.java from com.cubes.test + the two lines to changes the settings, without those lines everything is fine. I can change the default size of cubes in CubesSettings manually. I just wanted to say the method is throwing errors.

Hello,

this is one of my first posts on this forum. I have been working on a silly little voxel game, but need to have a worthy-of-use chunk manager (loading/unloading). Can anyone point me in the right direction as to how to do this? I have physics all setup and custom blocks and world generator. But the generator takes forever due to no chunks :frowning:

Any help would be great!!

@lawsy

Thanks!!

It looks really cool. But I have one question. I want to develop some game, and it will have some similarity to bloxel world, but with some differences too. Can I use and modify your engine?

It looks really cool. But I have one question. I want to develop some game, and it will have some similarity to bloxel world, but with some differences too. Can I use and modify your framework?

It looks really cool. But I have one question. I want to develop some game, and it will have some similarity to bloxel world, but with some differences too. Can I use and modify your framework?
P. S. Sorry for my bad English. And I’m sorry for some kind of flood (I have sent 3 similar replies). I had problems with Internet :frowning:

@Teapot
The framework is open-source and you can feel free to use it in your game. :slight_smile: If you want to see the code and not just use the framework, you can find it here:
https://code.google.com/p/jmonkeyplatform-contributions/source/browse/#svn%2Ftrunk%2Fcubes%2FCubes%2Fsrc%2Fcom%2Fcubes

@destroflyer, can you help me in any way? Thanks!!

@WookiePaw said: Hello,

this is one of my first posts on this forum. I have been working on a silly little voxel game, but need to have a worthy-of-use chunk manager (loading/unloading). Can anyone point me in the right direction as to how to do this? I have physics all setup and custom blocks and world generator. But the generator takes forever due to no chunks :frowning:

Any help would be great!!

@lawsy

Thanks!!

It would be a pleasure to help out in any way I can, please understand that I am no means an expert and there is way smarter guys with tones of experience in this forum.

This topic has been discuss many times over in this post, and there are different ways to go about a chunk manager for the framework, some of the guys on this forum have used clever techniques creating a chunk manager using the framework in its current form.

As for myself, I rewritten @destroflyer cube framework and using @sleaker greedy meshing to create a voxel world that suited my project, the guys done tones of awesome work, however going down this path is a lot of work, but like a true engineer, I needed to know how it all works and have no regrets :slight_smile:

Think it would be safe to say, if you are planning a infinite world using a chunk manager, you will at some point need to have a good threading model for loading/unloading chunks for smooth game play, and only displaying surface blocks, and watch your memory usage, when you start getting in the millions to tens of millions of blocks, memory will be very important, have a good concept or research Java garbage collector.

My method:

Chunk Manager
[java]private final ConcurrentHashMap<Vector3Int, Chunk> chunks = new ConcurrentHashMap<>();[/java]

Player position
[java]private Chunk getCurrentPosition() {
CollisionResults results = new CollisionResults();
terrainNode.collideWith(getRayCasting(Vector3f.UNIT_Y.negate()), results);

    if (results.size() == 0) {
        return null;
    }

    return getChunkControl(results.getClosestCollision().getGeometry());

}[/java]

Generate chunks around the player position
[java]private synchronized Set<Vector3Int> generator(Vector3Int location, Vector3Int size) {
Set<Vector3Int> points = new HashSet<>();

    int width = size.getX(), height = size.getY(), length = size.getZ();
    for (int y = height; y &gt;= 0; y--) {
        for (int x = width - width * 2; x &lt;= width; x++) {
            for (int z = length - length * 2; z &lt;= length; z++) {
                points.add(location.add(x, y, z));
            }
        }
    }

    return points;

}[/java]

Remove chunks that are no longer in the player vicinity
[java]private synchronized void removeChunkBlocks(final Set<Vector3Int> loading, final Vector3Int location) {
location.setY(0);
Set<Vector3Int> loaded = generator(location.clone(), settings.getWorldSize());

    if (loaded.removeAll(loading)) {
        chunkManager.removeChunks(loaded);
    }

}[/java]

1 Like

Ok, thank you very much :slight_smile:

1 Like