[Need Help] Second screen not shown up?

Hi, I’m new to Java, jMonkeyEngine and Nifty GUI. I’m still learning.

I’ve just complete a minigame, and was trying to make a start menu for it.
I’ve follow this tutorial: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:nifty_gui_overlay from the beginning, and also code from the “NiftyGUIDemo” example.

I’ve succeded in creating that menu, 2 button do what they mean to do very well. But on the second screen (which is my actual game), there’s nothing show up.
I know it’s running, because i can fire the bullet, and can hear the sound whenever a bullet is fired. But not a single image shown up.

I don’t know what wrong with my code. Please help me. Thank you.

Here are my codes:

MainMenuLayout.xml
[java]<?xml version=“1.0” encoding=“UTF-8”?>
<nifty xmlns=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd”>
<useStyles filename=“nifty-default-styles.xml” />
<useControls filename=“nifty-default-controls.xml” />
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ →
<!-- This demo shows a two-screen layout in Nifty’s XML syntax. →
<!-- You see two screens with two layers each, contain several panels. →
<!-- The panels contain images, text, and controls (label and buttons). →
<!-- Buttons have an interaction defined, and some of the text →
<!-- is dynamically defined, using the MyStartScreen controller. →
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ →

<!-- +++++++++++++++++++++++++++++++++++++++ →
<!-- lay out the start screen/layers/panels →
<!-- +++++++++++++++++++++++++++++++++++++++ →
<screen id=“start” controller=“neonwarships.MyStartScreen”>
<layer id=“background” childLayout=“center”>
<image filename=“Interface/start-background.png”></image>
</layer>
<layer id=“foreground” childLayout=“vertical”>
<panel id=“panel_top” height=“25%” width=“75%” align=“center” childLayout=“center”>
<text text="${CALL.getPlayerName()}'s Cool Game" font=“Interface/Fonts/Default.fnt” width=“100%” height=“100%” />
</panel>
<panel id=“panel_mid” height=“50%” width=“75%” align=“center” childLayout=“center”>
<text text=“Here goes some text describing the game and the rules and stuff. Incidentally, the text is quite long and needs to wrap at the end of lines. Here goes some text describing the game and the rules and stuff. Incidentally, the text is quite long and needs to wrap at the end of lines. Here goes some text describing the game and the rules and stuff. Incidentally, the text is quite long and needs to wrap at the end of lines.”
font=“Interface/Fonts/Default.fnt” width=“100%” height=“100%” wrap=“true” />
</panel>
<panel id=“panel_bottom” height=“25%” width=“75%” align=“center” childLayout=“horizontal”>
<panel id=“panel_bottom_left” height=“50%” width=“50%” valign=“center” childLayout=“center”>
<control name=“button” label=“Start” id=“StartButton” align=“center” valign=“center”
visibleToMouse=“true”>
<interact onClick=“startGame(hud1)” />
</control>
</panel>
<panel id=“panel_bottom_right” height=“50%” width=“50%” valign=“center” childLayout=“center”>
<control name=“button” label=“Quit” id=“QuitButton” align=“center” valign=“center”
visibleToMouse=“true” >
<interact onClick=“quitGame()”/>
</control>
</panel>
</panel>
</layer>
</screen>

<!-- +++++++++++++++++++++++++++++++++++++++ →
<!-- lay out the HUD screen/layers/panels →
<!-- +++++++++++++++++++++++++++++++++++++++ →
<screen id=“hud1” controller=“neonwarships.MyStartScreen”>
<layer id=“background” childLayout=“center”>
</layer>
<layer id=“foreground” childLayout=“horizontal”>
</layer>
</screen>
</nifty>[/java]

MyStartScreen.java:
[java]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package neonwarships;

/**
*

  • @author Theo
    */

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.TextRenderer;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

public class MyStartScreen extends AbstractAppState implements ScreenController {

private Nifty nifty;
private Application app;
private Screen screen;

/** custom methods */
public MyStartScreen() {
    /** You custom constructor, can accept arguments */
}

public void startGame(String nextScreen) {
    nifty.gotoScreen(nextScreen);  // switch to another screen
}

public void quitGame() {
    app.stop();
}

public String getPlayerName() {
    return System.getProperty("user.name");
}

public void bind(Nifty nifty, Screen screen) {
    this.nifty = nifty;
    this.screen = screen;
}

public void onStartScreen() {
}

public void onEndScreen() {
}

/** jME3 AppState methods */
@Override
public void initialize(AppStateManager stateManager, Application app) {
  this.app = app;
}

}[/java]

Main.java:
[java]package neonwarships;

import com.jme3.app.SimpleApplication;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.system.AppSettings;
import com.jme3.texture.Texture2D;
import com.jme3.ui.Picture;
import java.awt.Rectangle;
import java.util.Random;
import com.jme3.niftygui.NiftyJmeDisplay;
import de.lessvoid.nifty.Nifty;

/**

  • Urheberrecht (c) 2013, Daniel Gallenberger
  • MonkeyBlaster is a Port of Shape Blaster by Michael Hoffmann.
  • Shape Blaster is a Clone of Geometry Wars.

*/

public class MonkeyBlasterMain extends SimpleApplication implements ActionListener, AnalogListener {
private Hud hud;
private Sound sound;
private ParticleManager particleManager;
private Grid grid;

private long bulletCooldown;
private long enemySpawnCooldown;
private float enemySpawnChance = 80;
private long spawnCooldownBlackHole;

private Spatial player;
private Node bulletNode;
private Node enemyNode;
private Node blackHoleNode;
private Node particleNode;

private boolean gameOver = false;

private MyStartScreen startScreen;
    
public static void main(String[] args) {
    AppSettings settings = new AppSettings(true);
    settings.setResolution(640, 480);
    MonkeyBlasterMain app = new MonkeyBlasterMain();
    app.setShowSettings(false); // splashscreen
    app.setSettings(settings);
    app.start();
}

@Override
public void simpleInitApp() {

// setup camera for 2D games
cam.setParallelProjection(true);
cam.setLocation(new Vector3f(0,0,0.5f));
getFlyByCamera().setEnabled(false);

// turn off stats (you can leave it on, if you want)
setDisplayStatView(false);
setDisplayFps(false);

// initializing the bloom filter
FilterPostProcessor fpp=new FilterPostProcessor(assetManager);
BloomFilter bloom=new BloomFilter();
bloom.setBloomIntensity(2f);
bloom.setExposurePower(2);
bloom.setExposureCutOff(0f);
bloom.setBlurScale(1.5f);
fpp.addFilter(bloom);
guiViewPort.addProcessor(fpp);
guiViewPort.setClearColor(true);

// setup input handling
inputManager.setMouseCursor((JmeCursor) assetManager.loadAsset(“Textures/Pointer.ico”));

    inputManager.addMapping("mousePick", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(this, "mousePick");
    
    inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));
    inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));
    inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));
    inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));
    inputManager.addMapping("return", new KeyTrigger(KeyInput.KEY_RETURN));
    inputManager.addListener(this, "left");
    inputManager.addListener(this, "right");
    inputManager.addListener(this, "up");
    inputManager.addListener(this, "down");
    inputManager.addListener(this, "return");

// setup the hud
hud = new Hud(assetManager, rootNode, settings.getWidth(), settings.getHeight());
hud.reset();

// sounds
sound = new Sound(assetManager);
sound.startMusic();
sound.spawn();

// particles
particleManager = new ParticleManager(rootNode, getSpatial(“Laser”), getSpatial(“Glow”), settings.getWidth(), settings.getHeight());

// grid
Rectangle size = new Rectangle(0, 0, settings.getWidth(), settings.getHeight());
Vector2f spacing = new Vector2f(25,25);
grid = new Grid(size, spacing, rootNode, assetManager);

// setup the player
player = getSpatial(“Player”);
player.setUserData(“alive”,true);
player.move(settings.getWidth()/2, settings.getHeight()/2, 0);
player.addControl(new PlayerControl(settings.getWidth(), settings.getHeight(), particleManager));
rootNode.attachChild(player);

// setup the bulletNode
bulletNode = new Node(“bullets”);
rootNode.attachChild(bulletNode);
// setup the enemyNode
enemyNode = new Node(“enemies”);
rootNode.attachChild(enemyNode);
// setup the blackholeNode
blackHoleNode = new Node(“black_holes”);
rootNode.attachChild(blackHoleNode);
// setup the particleNode
particleNode = new Node(“particles”);
rootNode.attachChild(particleNode);

    /**
     * Activate the Nifty-JME integration: 
     */
    startScreen = new MyStartScreen();
    stateManager.attach(startScreen);
    
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(
            assetManager, inputManager, audioRenderer, guiViewPort);
    Nifty nifty = niftyDisplay.getNifty();
    nifty.fromXml("Interface/MainMenuLayout.xml", "start", startScreen);
    guiViewPort.addProcessor(niftyDisplay);
    //nifty.setDebugOptionPanelColors(true);

    flyCam.setDragToRotate(true); // you need the mouse for clicking now
}

