I just read the docs on the jME3 Threading Model and see the following two sentences:
“If you make changes only in Control.update(), AppState.update(), or SimpleApplication.simpleUpdate(), this will happen automatically. However, if you pass work to another thread, you may need to pass results back to the main jME3 thread so that scene graph changes can take place there.”
I’m just looking to make sure I understand the threading model correctly here:
It seems as though there is a “main thread” where the app’s main method is called
There is a separate thread where the SimpleApplication#simpleUpdate loop is run (what’s this thread called?). This is also where the scenegraph runs out of.
Each Custom Control instance is placed in its own thread, and its update method is continuously called inside that control’s dedicated thread
An isolated App State thread is also maintained
Are my assumptions correct or am I way off base? Am I missing any other important threads? Are there “client-only” and “server-only” threads that I should be aware of?
Way off There’s only one jme thread, and only one update loop which traverses the whole scenegraph and calls all Controls. The app states are also called in this loop.
To make changes to the scenegraph you have to inject your code into this jme thread (only if you’re not already there, which probably is the case if you do your stuff inside update() methods).
Just for clarity’s sake though: I’m still a wee bit fuzzy on the relationship of the scenegraph to all of these update methods. In these update methods, specific spatials can be transformed (rotated, scaled, relocated, etc). Is the scenegraph mutated lazily (perhaps one time, after all of these update methods run), or is the scenegraph mutated on-the-fly, as each transformation is executed?
Changes to objects are applied immediately. If multiple Controls work on the same Spatial, you could use relative transformations (Spatial.move()), so order shoudln’t be a problem.
Or rather… the interesing changes happen immediately. There are certain updates that happen once per cycle, lazily.
update geometric state, bounding volume update, stuff like this. But I think in general you don’t have to care about that.
It is perhaps a good idea to have only one to one control.
Remember that the scene graph defines the View. ie it is not the model (MVC pattern). That is your game state shouldn’t be clustered and tied into the scene graph (ie the view).
MVC stands for Model View Controller design pattern. You really want to look that up if you don’t know it already. If you only ever learn one design pattern learn this one.
Thanks everyone! And thanks for the example projects @pspeed - looking at those two projects, I have several questions about your project structure and code conventions. Is it OK to ask those questions here, or do you want me to create GitHub issues, or ask them somewhere else? (Or do you not want me to ask any questions about them at all!?)
So looking at your SimEthereal code base @pspeed, you make extensive use of app states.
I read the doc on App States, and I think I’m not quite seeing the “forest through the trees” here. It seems like App States allows you to turn your game into a state machine, where each state is perhaps a different/distinct scenegraph with its own/distinct game objects. And that when you transition to a different state, essentially the scenegraph and game objects associated with that state all get paused, and the new state is initialized/resumed.
Is that (more or less) correct, or am I way off base? Thanks again!
It’s better said that AppStates are a way of “extending” the functionality of application through composition instead of inheritance. And that “extending” can be temporary.
Generally, one should always prefer composition over inheritance.
Edit: and if you write your AppStates properly then many of them can be reused across many games.
Hmmmm, are you maybe saying that App States are meant to “extend” the SimpleApplication class? Any chance you can give a concrete example of a use case for an App State (the description in the jME3 docs, to me, is a wee bit vague/generic)?
For example, let’s take your SkyState, what exactly is that used for? Why make it an AppState? A concrete example like that will make all the light bulbs go off (or explode). Thanks!
My app states are concrete examples. The sky state adds a sky to the scene. Remove the app state again (or disable it) and the sky goes away. I can use that sky state with any application where I want stars in the background. (And it would be easy enough to modify to work with any images.)
The main menu state is active while the main menu is open. It handles the input for the main menu.
I mean, the names of these states are pretty self-explanatory I thought and the code for them is not complicated. AppStates have a specific lifecycle. You override/implement these methods to do things at those times. That lifecycle is covered in the AppState and AppStateManager javadocs.
Ahh so why did you choose an AppState to manage your sky spatial, and not a Custom Control (why does SkyState extend BaseAppState instead of AbstractControl)? Meaning, what’s the difference between App States and Custom Controls, and under what scenarios do you recommend using either of them?
I ask because based on my understanding of Custom Controls (per the docs), a Custom Control’s job is to manage a spatial, so I’m wondering why you’re managing your “sky” spatial via App State instead? Not being critical at all here, just trying to learn from you so I can implement similar designs in my stuff!
A control manages a spatial, that is correct. An app state instead can go way further: it can modify the whole scene graph. So in the example of the sky you would need an app state because you need to attach the sky spatial to the scene. Or phrased differently: a control can’t attach itself to the scene.
I see it that way:
App State: modify the scene graph. The important action happens when the state is attached or detached.
Control: per-frame modifications to a specific spatial, independent of where it is in the scene graph.
Some more examples from one of my projects:
flickering light → control that changes the light position + radius with some noise every frame
wireframes → an app state that adds/removes a processor forcing the wireframe material when it is attached/detached