Questions about AppState data flow

Hello,

I am working on organizing my game into app states. I have them working but don’t feel like I am doing it the right way. I followed the AppState wiki. In the examples I have found they initialize all of the AppStates in the Main SimpleApplication class. The examples also seem to update the AppStates from within the SimpleApplication as well (By way of Key Listeners etc).

Obviously we usually want to update states based on other events such as gui or game events.

Where I am confused is when I want to go to the next state after the one attached in Main. It seems odd to have every AppState reference Main in order to attach and detach states. So what I have put together is when I want to go to the next AppState I create and attach the next state in the current state. Though I think this way is wrong as well, it could easily become hard to manage what AppStates exist.

Is there a best practice method for handling the states? Should Main control all of the AppStates? Or am I missing something completely?

Thanks.

I can’t answer all of your questions, however, I would think that centralizing your AppState flow would be far better than having one state create/load the next. This way, if something needs to change in the flow/something goes wrong with the flow, all of your changes are handled in a single place.

EDIT: This doesn’t need to be done in your main class (actually, overall, this is a bad idea as it seems to be a dumping ground in most peoples cases)… create your own state manager (not the same as SimpleApplication’s StateManager… one that does nothing more than control your applications flow by managing states).

In my opinion, most app states should be as self contained as possible. The should register their key listeners, add things to the scene, etc. when initialized and enabled… and they should undo all of those things when disabled/cleaned up.

(If you borrow or extend Lemur’s BaseAppState then you can simply override enable() and disable() to make life easier as far as coordinating enabled+initialized and disabled+cleanup.)

That being said, there will be some app states that are more game specific than others and may coordinate the adding and removal of other states. Whether you can get away with something this simple or not is a matter of taste and/or number of app states.

In Mythruna, I had a lot of states that needed to be enabled and disabled in concert but there was no clean way to tie them all together… and in most cases it didn’t make sense. I ended up creating a central “game mode” class that can be listened to for changes… ie: states can be automatically enabled or disabled based on the current mode. So, for example, I could tie the camera state to the “InGame” mode and then when I pop-up an inventory screen I go to the “Inventory” mode and the camera state is automatically disabled. States can be linked to more than one mode so things like the chat console state can be hooked to almost all of the modes.

Whether or not you need that extra layer depends on how many app states you have. The Zay-ES example, Monkey Trap, has a bunch of states but I coordinate it in the traditional way. There is a MainMenuState that sets up and launches the GamePlayState which itself manages many child states… adding them on enable() and removing them on disable().

The source code for all of this is available online if you want to look. I can’t provide the links at the moment because of time constraints but you can search for Lemur and/or Zay-ES or Monkey Trap on the forum to find them I guess.

1 Like

What works well for me is to create and attach all the app states in simpleInitApp() and never detach them: instead, simply enable/disable them as necessary. In this regard, it’s helpful if your app states can be enabled/disabled prior to initialization, for which @pspeed’s BaseAppState is a good model.

Thanks. I went ahead and centralized the appState flow. It seems to be working well, and is easier to keep my head wrapped around what goes where. I can see the upsides and downsides to both ways. I would imagine for a larger project it would be better to take pspeeds more hybrid approach.

Now I am having an issue with Nifty Gui. Might belong in new thread but I did not want to create another thread, I have already received so much great help. I have my gui laid out and it changes from one screen to to another and does gui specific stuff(such as change text in a text area, or populate a list). For the most part it is all created in Java, with little use of XML. However I cannot for the life of me figure out how to get reference to outside classes from within my niftyGui controller.

At first a lot of my Nifty initialization was done using static methods. So I changed and run into a few errors I do not understand. If I try to reference an object outside of the say ListPaneController I get a methodInvocation exception or a could not load class exception.

I searched the net and found one similar thread here but it did not seem to answer my question to a workable extent. Though this seems like a common thing someone would want to do with a gui.

For example I need to call some of my networking class methods based on gui events such as the Connect Button. If anyone can point me to literature on that subject I would be very thankful.

Why don’t you want to create a new thread?

Have you tried writing a constructor for your screen controller class and passing your outside objects to the constructor? (If you did, you constructor could save references to these objects in fields.)

Trying not to litter the forums with my elementary questions.

So I try to pass it into the constructor. Right now I have closely followed Voids nifty tutorials/examples in creating my gui. Like his example I have a panel in the center of the screen. I add a Controller to that pane to handle gui events.

In my gui AppState init: [java]LobbyPane pane = new LobbyPane();
pane.register(nifty);
GuiBuilder builder = new GuiBuilder();
builder.createScreen(nifty);[/java]
The LobbyPane defines the layout of the panel. GuiBuilder lays out the rest of the gui.

The LobbyPane code throws Warning class [lobby.LobbyController] could not be instantiated
[java]
public void register(final Nifty nifty) {
new ControlDefinitionBuilder(NAME) {{
controller(new LobbyController((Application)app)); //This Does not work!
control(new ControlBuilder(DialogPanelControlDefinition.NAME) {{
// the list box panel at the top
panel(new PanelBuilder() {{
childLayoutHorizontal();
control(builders.createLabel(“Players:”));
control(new ListBoxBuilder(“listBox”) {{
displayItems(4);
selectionModeSingle();
showVerticalScrollbar();
hideHorizontalScrollbar();
width("*");
}});
}});
etc etc…[/java]

And the Controller
[java]
public LobbyController(Application app) {
this.app = (Main) app;
}
//Other methods

@NiftyEventSubscriber(id = “connectButton”)
public void onConnectClicked(final String id, final ButtonClickedEvent event) {
if (addTextField.getRealText().length() == 0) {
return;
}
listBox.addItem(new JustAnExampleModelClass(addTextField.getRealText()));
listBox.showItemByIndex(listBox.itemCount() - 1);
app.gameUpdater.toString(); //This does not work either, throws Method invocation exception
}

[/java]

@GunnerMan said: Trying not to litter the forums with my elementary questions.

It’s the same forum, whether you create a new thread or not.

If you consider your questions unworthy of a thread, why should anyone else consider them worthy of a reply?