@Override
public void simpleUpdate(float tpf) {
    if ((Boolean) player.getUserData("alive")) {
        spawnEnemies();
        spawnBlackHoles();
        handleCollisions();
        handleGravity(tpf);
    } else if (System.currentTimeMillis() - (Long) player.getUserData("dieTime") &gt; 4000f &amp;&amp; !gameOver) {
        // spawn player
        player.setLocalTranslation(500,500,0);
        rootNode.attachChild(player);
        player.setUserData("alive",true);
        sound.spawn();
        grid.applyDirectedForce(new Vector3f(0,0,5000), player.getLocalTranslation(), 100);
    }
    grid.update(tpf);
    hud.update();
}

public String getPlayerName() {
    return System.getProperty("user.name");
}

private void spawnEnemies() {
    if (System.currentTimeMillis() - enemySpawnCooldown &gt;= 17) {
        enemySpawnCooldown = System.currentTimeMillis();
        
        if (enemyNode.getQuantity() &lt; 50) {
            if (new Random().nextInt((int) enemySpawnChance) == 0) {
                createSeeker();
            }
            if (new Random().nextInt((int) enemySpawnChance) == 0) {
                createWanderer();
            }
        }
        
        //increase Spawn Time
        if (enemySpawnChance &gt;= 1.1f) {
            enemySpawnChance -= 0.005f;
        }
    }
}

    private void createSeeker() {
    Spatial seeker = getSpatial("Seeker");
    seeker.setLocalTranslation(getSpawnPosition());
    seeker.addControl(new SeekerControl(player));
    seeker.setUserData("active",false);
    enemyNode.attachChild(seeker);
}

private void createWanderer() {
    Spatial wanderer = getSpatial("Wanderer");
    wanderer.setLocalTranslation(getSpawnPosition());
    wanderer.addControl(new WandererControl(settings.getWidth(), settings.getHeight()));
    wanderer.setUserData("active",false);
    enemyNode.attachChild(wanderer);
}

private void spawnBlackHoles() {
    if (blackHoleNode.getQuantity() &lt; 2) {
         if (System.currentTimeMillis() - spawnCooldownBlackHole &gt; 10f) {
            spawnCooldownBlackHole = System.currentTimeMillis();
            if (new Random().nextInt(1000) == 0) {
                createBlackHole();
            }
        }
    }
}

private void createBlackHole() {
    Spatial blackHole = getSpatial("Black Hole");
    blackHole.setLocalTranslation(getSpawnPosition());
    blackHole.addControl(new BlackHoleControl(particleManager, grid));
    blackHole.setUserData("active",false);
    blackHoleNode.attachChild(blackHole);
}

private Vector3f getSpawnPosition() {
    Vector3f pos;
    do {
        pos = new Vector3f(new Random().nextInt(settings.getWidth()), new Random().nextInt(settings.getHeight()),0);
    } while (pos.distanceSquared(player.getLocalTranslation()) &lt; 8000);
    return pos;
}

private void handleCollisions() {
    // should the player die?
    for (int i=0; i&lt;enemyNode.getQuantity(); i++) {
        if ((Boolean) enemyNode.getChild(i).getUserData("active")) {
            if (checkCollision(player,enemyNode.getChild(i))) {
                killPlayer();   
            }
        }
    }
    
    //should an enemy die?
    int i=0;
    while (i &lt; enemyNode.getQuantity()) {
        int j=0;
        while (j &lt; bulletNode.getQuantity()) {
            if (checkCollision(enemyNode.getChild(i),bulletNode.getChild(j))) {
                // add points depending on the type of enemy
                if (enemyNode.getChild(i).getName().equals("Seeker")) {
                    hud.addPoints(2);
                } else if (enemyNode.getChild(i).getName().equals("Wanderer")) {
                    hud.addPoints(1);
                }
                particleManager.enemyExplosion(enemyNode.getChild(i).getLocalTranslation());
                enemyNode.detachChildAt(i);
                bulletNode.detachChildAt(j);
                sound.explosion();
                break;
            }
            j++;
        }
        i++;
    }
    
    //is something colliding with a black hole?
    for (i=0; i&lt;blackHoleNode.getQuantity(); i++) {
        Spatial blackHole = blackHoleNode.getChild(i);
        if ((Boolean) blackHole.getUserData("active")) {
            //player
            if (checkCollision(player,blackHole)) {
                killPlayer();
            }
            
            //enemies
            int j=0;
            while (j &lt; enemyNode.getQuantity()) {
                if (checkCollision(enemyNode.getChild(j),blackHole)) {
                    particleManager.enemyExplosion(enemyNode.getChild(j).getLocalTranslation());
                    enemyNode.detachChildAt(j);
                }
                j++;
            }
            
            //bullets
            j=0;
            while (j &lt; bulletNode.getQuantity()) {
                if (checkCollision(bulletNode.getChild(j),blackHole)) {
                    bulletNode.detachChildAt(j);
                    blackHole.getControl(BlackHoleControl.class).wasShot();
                    particleManager.blackHoleExplosion(blackHole.getLocalTranslation());
                    if (blackHole.getControl(BlackHoleControl.class).isDead()) {
                        blackHoleNode.detachChild(blackHole);
                        sound.explosion();
                    }
                }
                j++;
            }
        }
    }
}

