0
\$\begingroup\$

I'm following the Canyon Bunny example in making my own game and I'm at the point where I want to implement a level selection screen. The way the example code works is that there's a Level class whose constructor takes a string variable that contains the path of the level file to be loaded from WorldController class which contains the game logic. So far I have a LevelScreen with the various buttons for the various levels like so:

public class LevelScreen extends AbstractGameScreen {

private Stage stage;
private Skin levelSkin;
private String currLevel;

private Image imgBackground;

private Button btnForest, btnDesert;

private final float DEBUG_REBUILD_INTERVAL = 5.0f;
private boolean debugEnabled = false;
private float debugRebuildStage;

private static final String TAG = LevelScreen.class.getName();

public LevelScreen(DirectedGame game) {
    super(game);
}

private void rebuildStage() {
    levelSkin = new Skin(Gdx.files.internal(Constants.SKIN_LEVEL_UI),
            new TextureAtlas(Constants.TEXTURE_ATLAS_LEVELS));

    Table layerBackground = buildBackgroundLayer();
    Table layerLevels = buildLevelsLayer();

    stage.clear();
    Stack stack = new Stack();
    stage.addActor(stack);
    stack.setSize(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT);
    stack.add(layerBackground);
    stack.add(layerLevels);
}

private Table buildBackgroundLayer() {
    Table layer = new Table();
    imgBackground = new Image(levelSkin, "wallpaper");
    layer.add(imgBackground);
    return layer;
}

private Table buildLevelsLayer() {
    Table layer = new Table();

    btnDesert = new Button(levelSkin, "desert");
    layer.addActor(btnDesert);
    btnDesert.setPosition(50, 250);
    btnDesert.addListener(new ChangeListener() {
        @Override
        public void changed(ChangeEvent event, Actor actor) {
            onDesertClicked();
        }

        private void onDesertClicked() {
            setCurrLevel(Constants.LEVEL_01);
            ScreenTransition transition = ScreenTransitionSlide.init(0.75f, ScreenTransitionSlide.LEFT, false,
                    Interpolation.bounceOut);
            game.setScreen(new GameScreen(game), transition);
        }
    });

    btnForest = new Button(levelSkin, "forest");
    layer.addActor(btnForest);
    btnForest.setPosition(345, 150);
    btnForest.addListener(new ChangeListener() {
        @Override
        public void changed(ChangeEvent event, Actor actor) {
            onForestClicked();
        }

        private void onForestClicked() {
            setCurrLevel(Constants.LEVEL_02);
            ScreenTransition transition = ScreenTransitionSlide.init(0.75f, ScreenTransitionSlide.LEFT, false,
                    Interpolation.bounceOut);
            game.setScreen(new GameScreen(game), transition);
        }
    });

    btnBack = new Button(levelSkin, "back");
    layer.addActor(btnBack);
    btnBack.setPosition(640, 50);
    btnBack.addListener(new ChangeListener() {
        @Override
        public void changed(ChangeEvent event, Actor actor) {
            onBackClicked();
        }
    });

    return layer;
}

@Override
public InputProcessor getInputProcessor() {
    return stage;
}

@Override
public void render(float deltaTime) {
    Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    if (debugEnabled) {
        debugRebuildStage -= deltaTime;
        if (debugRebuildStage <= 0) {
            debugRebuildStage = DEBUG_REBUILD_INTERVAL;
            rebuildStage();
        }
    }

    stage.act(deltaTime);
    stage.draw();
    Table.drawDebug(stage);
}

private void onBackClicked() {
    ScreenTransition transition = ScreenTransitionSlide.init(1, ScreenTransitionSlide.RIGHT, false,
            Interpolation.bounceOut);
    game.setScreen(new MenuScreen(game), transition);
}

@Override
public void resize(int width, int height) {
    stage.getViewport().update(width, height, true);
}

@Override
public void show() {
    stage = new Stage(new StretchViewport(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT));
    rebuildStage();
}

@Override
public void hide() {
    stage.dispose();
    levelSkin.dispose();
}

@Override
public void pause() {
}

public String getCurrLevel() {
    return currLevel;
}

public void setCurrLevel(String currLevel) {
    this.currLevel = currLevel;
}

}

What I'm trying to achieve is for the initLevel() method in WorldController to receive currLevel and pass it to Level as shown

public class WorldController extends InputAdapter {

private static final String TAG = WorldController.class.getName();

public Level level;
public int lives;
public int coinScore, keyScore;

public CameraHelper cameraHelper;

private DirectedGame game;
private LevelScreen levScreen;

private Rectangle r1 = new Rectangle();
private Rectangle r2 = new Rectangle();

public WorldController(DirectedGame game) {
    this.game = game;
    init();
}

private void init() {
    cameraHelper = new CameraHelper();
    lives = Constants.LIVES_START;
    initLevel();
}

private void initLevel() {
    coinScore = 0;
    level = new Level(levScreen.getCurrLevel());
    cameraHelper.setTarget(level.player);
}

// more code

}

I keep getting a NPE error with this. I'm still new to java and libgdx, what I'd like to know is how I can pass the String containing the path to the level file from LevelSelect to WorldController and specifically to this line level = new Level(levScreen.getCurrLevel()); Thanks.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

In Java, every variable that is an object type (that is, any thing that isn't a primative type such as an int, float, boolean, etc.) is initialized to null. That means unless you store something in that variable via

 SomeObjectType variable = new SomeObjectType();
 //or
 SomeObjectType variable = otherVariableThatIsNotNull;

Then you will get a NullPointerException (NPE) whenever you call variable.anyFunction()

There may be more than one, but it looks like you have a guaranteed NPE in your WorldController class. You never give a value to your levScreen variable and you get a NPE when you call levScreen.getCurrLevel().

Either in WorldController's constructor or in the initLevel() function you need to pass in your levelScreen so that WorldController can store and access it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .