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
\$\begingroup\$

In Java, every variable that is an object type (i.e any that are not 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 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.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.