private boolean checkCollision(Spatial a, Spatial b) {
    float distance = a.getLocalTranslation().distance(b.getLocalTranslation());
    float maxDistance =  (Float)a.getUserData("radius") + (Float)b.getUserData("radius");
    return distance &lt;=maxDistance;
}

private void killPlayer() {
    player.removeFromParent();
    player.getControl(PlayerControl.class).reset();
    player.setUserData("alive", false);
    player.setUserData("dieTime", System.currentTimeMillis());
    enemyNode.detachAllChildren();
    blackHoleNode.detachAllChildren();
    particleManager.playerExplosion(player.getLocalTranslation());
    if (!hud.removeLife()) {
        hud.endGame();
        gameOver = true;
    }
}

private void handleGravity(float tpf) {
    for (int i=0; i&lt;blackHoleNode.getQuantity(); i++) {
        if (!(Boolean)blackHoleNode.getChild(i).getUserData("active")) {continue;}
        int radius = 250;
        
        // check Player
        if (isNearby(player,blackHoleNode.getChild(i),radius)) {
            applyGravity(blackHoleNode.getChild(i), player, tpf);
        }
        // check Bullets
        for (int j=0; j&lt;bulletNode.getQuantity(); j++) {
            if (isNearby(bulletNode.getChild(j),blackHoleNode.getChild(i),radius)) {
                applyGravity(blackHoleNode.getChild(i), bulletNode.getChild(j), tpf);
            }
        }
        // check Enemies
        for (int j=0; j&lt;enemyNode.getQuantity(); j++) {
            if (!(Boolean)enemyNode.getChild(j).getUserData("active")) {continue;}
            if (isNearby(enemyNode.getChild(j),blackHoleNode.getChild(i),radius)) {
                applyGravity(blackHoleNode.getChild(i), enemyNode.getChild(j), tpf);
            }
        }
        // check Particles
        for (int j=0; j&lt;particleNode.getQuantity(); j++) {
            if (particleNode.getChild(j).getUserData("affectedByGravity")) {
                applyGravity(blackHoleNode.getChild(i), particleNode.getChild(j), tpf);
            }
        }
    }
}

private boolean isNearby(Spatial a, Spatial b, float distance) {
    Vector3f pos1 = a.getLocalTranslation();
    Vector3f pos2 = b.getLocalTranslation();
    return pos1.distanceSquared(pos2) &lt;= distance * distance;
}

private void applyGravity(Spatial blackHole, Spatial target, float tpf) {
    Vector3f difference = blackHole.getLocalTranslation().subtract(target.getLocalTranslation());
    
    Vector3f gravity = difference.normalize().multLocal(tpf);
    float distance = difference.length();
    
    if (target.getName().equals("Player")) {
        gravity.multLocal(250f/distance);
        target.getControl(PlayerControl.class).applyGravity(gravity.mult(80f));
    } else if (target.getName().equals("Bullet")) {
        gravity.multLocal(250f/distance);
        target.getControl(BulletControl.class).applyGravity(gravity.mult(-0.8f));
    } else if (target.getName().equals("Seeker")) {
        target.getControl(SeekerControl.class).applyGravity(gravity.mult(150000));
    } else if (target.getName().equals("Wanderer")) {
        target.getControl(WandererControl.class).applyGravity(gravity.mult(150000));
    } else if (target.getName().equals("Laser") || target.getName().equals("Glow")) {
        target.getControl(ParticleControl.class).applyGravity(gravity.mult(15000), distance);
    }
}

@Override
public void simpleRender(RenderManager rm) {}

public void onAction(String name, boolean isPressed, float tpf) {
    if ((Boolean) player.getUserData("alive")) {
        if (name.equals("up")) {
           player.getControl(PlayerControl.class).up = isPressed;
        } else if (name.equals("down")) {
            player.getControl(PlayerControl.class).down = isPressed;
        } else if (name.equals("left")) {
            player.getControl(PlayerControl.class).left = isPressed;
        } else if (name.equals("right")) {
            player.getControl(PlayerControl.class).right = isPressed;
        }
    }
}

