Here is some code that uses direct references without indices. It also organizes the blocks in Chunk nodes.
It might not be exactly the approach you want to go for (I guess, you will not be generating all the chunks and blocks at the beginning, but rather load them from your DB as you go), but maybe it helps.
First, a class representing a chunk (it extends Node).
For demonstration purposes each chunk uses its own color for its blocks:
package mygame;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import java.util.HashMap;
import java.util.Map;
public class Chunk extends Node {
private ColorRGBA chunkColor = ColorRGBA.randomColor();
private Map<Vector2f, Geometry> blocks = new HashMap<Vector2f, Geometry>();
public void addBlockAt(int x, int y, AssetManager assetManager) {
// Create block
Box box = new Box(0.5f, 0.5f, 0.5f);
Geometry block = new Geometry("block", box);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", chunkColor);
block.setMaterial(mat);
// Move the block to its position
block.move(x, y, 0);
// Store the block in the map
blocks.put(new Vector2f(x, y), block);
// Attach the block
attachChild(block);
}
public Map<Vector2f, Geometry> getBlocks() {
return blocks;
}
}
Then we have the Main class, which creates 100x100 blocks. Each time a block is created it is automatically allocated to the appropriate chunk:
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import java.util.HashMap;
import java.util.Map;
public class Main extends SimpleApplication {
public static final int CHUNK_SIZE = 10;
private Map<Vector2f, Chunk> chunks = new HashMap<Vector2f, Chunk>();
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
addBlock(x, y);
}
}
}
private void addBlock(int x, int y) {
// get chunk
int chunkX = x / CHUNK_SIZE;
int chunkY = y / CHUNK_SIZE;
Vector2f chunkCoordinates = new Vector2f(chunkX, chunkY);
Chunk chunk = chunks.get(chunkCoordinates);
if (chunk == null) {
// Create chunk
chunk = new Chunk();
// Move chunk to its correct position
chunk.move(chunkX * CHUNK_SIZE, chunkY * CHUNK_SIZE, 0);
// Store chunk in map
chunks.put(chunkCoordinates, chunk);
// Only for testing purposes: Attach all creates chunks to the rootNode
rootNode.attachChild(chunk);
}
// get coordinates of block within chunk
int blockX = x % CHUNK_SIZE;
int blockY = y % CHUNK_SIZE;
// create block
chunk.addBlockAt(blockX, blockY, assetManager);
}
}
Running this gives you a 100x100 array of blocks in the world. Each 10x10 block has its own color because it’s a different chunk.
If you need a back reference from a block to its chunk, you can easily store it in the Geometry’s userData.