AppState and Control logic questions

Hello, I have read the jme3 tutorial section about AppStates and Controls, but I just wanted to ask a few questions to clear up if I am using them in best practice. I’ve studied Java for a few months now and I have a good understanding of the basics, but I’ve only fiddled around with small business-like applications with the Java Swing/FX and a handful of threads. I’m interested in game development as a hobby, and I understand a good chunk in theory, but now there are things like optimization, garbage collection and other topics that I didn’t “need” to know when I made those small business applications. So I just want to check if I got it right.

For example, I’m working on a 3D first person game, let’s say I have a scene, with a room that has a door which leads to a hallway. I want to make a control that handles opening doors in that scene, I would write something like this:

[java]
public class DoorControl extends AbstractControl {

//Fields that store information about collision, "You opened a door" BitmapText that will display using the guiNode, door opening audio etc.
private CollisionResults results;
private Ray ray;
...

@Override
protected void controlUpdate(float tpf) {
    //Ray casting code
}

public DoorControl(SimpleApplication app) {
    //Constructor to initialize the fields
}

private ActionListener mouseClickListener = new ActionListener() {
    //Code that handles door movement in the 3D scene
};

}
[/java]

Now my questions regarding this simple example and in general are:

  1. If I recall correctly, when you are finished using an AppState, you detach it and then the cleanup method is called in which I detach nodes etc., I noticed there isn’t a cleanup method in the AbstractControl class, what happens to the field values/objects in the control when I detach the control from a node? Does the garbage collector get them? I should manually clean them up?

  2. When I unregister all my listeners, detach all my nodes etc., in the AppState, do I need to assign null values to the fields to tell the GC that they are ready for garbage collection or does the cleanup method do that automatically?

Example, I’m currently doing this:
[java]
@Override
public void cleanup() {
super.cleanup();
this.app.getRootNode().detachChild(someNode);
gunfireSound = null;
worldNode = null;

}
[/java]

I’m worried about memory consumption, in other words, memory leaks. I’m sorry if this is a stupid question, but the books I’ve read didn’t give much advice regarding the GC process.

  1. Let’s say I have a AudioNode field in the DoorControl that plays a 0.5MB wav file, if I have 4 instances of DoorControl assigned to 4 different spatials in the scene, does that mean there are 4 instances of the audio file loaded in the memory, consuming 2MB in total? Should I create an AppState containing only 1 instance of all audio/dialog/text files and then play them from the individual controls?

  2. Is it good practice to use a lot of fields, if any, in the custom Control classes that manage behaviour in my game?

  3. What is the best way to communicated between AppStates and Controls? I know how to communicate between the AppStates using the state manager:
    [java]
    this.app.getStateManager().getState(MyAppState.class).doSomeCustomStuffInThisState();
    [/java]
    But how does one communicate between an AppState/Control or Control/Control? Should I pass the app object through he Control constructor like in the example above? Or should I use the getControl() accessor to get Control objects from spatials and then access the fields using custom methods in the controls I’m accessing?

Even a short answer will suffice, just a pointer to avoid the pitfalls. As you see, I think I understand the logic behind using AppState and Controls, but I’m feeling as I’m using them incorrectly which will bite me back when I will reach a high in-game model count, a lot of audio etc., I fear that I will get memory leaks and OutOfMemoryExceptions, and that I’m leaving a lot of objects in the memory that aren’t being used anymore which should be properly cleaned up.

Thank you for your time, and I hope I didn’t embarrass myself with these questions. :facepalm:

Just a quick answer before I’ve read it all… but the GC will handle a lot of what you worry about. You don’t generally need to null out fields if the parent object is also going away.

AppState has a cleanup method because it generally does stuff in init that it will have to undo in order to be removed properly (removing things from the scene, for example). Controls don’t usually need this kind of life-cycle.

If a control really needs access to the app then you can provide it on the constructor or something… but I think this is extremely rare and might be a sign of a design issue. Specific examples would be needed to better comment.

If a control needs a specific app state then you can pass that to the constructor or something… this is more likely.

1 Like
@pspeed said: If a control really needs access to the app then you can provide it on the constructor or something... but I think this is extremely rare and might be a sign of a design issue. Specific examples would be needed to better comment.

First of all thanks for taking the time to help me pspeed.

As seen in the example above, in the Controls constructor, I passed the app because I need the input manager to add the mappings and the listener. I also need the guiNode which I can easily access with the app reference variable as well. You mentioned that this control design might be flawed. I combed the jme3 custom controls section for more complex control design, but they only show simple examples.

I was thinking of finding some open source code of a game with good practice control design, but I fear I might run into examples that might not be far off from where I am going, which would be a pitfall I guess.

In short, understanding how each component works separately isn’t that problematic for me, the problem is to understand how they work in unison. In other words, doing the work of a construction worker is not so hard, the architect part is giving me a headache, because if I don’t know how to properly design a building, no matter how good I lay the bricks the house is going to come crumbling down. :explode:

If you could point me to a well designed game or some more complex best practice examples regarding controls or game design in jme3 in general, that would help me immensely.

@calmkiwi said: First of all thanks for taking the time to help me pspeed.

As seen in the example above, in the Controls constructor, I passed the app because I need the input manager to add the mappings and the listener. I also need the guiNode which I can easily access with the app reference variable as well. You mentioned that this control design might be flawed. I combed the jme3 custom controls section for more complex control design, but they only show simple examples.

See, already “I need the input manager to add the mappings and the listener” sounds really scary. What happens when you have more than one door? They’ll all be registering tons of listeners.

Input is better handled by an app state since input is kind of a global thing. How you handle that input could be done in a control.