public void onAnalog(String name, float value, float tpf) {
    if ((Boolean) player.getUserData("alive")) {
        if (name.equals("mousePick")) {
            //shoot Bullet
            if (System.currentTimeMillis() - bulletCooldown &gt; 83f) {
                bulletCooldown = System.currentTimeMillis();
                
                Vector3f aim = getAimDirection();
                Vector3f offset = new Vector3f(aim.y/3,-aim.x/3,0);

// init bullet 1
Spatial bullet = getSpatial(“Bullet”);
Vector3f finalOffset = aim.add(offset).mult(30);
Vector3f trans = player.getLocalTranslation().add(finalOffset);
bullet.setLocalTranslation(trans);
bullet.addControl(new BulletControl(aim, settings.getWidth(), settings.getHeight(), particleManager, grid));
bulletNode.attachChild(bullet);

// init bullet 2
Spatial bullet2 = getSpatial(“Bullet”);
finalOffset = aim.add(offset.negate()).mult(30);
trans = player.getLocalTranslation().add(finalOffset);
bullet2.setLocalTranslation(trans);
bullet2.addControl(new BulletControl(aim, settings.getWidth(), settings.getHeight(), particleManager, grid));
bulletNode.attachChild(bullet2);

                sound.shoot();
            }
        }
    }
}

private Vector3f getAimDirection() {
    Vector2f mouse = inputManager.getCursorPosition();
    Vector3f playerPos = player.getLocalTranslation();
    Vector3f dif = new Vector3f(mouse.x-playerPos.x,mouse.y-playerPos.y,0);
    return dif.normalizeLocal();
}

public static float getAngleFromVector(Vector3f vec) {
    Vector2f vec2 = new Vector2f(vec.x,vec.y);
    return vec2.getAngle();
}

public static Vector3f getVectorFromAngle(float angle) {
    return new Vector3f(FastMath.cos(angle),FastMath.sin(angle),0);
}

private Spatial getSpatial(String name) {
    Node node = new Node(name);

// load picture
Picture pic = new Picture(name);
Texture2D tex = (Texture2D) assetManager.loadTexture(“Textures/”+name+".png");
pic.setTexture(assetManager,tex,true);

// adjust picture
float width = tex.getImage().getWidth();
float height = tex.getImage().getHeight();
pic.setWidth(width);
pic.setHeight(height);
pic.move(-width/2f,-height/2f,0);

// add a material to the picture
Material picMat = new Material(assetManager, “Common/MatDefs/Gui/Gui.j3md”);
picMat.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);
node.setMaterial(new Material());

// set the radius of the spatial
// (using width only as a simple approximation)
node.setUserData(“radius”, width/2);

// attach the picture to the node and return it
node.attachChild(pic);
return node;
}

public AppSettings getSettings() {return settings;}

}[/java]

Help me please, guy. I’m stuck now :frowning:

I don’t want to deter you from using Nifty, but you will likely get more active support using Lemur or tonegodGUI. Especially if all you are trying to do is throw together a start menu and HUD and are hitting problems already.

Also, not trying to avoid your question, I just don’t know anything about Nifty anymore.

Well… in the example you linked you don’t actually have any visible elements in hud1 so it isn’t a nifty problem. Just quickly glancing at your code but I think your problem is in your “getSpatial” method. I think you are setting up the picture class incorrectly. For one… the material should be set on the picture and the texture needs to be set on the material. I think you are setting the texture on the built in picture material and then replacing it. I would step through that section of code and debug it to be sure though.

@glh3586 said: Well... in the example you linked you don't actually have any visible elements in hud1 so it isn't a nifty problem. Just quickly glancing at your code but I think your problem is in your "getSpatial" method. I think you are setting up the picture class incorrectly. For one... the material should be set on the picture and the texture needs to be set on the material. I think you are setting the texture on the built in picture material and then replacing it. I would step through that section of code and debug it to be sure though.
Ok, i looked into that and fixed it to this: [java]private Spatial getSpatial(String name) { // load picture Picture pic = new Picture(name);
    //add a material to the picture
    Material picMat = new Material(assetManager, "Common/MatDefs/Gui/Gui.j3md");
    Texture2D tex = (Texture2D) assetManager.loadTexture("Textures/"+name+".png");
    picMat.setTexture("Texture", tex);
    picMat.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);
    pic.setMaterial(picMat);

// adjust picture
float width = tex.getImage().getWidth();
float height = tex.getImage().getHeight();
pic.setWidth(width);
pic.setHeight(height);
pic.move(-width/2f,-height/2f,0);

// set the radius of the spatial
// (using width only as a simple approximation)
pic.setUserData(“radius”, width/2);

// attach the picture to the node and return it
rootNode.attachChild(pic);
return rootNode;
}[/java]
NOW I CAN’T EVEN START THE GAME. It brings out an error that says:

Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main] java.lang.StackOverflowError

Where did i go wrong ?

