[Solved] Refactoring a growing application

i have a design question. i’m trying to move more stuff into AppStates . but i’m hitting up against the fact that certain core objects ( e.g. Camera, RootNode, GuiNode, etc.) are typically held by the Application object. is there a design pattern (or non-obvious mechanic) that allows to decouple these things from the main Application in a way that does not run afoul of the asynchronous updates and inter-object dependencies that arise from the scene graph/physics/lighting/camera/etc.

basically, my app is growing and i’m trying to ascertain what patterns make sense to modularize bits and pieces. some things are obvious (login screen workflow is an AppState, general play is an AppState, etc.) but i’m now wondering if there is a way to move more things (zone initialization, player construction, message handling, etc.) out of the Main App and into AppStates, but there are some coupling points that it is not clear how to decouple them appropriately that does not introduce “wonky code”

Maybe some of these examples will give you ideas:

sim-eth-basic is a networked space “game” that uses regular game objects.
sim-eth-es is the version that uses an entity component system.

These show a way to organize an application into app states. I personally leave very little code in the main SimpleApplication subclass but note that global things like camera, main viewport, etc. are already available to all app states anyway.

…and hopefully you are extending BaseAppState for your app states or you are doing it on “hard mode”.

3 Likes

Additioannly getState() is implemented in a way that allows you to use an interface/abstract AppState and have different implementations, for testing/development shortcuts/mocks.

1 Like

Just encapsulate it with SimpleApplication in your BaseAppStates

protected void initialize(Application app) {
	((SimpleApplication)app).getRootNode();
	((SimpleApplication)app).getCamera();
	((SimpleApplication)app).getFlyByCamera();
	((SimpleApplication)app).getGuiNode();

yeah, i saw that discussed in the wiki docs, trapping the references in the AppState when the App is passed in.

i was trying to figure out a way to reduce that coupling, but i guess, if i have to, i have to.

thanks for the input.

so, adding additional insight for anyone who strolls through this posting.

i stumbled over AppStateManager.getState( Class<> ) and this was quite the game changer for me. it allows me to lookup an attached AppState without having to store hard references or pass them around the object hierarchy (blech). this allows me to decouple A LOT of capabilities without having to store cross references during my refactoring.

BIG WIN!

the only stumbling point i can see is if i end up with multiple instances of a specific Type of AppState, but i have not hit that kind of obstacle yet.

YMMV.
caveat emptor.
void where prohibited by law.

2 Likes

If your app states extend BaseAppState then you don’t even need to go that far…

BaseAppState has a getState(Class) method on it that allows easy collaboration between app states.

It also properly implements the app state lifecycle in a way that is easy to hook into… this lifecycle is really tricky to implement correctly if you implement AppState directly.

1 Like

I am currently into this same problem. So, I would generally say out my approach (which was partly wrong and corrected because of this great community review!).

First of all, any approach whatever it’s (ECS or low-level Automatas) will require you to build a binding API to the AppStateManager typically through building a BaseAppState that integrates the API interfaces into jMonkeyEngine…

Anyway, I’ve built an ECS-based API with some customized behavior, if-necessary including ECS Modules and ECS Data-flow attached patterns, these patterns ensure data and behavior decoupling while keeping them integrable and cohesive, at the same time preserving the classic ECS.

You will find an example that converts TestJaime to use an ECS-based solution… Among an initial specification.

Another API is Automata4j, a classic Finite-state automata library for Java applications that supports states aggregation through the cascading interface…

Furthermore, I am building up some software philosophy in integrating an additional API that utilizes the state machines as Systems of the game for ECS-based games to achieve a standard pattern for game development…

Another framework I am still building is Jector, a dependency injection framework for concurrency and multi-threading management with an API for jMonkeyEngine.

It’s presumed that my apps will utilize a superimposition of ECS with juxtaposition of these supplementary patterns to achieve the best outcomes… However, full integration is not ready yet.

They are available currently at maven-central as pre-releases.

2 Likes