@calmkiwi said: I was thinking of finding some open source code of a game with good practice control design, but I fear I might run into examples that might not be far off from where I am going, which would be a pitfall I guess.

In short, understanding how each component works separately isn’t that problematic for me, the problem is to understand how they work in unison. In other words, doing the work of a construction worker is not so hard, the architect part is giving me a headache, because if I don’t know how to properly design a building, no matter how good I lay the bricks the house is going to come crumbling down. :explode:

If you could point me to a well designed game or some more complex best practice examples regarding controls or game design in jme3 in general, that would help me immensely.

I’m sure there are some but I don’t know them off the top of my head. My example games were ES examples and so might be confusing for someone not using an ES. (Asteroid Panic and Monkey Trap)

1 Like

the order of execution in the game loop is

action/analog/raw input listeners
app states
controls
repeat

what goes in each part is really up to you, youre entire game could work with just controls or just app states, or even just input listeners (though thatd be tough). all that any of these things are is just code that gets executed on the game loop. the choice to break up your code in to app states or controls is almost purely an organizational one and a personal preference.

@pspeed said: See, already "I need the input manager to add the mappings and the listener" sounds really scary. What happens when you have more than one door? They'll all be registering tons of listeners.

Input is better handled by an app state since input is kind of a global thing. How you handle that input could be done in a control.

Aha, now I’m starting to get the big picture.

Two more questions and I’ll be on my way (I hope :facepalm: ):

1.) You said that “If a control needs a specific app state then you can pass that to the constructor or something… this is more likely.”, so does that mean that I should keep all my data like audio, text etc., defined inside an AppState and then access that data from the Controls with the help of custom methods that are located in said AppState? In other words, the Control only handles the data FROM an AppState, but never contains any data within itself? For example a metaphor, consider water to be data in an AppState, the Control would be a water filter that only changes the water’s properties but doesn’t contain nor store water in itself?

2.) You mentioned that “Controls don’t usually need this kind of life-cycle.”, if I create an AudioNode field that contains a sound effect, inside an Control, what happens to that audio data when I detach the Control from the Spatial? Does the AudioNode object get wiped from the memory?

@pspeed said: I'm sure there are some but I don't know them off the top of my head. My example games were ES examples and so might be confusing for someone not using an ES. (Asteroid Panic and Monkey Trap)
ES, as in Entity system? Oh man, I ask for a sword and you hand me an atomic bomb ;-P . Aren't Entity System used for more complex games like MMORPGs? I don't think I'm that experienced in programming to tackle ES, I'm just trying to make a simple first person adventure game. Thanks for the suggestions though.

I’ll try to find some similar examples on the forums.

Anyway, thanks for the help so far, you helped me clear some things up :slight_smile:

@calmkiwi said: Aha, now I'm starting to get the big picture.

Two more questions and I’ll be on my way (I hope :facepalm: ):

1.) You said that “If a control needs a specific app state then you can pass that to the constructor or something… this is more likely.”, so does that mean that I should keep all my data like audio, text etc., defined inside an AppState and then access that data from the Controls with the help of custom methods that are located in said AppState? In other words, the Control only handles the data FROM an AppState, but never contains any data within itself? For example a metaphor, consider water to be data in an AppState, the Control would be a water filter that only changes the water’s properties but doesn’t contain nor store water in itself?

I’d need a real example and not an abstract one. You might pass an app state to a control if it needed access to global resources that would be managed by that app state. In general, there is likely an even better abstraction. For example, passing the sound to the control instead of the sound manager. Or passing the entity to the control instead of the whole entity system.

@calmkiwi said: 2.) You mentioned that "Controls don’t usually need this kind of life-cycle.", if I create an AudioNode field that contains a sound effect, inside an Control, what happens to that audio data when I detach the Control from the Spatial? Does the AudioNode object get wiped from the memory?

If nothing is referring to the control anymore then it will get garbage collected. If nothing is referring to the AudioNode anymore then it will get garbage collected.

@calmkiwi said:

ES, as in Entity system? Oh man, I ask for a sword and you hand me an atomic bomb :stuck_out_tongue_winking_eye: . Aren’t Entity System used for more complex games like MMORPGs? I don’t think I’m that experienced in programming to tackle ES, I’m just trying to make a simple first person adventure game. Thanks for the suggestions though.

Yeah, as I said. I pretty much use an ES for everything now but it does have a significant learning curve and brain warping required. “Asteroid Panic”, for example, is just a basic Asteroids clone that uses an ES.

Best to wait on that, I guess. :slight_smile:

@pspeed said: If nothing is referring to the control anymore then it will get garbage collected. If nothing is referring to the AudioNode anymore then it will get garbage collected.

Aha, then if I had something like:

[java]
public class SimpleControl extends AbstractControl {

private AudioNode sound = new AudioNode(assetManager(), "Sounds/sound.ogg");

//Other code
...

}
[/java]

And inside an AppState I have something like:

[java]
private SimpleControl control = new SimpleControl();

public void initialize(AppStateManager stateManager, Application app) {
    someNode.addControl(control);

    //Some code
    ...

    someNode.removeControl(control);

    control = null;

}

[/java]

Now I’m not referring to the SimpleControl object anymore by using null, then does the sound field inside the control still refer to the AudioNode object or does it too get garbage collected, or will this cause a memory leak?

I’ve understood everything else so far, this is the last thing that bugs me now.

the AudioNode within the SimpleControl will be GCed presuming its not referenced anywhere else. if you reference the audio node in other controls, or if its still in the scenegraph it will not be GCed.

but yes, java is capable to know if youre still maintaining a reference to something, and it understandands that an object can contain other references etc etc and accounts for that when it does GC.