@t0neg0d said: I don't want to deter you from using Nifty, but you will likely get more active support using Lemur or tonegodGUI. Especially if all you are trying to do is throw together a start menu and HUD and are hitting problems already.

Also, not trying to avoid your question, I just don’t know anything about Nifty anymore.


Thank you. I’ll try using Lemur and tonegodGUI after this :smiley:

@lovelyiris said: Ok, i looked into that and fixed it to this: [java]private Spatial getSpatial(String name) { // load picture Picture pic = new Picture(name);
    //add a material to the picture
    Material picMat = new Material(assetManager, "Common/MatDefs/Gui/Gui.j3md");
    Texture2D tex = (Texture2D) assetManager.loadTexture("Textures/"+name+".png");
    picMat.setTexture("Texture", tex);
    picMat.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);
    pic.setMaterial(picMat);

// adjust picture
float width = tex.getImage().getWidth();
float height = tex.getImage().getHeight();
pic.setWidth(width);
pic.setHeight(height);
pic.move(-width/2f,-height/2f,0);

// set the radius of the spatial
// (using width only as a simple approximation)
pic.setUserData(“radius”, width/2);

// attach the picture to the node and return it
rootNode.attachChild(pic);
return rootNode;
}[/java]
NOW I CAN’T EVEN START THE GAME. It brings out an error that says:

Where did i go wrong ?

Well, you left all of the helpful bits out of the stack trace… namely: the stack trace. Hard to help without seeing that.

For a stack overflow, there should be a bunch of recursively repeating calls… usually in your code. Then you can figure out where you are recursing and fix it.

@pspeed said: Well, you left all of the helpful bits out of the stack trace... namely: the stack trace. Hard to help without seeing that.

For a stack overflow, there should be a bunch of recursively repeating calls… usually in your code. Then you can figure out where you are recursing and fix it.


I’m sorry, i forgot about that. Here the error log:
[java]SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.StackOverflowError
at com.jme3.scene.Node.getChild(Node.java:437)
at com.jme3.scene.Node.getChild(Node.java:437)
at com.jme3.scene.Node.getChild(Node.java:437)
at com.jme3.scene.Node.getChild(Node.java:437)
at com.jme3.scene.Node.getChild(Node.java:437)
at com.jme3.scene.Node.getChild(Node.java:437)
…[/java]
(the … is where that line repeat several times)
And this is com.jme3.scene.Node.getChild(Node.java:437):
[java]public Spatial getChild(String name) {
if (name == null)
return null;

    for (Spatial child : children.getArray()) {
        if (name.equals(child.getName())) {
            return child;
        } else if(child instanceof Node) {
            Spatial out = ((Node)child).getChild(name);     //(this is line 437)
            if(out != null) {
                return out;
            }
        }
    }
    return null;
}[/java]

Yeah, i know this is a recursive call error, and maybe because of this
[java]
private Spatial getSpatial(String name) {

rootNode.attachChild(pic);
return rootNode;}
[/java]
versus many getSpatial calls like this in the Main.java
[java]…
Spatial bullet = getSpatial(“Bullet”);

particleManager = new ParticleManager(rootNode, getSpatial(“Laser”), getSpatial(“Glow”), settings.getWidth(), settings.getHeight());

player = getSpatial(“Player”);

[/java]
I’m not sure, just my guess…

It looks like somehow you have managed to attach the root node to itself.

Weird that your getSpatial() call returns rootNode instead of the spatial. Seems like a bug or that the method is misnamed.

Ok, this is the getSpatial() code i’ve just fixed:
[java]private Spatial getSpatial(String name) {
Node node = new Node(name);
// load picture
Picture pic = new Picture(name);

    //add a material to the picture
    Material picMat = new Material(assetManager, "Common/MatDefs/Gui/Gui.j3md");
    Texture2D tex = (Texture2D) assetManager.loadTexture("Textures/"+name+".png");
    picMat.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);
    picMat.setTexture("Texture", tex);
    pic.setMaterial(picMat);

// adjust picture
float width = tex.getImage().getWidth();
float height = tex.getImage().getHeight();
pic.setWidth(width);
pic.setHeight(height);
pic.move(-width/2f,-height/2f,0);

// set the radius of the spatial
// (using width only as a simple approximation)
node.setUserData(“radius”, width/2);

// attach the picture to the node and return it
node.attachChild(pic);
return node;
}[/java]
and now, i realize a new problem:
FROM THE #1 POST IN THIS TOPIC, THE SECOND SCREEN RUNS ALONG WITH THE START MENU. That’s mean I can play the game from the first screen (start menu), without clicking the Start Button (and the Welcome layer is still there).
OF COURSE, STILL, NOTHING IN THE SECOND SCREEN SHOW UP. It’s just like playing the game in Blind Mode (literally).

