java.lang.IllegalStateException: Scene graph is not properly updated for rendering

Man…

public class Main extends SimpleApplication {
...this is all of your code.  You would need to continue having 
this code.  This next part is a possible way to do it but not the 
complete solution because programming often requires 
extrapolating from incomplete information...

private float time = 0;
public void simpleUpdate( float tpf ) {
    time += tpf;
    if( time > 5 ) {
        time = 0;
        do the thing you want to do every 5 seconds. 
        Note this is not real code.  This line would be where you put 
        the code that you write that does the thing you need to do every 
        5 seconds.
    }
}

Or you could put it in an app state. Or you could put it in a control.

As said already, it depends on what you actually need to do.

Personally, I never put any actual real code in my main class because that’s a recipe for a 9,357,453,621 line class.

But if you want the simplest example possible then that’s it.

If you still don’t understand then please be more specific about WHAT PART you don’t understand.

I understand that code has to be modularized. for a moment I am just trying to verify tile mapping is works as I am expecting.
I tried below code. it works fine. but not sure how good this approach is. It still executes addNeighbours in separate thread but instead of attaching new node to root, it adds to queue. the queue will read by jme thread and can be attach to root in simpleUpdate.

private Queue<Tile> queue = new ConcurrentLinkedQueue<>();
	
	private void addNeighbours(Point position) {
		Map<Integer, Point> openPositions = grid.findOpenPositions(position);
		List<Tile> tmp = new LinkedList<>();
		for (Map.Entry<Integer, Point> positions : openPositions.entrySet()) {
			int side = positions.getKey();
			if (!isUnderGrid(side, positions.getValue())) {
				continue;
			}
			Map<Integer, Tile> neighbours = grid.findNeighbours(positions.getValue());
			Set<Tile> connections = new HashSet<>(4);
			neighbours.forEach((oppositSide, _tile) -> {
				if (connections.isEmpty()) {
					connections.addAll(_tile.getConnections(_tile.getOppositIndex(oppositSide)));
				} else {
					connections.retainAll(_tile.getConnections(_tile.getOppositIndex(oppositSide)));
				}
			});

			if (!connections.isEmpty()) {
				Tile n = new Tile(connections.toArray(new Tile[connections.size()])[dice.nextInt(connections.size())]);
				n.getPosition().setLocation(positions.getValue());
				grid.add(n);
				loadNode(n);
				tmp.add(n);
				queue.add(n);
			}
		}

		tmp.forEach((t) -> addNeighbours(t.getPosition()));
	}

@Override
	public void simpleUpdate(float tpf) {
		stopTime += tpf;
		if (stopTime > 0.250f) {
			stopTime = 0;
			Tile tile = queue.poll();
			if (tile != null) {
				enqueue(() -> {
					transformNode(tile);
					GEOM_NODE.attachChild(tile.getNode());
				});
			}
		}
		
		/*
		 * texts.forEach((text)->{ Quaternion q = new Quaternion();
		 * q.lookAt(cam.getLocation(),cam.getUp()); text.setLocalRotation(q); });
		 */
	}

You can modify the scene graph from the update thread. You can modify the scene graph from simpleUpdate(), AppState.update(), control.update(), etc… Updating. On the update thread. You can modify the scene graph.

You cannot ever in any circumstance of in any case whatsoever modify the attached scene graph from a SEPARATE thread.

So what you have is fine but you are re-enqueing unnecessarily.

enqueue() is just going to push that code to be run on the next frame’s update… but you were already update.

I feel like in this thread I need to be 100% clear to avoid vague questions that launch 20 more posts… so I will rewrite the code for you:

@Override
	public void simpleUpdate(float tpf) {
		stopTime += tpf;
		if (stopTime > 0.250f) {
			stopTime = 0;
			Tile tile = queue.poll();
			if (tile != null) {
				transformNode(tile);
				GEOM_NODE.attachChild(tile.getNode());
			}
		}
		
		/*
		 * texts.forEach((text)->{ Quaternion q = new Quaternion();
		 * q.lookAt(cam.getLocation(),cam.getUp()); text.setLocalRotation(q); });
		 */
	}

Thanks for your help.

1 Like