How to destroy an appstate object?

Hi,
my application starts and stops the game as per the nifty gui buttons. I have made appstates such as RunningGame, MainMenuAppState etc. When I detach the Running game appstate it doesnt automatically destroy that appstate and all the previous objects remain attached to rootNode. is there a way to completely destroy previous appstates so that I can start a clean and new instance of those appstates?? I’m also concerned about my assetmanager objects. How could I be sure that I have removed all objects attached to simpleapplication object and freed my memory??

How about if I run all my nifty thing in one simpleapplication extended appstate and run my game in another simpleapplication appstate and then I can do runnGame.stop() to destroy all the assets that it contains.

Implement the cleanup method of your AppState and remove what it added in it.

Your app state needs to clean itself up in cleanup(). There is no magic. Your app state adds stuff so your app state must remove it again. JME has no idea what it’s done and so couldn’t possibly do this automatically.

But there isn’t any tutorial explaining how to do this effectively??
Is detachAllChildren() going to remove all my objects from rootNode??
How should I remove instances of nodes like shootables etc??

If I have created an object in one of my appstates (global private), how should I destroy it??
Will detaching an appstate, destroy that object as well??

I have implemented the cleanup() function to remove allChildren of rootNode and guiNode?
But when I attach a new appstate using statemanager.attachState(new RunningGameAppState()) it loads a white colored scene. I have no idea whats happening?

Your code looks fine from here.

ok
[java] package threeD.dragdrop;

import other.Reminder;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.light.AmbientLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;

/**

  • This state handles the configuration of the running game. Setsup the game

  • scenegraph

  • @author simar
    */
    public class RunningGameAppState extends AbstractAppState {

    private SimpleApplication app;
    private Node modelRoot;
    private Node allAttached;
    private Node shootables;

    private void setUpSceneGraph() {
    modelRoot = new Node(“modelRoot”);
    allAttached = new Node(“allAttached”);
    shootables = new Node(“shootables”);

     allAttached.attachChild(shootables);
     modelRoot.attachChild(allAttached);
     app.getRootNode().attachChild(modelRoot);
    

    }

    private void setUpCamera() {
    //(2.0637982, 16.589993, 31.493382) (2.9092522, -0.03732109, -11.785362)
    Vector3f camloc = new Vector3f(2.063f, 16.58f, 31.49f);
    Vector3f lookAt = new Vector3f(2.90f, -0.037f, -11.78f);

     app.getCamera().setLocation(camloc);
     //cam.lookAtDirection(lookAt,cam.getUp());
    
     //app.getStateManager().getFlyByCamera().setRotationSpeed(4);
     //app.getFlyByCamera().setZoomSpeed(10);
     //app.getFlyByCamera().setMoveSpeed(25);
    

    }

    private void setUpLight() {
    // We add light so we see the scene
    // Use minimal lightening as part of android specific optimisations

     AmbientLight al = new AmbientLight();
     al.setColor(ColorRGBA.White.mult(1.3f));
     app.getRootNode().addLight(al);
    
     //DirectionalLight dl = new DirectionalLight();
     //dl.setColor(ColorRGBA.White);
     //dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
     //app.getRootNode().addLight(dl);
    

    }

    public RunningGameAppState() {
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (SimpleApplication) app;

     //app.getStateManager().attach(new StatsAppState());
     //app.getStateManager().attach(new FlyCamAppState());
     //app.getStateManager().attach(new DebugKeysAppState());
    
     setEnabled(true);
    
     //attach some spacials
     //this.app.getRootNode().attachChild(getBox());   
    

    }

    @Override
    public void cleanup() {
    super.cleanup();
    shootables.detachAllChildren();
    allAttached.detachAllChildren();
    app.getRootNode().detachAllChildren();
    app.getGuiNode().detachAllChildren();
    //app.getAssetManager().

    }

    @Override
    public void setEnabled(boolean enabled) {
    // Pause and unpause
    super.setEnabled(enabled);
    if (enabled) {
    //Settings
    setUpCamera();
    setUpLight();
    setUpSceneGraph();
    initCrossHairs();
    initHUD();
    System.out.println(“Started”);

         //app.getStateManager().attach(new StatsAppState());
         //app.getStateManager().attach(new FlyCamAppState());
         //app.getStateManager().attach(new DebugKeysAppState());
     } else {
         //take away everything that is not needed while this state is paused
     }
    

    }

    @Override
    public void update(float tpf) {
    //do the following while game is running
    //this.app.getRootNode().getChild(“Box”).scale(tpf*2);

     // Update HUD
    

    }

    /**

    • A centred plus sign to help the player aim.
      */
      private void initCrossHairs() {
      AppSettings settings = new AppSettings(true);
      BitmapFont guiFont;

      app.setDisplayStatView(false);
      guiFont = app.getAssetManager().loadFont(“Interface/Fonts/Default.fnt”);
      BitmapText ch = new BitmapText(guiFont, false);
      ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
      ch.setText("+"); // crosshairs
      ch.setLocalTranslation( // center
      settings.getWidth() / 2 - ch.getLineWidth() / 2, settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
      app.getGuiNode().attachChild(ch);
      }

    private void initHUD() {
    BitmapFont guiFont = app.getAssetManager().loadFont(“Interface/Fonts/Default.fnt”);
    BitmapText hudText = new BitmapText(guiFont, false);
    hudText.setSize(guiFont.getCharSet().getRenderedSize()); // font size
    hudText.setColor(ColorRGBA.Blue); // font color
    hudText.setText("Time Left: "); // the text
    hudText.setLocalTranslation(0,hudText.getHeight(), 1); // position
    app.getGuiNode().attachChild(hudText);

     Reminder timer =  new Reminder(hudText,30);
     timer.setUpdateInterval(1);
    

    }

}

[/java]

My question is what else are the possibilities about removing what all it added??

Another appstate
[java]
package threeD.dragdrop;

import threeD.modelFactories.xmlParser;
import threeD.modelFactories.ModelFactory;
import threeD.entityComponents.EntityDataState;
import threeD.entityComponents.MagnetSubMesh;
import threeD.entityComponents.MagnetSubMeshParent;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.bounding.BoundingBox;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.simsilica.es.Entity;
import com.simsilica.es.EntityData;
import com.simsilica.es.EntityId;
import com.simsilica.es.EntitySet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**

  • This manages the interface between entities and models. It creates respective
  • entity for each model.
  • @author simar
    */

public class ModelEntityState extends AbstractAppState {
private SimpleApplication app;

//static Logger log = LoggerFactory.getLogger( ModelState.class );

private EntityData ed;
private Map<EntityId, Spatial> models = new HashMap<EntityId, Spatial>();
private ModelFactory factory;
private xmlParser xPar;
private static Logger log = Logger.getLogger(ModelEntityState.class.getName());
private static String delims = "[,]+";

private float maxSpaX;
private float maxSpaZ;
private Node shootables;


public ModelEntityState (ModelFactory factory) {
    this.factory  = factory;
    PropertyConfigurator.configure("log4j.xml");
    

}

public Spatial getSpatial( EntityId entity ) {
    return models.get(entity);
}

public SimpleApplication getApplication() {
    return this.app;
}

protected Spatial createSpatial( EntityId e ) {
    return factory.createModel(e);
}

private void addModels() {
    // Create an entity
    EntityId entityid = ed.createEntity();
    Spatial spa;
    
    while ((spa = createSpatial(entityid)) != null) {
        // Create entity map
        models.put(entityid, spa);
        
        // Attach components

        attachComponents((String) spa.getUserData("name"), entityid);
        
        // Create new id, one may id will be extra...
        entityid = ed.createEntity();
    }
}

private void addScene() {
    EntityId entityid = ed.createEntity();
    Spatial spa = factory.createScene(entityid);
    models.put(entityid, spa);
    
    attachComponents((String) spa.getUserData("name"), entityid);
}

private void addSubMeshModels() {
    Spatial s2;
    EntitySet eSet = ed.getEntities(MagnetSubMeshParent.class);
    //eSet.applyChanges();
    Iterator<Entity> iterator = eSet.iterator();
    System.out.println(eSet.size());
    while(iterator.hasNext()) {
        Entity entity = iterator.next();
        MagnetSubMeshParent subMeshParent = ed.getComponent(entity.getId(), MagnetSubMeshParent.class);
        Node s = (Node)getSpatial(entity.getId());
        
        ArrayList subMesh = subMeshParent.getSubMesh();
        ArrayList orientation = subMeshParent.getOrientation();
        
        //Iterator<String> it = subMesh.iterator();
        for (int i=0; i <subMesh.size();i++) {
            if ((s2 = s.getChild((String)subMesh.get(i)))!= null) {
                // Add entities
                EntityId entityid = ed.createEntity();
                models.put(entityid, s2);
                s2.setUserData("EntityId", entityid.getId());
                s2.setUserData("name", s2.getName());

                // Add Component
                ed.setComponent(entityid, new MagnetSubMesh(maxSpaX, s2,(Integer)orientation.get(i)));
                
                // Log
                log.info("SubMeshMAGNET added: " +s2.getName() + " " + orientation.get(i));                     
            }    
        }
    }
}

private void setMaxSizeSpatials() {
    float size;
    
    for (int i = 0; i < shootables.getChildren().size(); i++) {

        // Bug - 4/9/13
        // this will generate a null pointer exception if spacial is empty. should handle it
        // To reproduce the bug, export the mesh without selecting anything in google sketchup
        size = ((BoundingBox) shootables.getChildren().get(i).getWorldBound()).getXExtent();
        if (maxSpaX < size) {
            maxSpaX = size;
        }

        //System.out.println ( "\n\n Name= " + shootables.getChildren().get(i).getName());

        size = ((BoundingBox) shootables.getChildren().get(i).getWorldBound()).getZExtent();
        if (maxSpaZ < size) {
            maxSpaZ = size;
        }
    }

    // getXEntent will return extend only on one side of center.
    // This is somewhat similar to box(1,1,1) generating (2,2,2) thing...
    maxSpaX = maxSpaX * 2;
    maxSpaZ = maxSpaZ * 2;
    log.debug("MAX Size of Spatial: " + maxSpaX + " " + maxSpaZ);
    //app.getStateManager().getState(Tester.class).envelopeBoxSubMesh(shot);

}

private void attachComponents(String s, EntityId e) {
    try {
        xPar.parse(s, e);
    }
    catch (Exception e1) {
        // Null pointer exception means that component is not found..
        System.out.println("\nError in XML parser: " + e1.toString());
        System.out.println("\nMost linkely cause is that you must check your XML as per code norms");
        
    }        
}

@Override
public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (SimpleApplication)app;
    
    factory.setState(this);

    // Grab the set of entities we are interested in
    ed = app.getStateManager().getState(EntityDataState.class).getEntityData();
    xPar = new xmlParser((SimpleApplication) app);
    shootables = (Node) ((Node) ((Node) (this.app.getRootNode().getChild("modelRoot"))).getChild("allAttached")).getChild("shootables");


    // Load the models and scene
    addModels();
    addScene();
    
    // Compute max size of spatials
    setMaxSizeSpatials();

    // Add MAGNETs to sub meshes
    addSubMeshModels();

    System.out.println("\n\n*********In Main.class: Ready to catch EVENT *********\n");
}

@Override
public void cleanup() {
    // Release the entity set we grabbed previously

    super.cleanup();        
}

@Override
public void setEnabled(boolean enabled) {
    // Pause and unpause
    super.setEnabled(enabled);
    if (enabled) {
        // init stuff that is in use while this state is running
        // this.app.getRootNode()
        System.out.println("Enabled");

        //addModels
        //System.out.println("\n hello there");
        //factory.createModel(null);
        
        
    } else {
        //take away everything that is not needed while this state is paused
    }
}

@Override
public void update(float tpf) {
    //do the following while game is running
    //this.app.getRootNode().getChild("Box").scale(tpf*2);
}

}

[/java]

This is how my scene look before and after when I reloads all my appstates…

This is how my scene look before and after when I reloads all my appstates…

Your cleanup() doesn’t cleanup everything that was setup. Like lights, for example.

when i write
rootNode.deattachAllChildren() doesnt it remove lights as well??

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/scene/Node.java#373

Was just being a bit lazy looking at source…
Thanks… Got it

I’ve got a question regarding the detachment of all children. Am I supposing right that I don’t have to remove any spatial - like geometries I’ve created - manually but only things like lights that aren’t actually spatials?

deatchAllChildren() detaches all of the children. If something is not a child then a different method has to be used to remove it. Lights are not children. Only spatials are children in this context.

Alright, that’s the answer I’ve been asking for, thank you. Makes sense.