After taking a closer look at your code… you start the gameplay when you load the main menu and not when you switch to the hud1 screen. Everything in the application initialization gets run at start up and doesn’t magically get setup after you go to screen 2. You would have to do all that game setup after you move to the next screen. For example, in your startGame method.

It looks like you are setting up the camera incorrectly as well. it looks like you set the position for your player for example outside of the camera’s view so it wouldn’t show up either.

@glh3586 said: After taking a closer look at your code.... you start the gameplay when you load the main menu and not when you switch to the hud1 screen. Everything in the application initialization gets run at start up and doesn't magically get setup after you go to screen 2. You would have to do all that game setup after you move to the next screen. For example, in your startGame method.

It looks like you are setting up the camera incorrectly as well. it looks like you set the position for your player for example outside of the camera’s view so it wouldn’t show up either.


Wow, it seams things are getting complicated now.
So, how would you suggest me to do? I’m a little confused right now >.<
Thanks so much.

@lovelyiris said: Wow, it seams things are getting complicated now. So, how would you suggest me to do? I'm a little confused right now >.< Thanks so much.

Here is how the life cycle of an AppState works (which will help you initialize things when you want.

The constructor is called the moment you instantiate the AppState (AppState blah = new AppState(), etc)… so any code added to the constructor will execute at that time.
The initiaze method of an AppState runs the moment you attach the AppState to the state manager (this executes every time you attach it)
The cleanup method is run every time you detach the AppState from state manager.

Hopefully, this will help.

@t0neg0d said: Here is how the life cycle of an AppState works (which will help you initialize things *when* you want.

The constructor is called the moment you instantiate the AppState (AppState blah = new AppState(), etc)… so any code added to the constructor will execute at that time.
The initiaze method of an AppState runs the moment you attach the AppState to the state manager (this executes every time you attach it)
The cleanup method is run every time you detach the AppState from state manager.

Hopefully, this will help.


Thank you. Though i still feel confusing from this.
Guess today will be another hard-coding day >.<.

@lovelyiris said: Thank you. Though i still feel confusing from this. Guess today will be another hard-coding day >.<.

Feel free to ask specific questions as you go!

One of the things I try and remember with AppStates to keep myself in check is:

Constructor = create the objects I need… don’t do anything with them… just create them.
initialize = Add objects to the scene, add input mapping to the input manager, etc
cleanup = Remove objects from the scene, remove bindings from the input manager, etc.

The difficult part (when managing your bindings this way) is remembering what binds are already there and making sure you don’t reuse them unless you really mean to reuse them.

@t0neg0d said: Feel free to ask specific questions as you go!

One of the things I try and remember with AppStates to keep myself in check is:

Constructor = create the objects I need… don’t do anything with them… just create them.
initialize = Add objects to the scene, add input mapping to the input manager, etc
cleanup = Remove objects from the scene, remove bindings from the input manager, etc.

The difficult part (when managing your bindings this way) is remembering what binds are already there and making sure you don’t reuse them unless you really mean to reuse them.


Base on my code, can you show me a little more details about what I should do now please? Thank you so much :smiley:

@lovelyiris said: Base on my code, can you show me a little more details about what I should do now please? Thank you so much :D

So sorry… missed this post somehow. Give me a little bit to caffeinate myself, wake up a bit more and I’ll re-read the thread and see where you left off.

Can you do me a favor and explain what you are trying to accomplish in a simple description. Something like:

  1. Start app and show Main Menu
  2. Click on Start Game, unload Main Menu, load HUD
  3. Click pause button, load Pause Menu
  4. Click Exit Game, stop game, unload HUD & Pause Menu, load Main Menu.

I may not be able to give you specific help with Nifty, however, I could help a bit with how to setup your AppStates as simple as possible, which will give you something to run with.

@t0neg0d said: Can you do me a favor and explain what you are trying to accomplish in a simple description. Something like:
  1. Start app and show Main Menu
  2. Click on Start Game, unload Main Menu, load HUD
  3. Click pause button, load Pause Menu
  4. Click Exit Game, stop game, unload HUD & Pause Menu, load Main Menu.

I may not be able to give you specific help with Nifty, however, I could help a bit with how to setup your AppStates as simple as possible, which will give you something to run with.


Ok, what i want is:

  • Start the game with Main Menu, 2 buttons there: Star Game and Quit
  • Click Start Game -> go to the main game scene

That’s all i want for now. Thank you :smiley:

@lovelyiris said: Ok, what i want is: - Start the game with Main Menu, 2 buttons there: Star Game and Quit - Click Start Game -> go to the main game scene

That’s all i want for now. Thank you :smiley:

I know you are using Nifty, but my examples will have to use my gui library, as it is what I am familiar with… Forget about the actual ui components, as it is the AppState usage that is most important here:

MainMenu.java
[java]
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.math.Vector2f;
import tonegod.gui.core.Screen;
import tonegod.gui.controls.buttons.ButtonAdapter;

/**
*

  • @author t0neg0d
    */
    public class MainMenu extends AbstractAppState {
    private Main main;
    private Screen screen;
    private ButtonAdapter button1, button2;

    public MainMenu(Main main, Screen screen) {
    this.main = main;
    this.screen = screen;

     initScreen();
    

    }

    private void initScreen() {
    button1 = new ButtonAdapter(
    screen,
    new Vector2f(screen.getWidth()/2-50, screen.getHeight()/2-30), // position
    new Vector2f(100,20) // dimensions
    ) {
    @Override
    public void onButtonMouseLeftUp(MouseButtonEvent evt, boolean toggled) {
    // start your game and load game appstate
    main.getStateManager().detach(main.getMainMenu());
    main.getStateManager().attach(main.getGameState());
    }
    };
    button1.setText(“Start Game”);

     button2 = new ButtonAdapter(
     	screen,
     	new Vector2f(screen.getWidth()/2-50, screen.getHeight()/2+30), // position
     	new Vector2f(100,20) // dimensions
     ) {
     	@Override
     	public void onButtonMouseLeftUp(MouseButtonEvent evt, boolean toggled) {
     		// Quit the app
     		main.exit(0);
     	}
     };
     button2.setText("Quit Game");
    
     screen.addElement(button1, true);
     screen.addElement(button2, true);
    

    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    // When you load the appstate, show the ui elements you want
    button1.showWithEffect();
    button2.showWithEffect();
    }

    @Override
    public void update(float tpf) { }

    @Override
    public void cleanup() {
    // When you detach the appstate, remove the ui elements you no longer need
    button1.hideWithEffect();
    button2.hideWithEffect();
    }
    }
    [/java]

Game.java
[java]
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.math.Vector2f;
import tonegod.gui.core.Screen;
import tonegod.gui.controls.buttons.ButtonAdapter;

/**
*

  • @author t0neg0d
    */
    public class MainMenu extends AbstractAppState {
    private Main main;
    private Screen screen;
    private ButtonAdapter button1;

    public MainMenu(Main main, Screen screen) {
    this.main = main;
    this.screen = screen;

     initScreen();
    

    }

    private void initScreen() {
    button1 = new ButtonAdapter(
    screen,
    new Vector2f(screen.getWidth()/2-50, screen.getHeight()/2-30), // position
    new Vector2f(100,20) // dimensions
    ) {
    @Override
    public void onButtonMouseLeftUp(MouseButtonEvent evt, boolean toggled) {
    // start your game and load game appstate
    main.getStateManager().detach(main.getGameState());
    main.getStateManager().attach(main.getMainMenu());
    }
    };
    button1.setText(“Main Menu”);

     screen.addElement(button1, true);
    

    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    // When you load the appstate, show the ui elements you want
    button1.showWithEffect();
    }

    @Override
    public void update(float tpf) { }

    @Override
    public void cleanup() {
    // When you detach the appstate, remove the ui elements you no longer need
    button1.hideWithEffect();
    }
    }
    [/java]

Your main app class: (Main.java)
[java]
import com.jme3.app.SimpleApplication;
import tonegod.gui.core.Screen;

public class Main extends SimpleApplication {
private Screen screen;
private MainMenu mainMenu;
private Game game;

public static void main(String[] args) {
	Main app = new Main();
	app.start();
}

@Override
public void simpleInitApp() {
	flyCam.setDragToRotate(true);
	inputManager.setCursorVisible(true);
	
	initScreen();
	initStates();
	startApp();
}

private void initScreen() {
	screen = new Screen(this);
	guiNode.addControl(screen);
}

private void initStates() {
	mainMenu = new MainMenu(this, screen);
	game = new Game(this, screen);
}

private void startApp() {
	stateManager.attach(mainMenu);
}

public MainMenu getMainMenu() { return this.mainMenu; }
public Game getGameState() { return this.game; }

@Override
public void simpleUpdate(float tpf) {  }

@Override
public void simpleRender(RenderManager rm) {  }

}
[/java]

These were type out by hand, so you’ll likely find errors in them, but… the basic idea is to show how simple managing your application flow using app states should be. I use the constructor to create ui elements, add a reference to the one and only screen control… and in this case I hide them right away… which removes them from the rendered scene). In the initialize function, I show the elements. which adds the to the rendered scene using whatever Show effect is associated with them. In cleanup, I hide the elements using whatever Hide effect is associated with them.

There is nothing more to it than this…