jME 3.10.0-alpha4
jMonkeyEngine Hub
May 7, 2026
https://drive.google.com/drive/folders/1mnwaMuswKaG4m853MOhAhKX7jg30mcsW?usp=sharing
This is a main, where every frame I update get x y z of player and show tiles if needed. When I need new tiles, I will assign the correct image to the tile.
The images I use are 16 grey scale, so have only one channel.
package com.worldgame;
import Terrain.TileManager;
import Terrain.TileMeshBuilder;
import Terrain.location.Position3D;
import Terrain.utils.Tile;
import Terrain.utils.TileID;
import com.config.AppSettingsConfig;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.system.AppSettings;
import com.jme3.texture.Texture;
import java.util.HashMap;
import java.util.Set;
public class WorldGame extends SimpleApplication {
private TileManager terrainDataManager;
private final HashMap<TileID, Geometry> renderedTiles = new HashMap<>();
private final HashMap<String, Texture> textureCache = new HashMap<>();
public static void main(String
args) {
WorldGame app = new WorldGame();
AppSettings settings = AppSettingsConfig.getInstance().getSettings();
app.setSettings(settings);
app.start();
}
@Override
public void simpleInitApp() {assetManager.registerLocator(
"C:\\software\\eclipse_workspace\\WorldGame\\src\\main\\resources\\heightData",
com.jme3.asset.plugins.FileLocator.class
);
cam.setLocation(new Vector3f(0, 1f, 0f));
Vector3f playerPos = cam.getLocation();
cam.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);
cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.00001f, 1000f);
float[] earthCenter = new float[]{0f, 0f, 0f};
viewPort.setBackgroundColor(ColorRGBA.White); // Purple/indigo nyan color
terrainDataManager = new TileManager(
new Position3D(playerPos.x, playerPos.y, playerPos.z),
new Position3D(earthCenter[0], earthCenter[1], earthCenter[2])
);
Set<Tile> tiles = terrainDataManager.getTilesToRender();
for (Tile t : tiles) {
addTile(t);
}
flyCam.setMoveSpeed(0.01f);
System.out.println("=== Scene Tree ===");
printSceneTree(rootNode, 0);
}
@Override
public void simpleUpdate(float tpf) {
Vector3f playerPos = cam.getLocation();
boolean playerChangedTile = terrainDataManager.setPlayerTile(
new Position3D(playerPos.x, playerPos.y, playerPos.z));
// First frame: same tile as constructor → setPlayerTile false; still need to attach meshes.
if (playerChangedTile) {
Set<Tile> tiles = terrainDataManager.getTilesToRender();
for (Tile t : tiles) {
if (!renderedTiles.containsKey(t.getTileId())) {
addTile(t);
}
}
renderedTiles.entrySet().removeIf(entry -> {
boolean stillVisible = tiles.stream().anyMatch(t -> t.getTileId() == entry.getKey());
if (!stillVisible) {
entry.getValue().removeFromParent();
}
return !stillVisible;
});
}
}
private void addTile(Tile t) {
Mesh m = TileMeshBuilder.getInstance().buildMeshFromTile(t.getBuffer());
Geometry g = new Geometry("tile_" + t.hashCode(), m);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TileID id = t.getTileId();
Texture tex = getTexture(id);
mat.setTexture("ColorMap", tex);
mat.getAdditionalRenderState().setWireframe(false);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
g.setMaterial(mat);
rootNode.attachChild(g);
renderedTiles.put(t.getTileId(), g);
}
private void printSceneTree(com.jme3.scene.Spatial node, int depth) {
String indent = " ".repeat(depth);
System.out.println(indent + node.getName() + " (" + node.getClass().getSimpleName() + ")");
if (node instanceof com.jme3.scene.Node n) {
for (com.jme3.scene.Spatial child : n.getChildren()) {
printSceneTree(child, depth + 1);
}
}
}private Texture getTexture(TileID id) {
String path = id.face() + "/" + id.row() + "_" + id.col() + ".png";
return textureCache.computeIfAbsent(path, p -> assetManager.loadTexture(p));
}
}
Discussion in the ATmosphere