Hey monkeys
I’ve just got appStates working properly, switching back and forth between a menu state, and multiple game states. The problem I’m having is when detaching states the Audio is not being flushed.
I surmise that this is Jmonkey treating the Audionode as an external handle to the stream, and killing the appState is only destroying the handle, not the actual object. Is there something I’m not doing correctly with my state, and if not, is there a way to manually flush the audio?
here’s the code to see what’s going on:
package appStates;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppState;
import com.jme3.audio.AudioNode;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
/**
*
* @author Zachariah
*/
public class Main extends SimpleApplication {
private static AudioNode gun;
private static Menu menu;
private static LoadCube loadCube;
private static LoadCustom loadCustom;
private static LoadSphere loadSphere;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
inputManager.addMapping("Shoot",
new KeyTrigger(KeyInput.KEY_SPACE),
new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
menu = new Menu(this);
loadCube = new LoadCube(this);
loadSphere = new LoadSphere(this);
loadCustom = new LoadCustom(this);
stateManager.attach(menu);
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
initCrossHairs();
initAudio();
}
protected void initAudio() {
gun = new AudioNode(assetManager, "Sound/Effects/Gun.wav", false);
}
protected void initCrossHairs() {
setDisplayStatView(false);
guiFont = assetManager.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);
guiNode.attachChild(ch);
}
public static AppState getCube() {
return loadCube;
}
public static AppState getCustom() {
return loadCustom;
}
public static AppState getSphere() {
return loadSphere;
}
public static AppState getMenu() {
return menu;
}
public static void getAudio() {
gun.playInstance();
}
}
and the menu that gets loaded initially
package appStates;
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.collision.CollisionResults;
import com.jme3.input.controls.ActionListener;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
/**
*
* @author Zachariah
*/
public class Menu extends AbstractAppState {
protected Node rootNode;
private SimpleApplication app;
protected Geometry appOne;
protected Geometry appTwo;
protected Geometry appThree;
protected Geometry exit;
public Menu(SimpleApplication app) {
this.rootNode = app.getRootNode();
this.app = app;
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
rootNode.addLight(sun);
super.initialize(stateManager, app);
appOne = new Geometry("appOne", new Box(1, 1, 1));;
Material appOneMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
appOneMat.setColor("Color", ColorRGBA.Blue);
appOne.setMaterial(appOneMat);
appTwo = new Geometry("appTwo", new Box(1, 1, 1));
Material appTwoMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
appTwoMat.setColor("Color", ColorRGBA.Red);
appTwo.setMaterial(appTwoMat);
appThree = new Geometry("appThree", new Box(1, 1, 1));
Material appThreeMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
appThreeMat.setColor("Color", ColorRGBA.Green);
appThree.setMaterial(appThreeMat);
exit = new Geometry("exit", new Box(1, 1, 1));
Material exitMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
exitMat.setColor("Color", ColorRGBA.Gray);
exit.setMaterial(exitMat);
rootNode.attachChild(appOne);
appOne.setLocalTranslation(-3, 0, 0);
rootNode.attachChild(appTwo);
appTwo.setLocalTranslation(0, 0, 0);
rootNode.attachChild(appThree);
appThree.setLocalTranslation(3, 0, 0);
rootNode.attachChild(exit);
exit.setLocalTranslation(0, -3, 0);
initKeys();
}
@Override
public void cleanup() {
super.cleanup();
rootNode.detachAllChildren();
app.getInputManager().removeListener(actionListener);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
}
public void initKeys() {
app.getInputManager().addListener(actionListener, "Shoot");
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) {
if(name.equals("Shoot") && !isPressed) {
getAudio();
CollisionResults results = new CollisionResults();
Ray ray = new Ray(app.getCamera().getLocation(), app.getCamera().getDirection());
rootNode.collideWith(ray, results);
if(results.size() > 0) {
Geometry hit = results.getCollision(1).getGeometry();
System.out.println(hit);
rootNode.detachChild(hit);
if(hit == exit) {
app.stop();
} else if(hit == appOne) {
cleanup();
detachMenu();
getAppOne();
} else if(hit == appTwo) {
cleanup();
detachMenu();
getAppTwo();
} else if(hit == appThree) {
cleanup();
detachMenu();
getAppThree();
} else {
System.out.println("what happened ?");
}
} else
System.out.println("how'd you miss?");
}
}
};
private void detachMenu() {
app.getStateManager().detach(this);
}
private void getAppOne() {
app.getStateManager().attach(Main.getCube());
}
private void getAppTwo() {
app.getStateManager().attach(Main.getCustom());
}
private void getAppThree() {
app.getStateManager().attach(Main.getSphere());
}
private void getAudio() {
Main.getAudio();
}
}
aaaand here’s the class where the audio bug is:
package appStates;
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.audio.AudioNode;
import com.jme3.collision.CollisionResults;
import com.jme3.input.controls.ActionListener;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
/**
*
* @author Zachariah
*/
public class LoadCustom extends AbstractAppState {
protected Node rootNode;
protected Spatial character;
protected Geometry exit;
private SimpleApplication app;
private AudioNode sound;
public LoadCustom(SimpleApplication app) {
this.rootNode = app.getRootNode();
this.app = app;
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
rootNode.addLight(sun);
super.initialize(stateManager, app);
character = app.getAssetManager().loadModel("Models/Character/Character.001.mesh.j3o");
Material characterMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
characterMat.setColor("Color", ColorRGBA.Cyan);
character.setMaterial(characterMat);
exit = new Geometry("exit", new Box(1, 1, 1));
Material exitMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
exitMat.setColor("Color", ColorRGBA.Gray);
exit.setMaterial(exitMat);
rootNode.attachChild(character);
character.setLocalTranslation(0, 0, 0);
rootNode.attachChild(exit);
exit.setLocalTranslation(0, -3, 0);
initSound();
initKeys();
}
@Override
public void cleanup() {
super.cleanup();
rootNode.detachAllChildren();
app.getInputManager().removeListener(actionListener);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
}
public void initKeys() {
app.getInputManager().addListener(actionListener, "Shoot");
}
public void initSound() {
sound = new AudioNode(app.getAssetManager(), "Sound/Environment/River.ogg", true);
sound.setLooping(true);
sound.play();
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) {
if(name.equals("Shoot") && !isPressed) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(app.getCamera().getLocation(), app.getCamera().getDirection());
rootNode.collideWith(ray, results);
if(results.size() > 0) {
Geometry hit = results.getCollision(1).getGeometry();
System.out.println(hit);
rootNode.detachChild(hit);
if(hit == exit) {
detachThis();
attachMenu();
}
}
}
}
};
private void detachThis() {
app.getStateManager().detach(this);
}
private void attachMenu() {
app.getStateManager().attach(Main.getMenu());
}
}
so now when I go back to the menu, the audio is still playing, and if I enter the customState another stream spools up, and I get two of the same playing.
Sorry if this is a newb question