From what I understand when reading other peoples code on how to make different screens. You do a main handler class sort of... And then create a new class for each screen.
The thing that confuses me is that whenever you create a new screen, you have to redefine everything that's going to be rendered, like SpriteBatch, sprites, fonts, etc. Is there any way to reuse these kind of things in all screens? I mean, if I have 10 screens, and want to be able to draw text on every screen. Is it really good programming practice to make a new BitmapFont for all 10 screen classes?
Open Source: libGDX is licensed under Apache 2.0 and maintained by the community, so you can take a look under the hood and see how everything works.
It's free and royalty-free, which is good unlike Unity, and it's on Java so it's relatively fast.
I've created an Abstract Screen class that contains all the common objects for a screen, every one of my screens extend this abstract class. And that looks like this:
public abstract class AbstractScreen implements Screen {
protected final Game game;
protected InputMultiplexer multiInputProcessor;
protected ScreenInputHandler screenInputHandler;
protected Stage uiStage;
protected Skin uiSkin;
public AbstractScreen(Game game) {
this.game = game;
this.uiStage = new Stage();
this.uiSkin = new Skin();
this.screenInputHandler = new ScreenInputHandler(game);
this.multiInputProcessor = new InputMultiplexer();
multiInputProcessor.addProcessor(uiStage);
multiInputProcessor.addProcessor(screenInputHandler);
Gdx.input.setInputProcessor(multiInputProcessor);
}
private static NinePatch processNinePatchFile(String fname) {
final Texture t = new Texture(Gdx.files.internal(fname));
final int width = t.getWidth() - 2;
final int height = t.getHeight() - 2;
return new NinePatch(new TextureRegion(t, 1, 1, width, height), 3, 3, 3, 3);
}
@Override
public void render (float delta) {
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
uiStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
uiStage.draw();
Table.drawDebug(uiStage);
}
@Override
public void resize (int width, int height) {
}
@Override
public void show() {
}
@Override
public void hide() {
dispose();
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void dispose() {
uiStage.dispose();
uiSkin.dispose();
}
}
When I want to create a new class I just extend the abstract screen and add what I need. For example I have a basic credits screen, I just need to create the components but the abstract screen draws it:
public class CreditsScreen extends AbstractScreen {
public CreditsScreen(final Game game) {
super(game);
// Generate a 1x1 white texture and store it in the skin named "white".
Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fill();
uiSkin.add("white", new Texture(pixmap));
// Store the default libgdx font under the name "default".
BitmapFont buttonFont = new BitmapFont();
buttonFont.scale(scale);
uiSkin.add("default", buttonFont);
// Configure a TextButtonStyle and name it "default". Skin resources are stored by type, so this doesn't overwrite the font.
TextButtonStyle textButtonStyle = new TextButtonStyle();
textButtonStyle.up = uiSkin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.down = uiSkin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.checked = uiSkin.newDrawable("white", Color.BLUE);
textButtonStyle.over = uiSkin.newDrawable("white", Color.LIGHT_GRAY);
textButtonStyle.font = uiSkin.getFont("default");
uiSkin.add("default", textButtonStyle);
// Create a table that fills the screen. Everything else will go inside this table.
Table table = new Table();
table.setFillParent(true);
uiStage.addActor(table);
table.debug(); // turn on all debug lines (table, cell, and widget)
table.debugTable(); // turn on only table lines
// Label
BitmapFont labelFont = new BitmapFont();
labelFont.scale(scale);
LabelStyle labelStyle = new LabelStyle(labelFont, Color.BLUE);
uiSkin.add("presents", labelStyle);
final Label myName = new Label("Credits and all that stuff", uiSkin, "presents");
table.add(myName).expand().center();
}
}
I also have a single class that handles the input for all the screens, the specific purpose for this is to handle how the back button works around the different screens. And this input handler class is created in the abstract class.
public class ScreenInputHandler implements InputProcessor {
private final Game game;
public ScreenInputHandler(Game game) {
this.game = game;
}
@Override
public boolean keyDown(int keycode) {
if(keycode == Keys.BACK || keycode == Keys.BACKSPACE){
if (game.getScreen() instanceof MainMenuScreen) {
Gdx.app.exit();
}
if (game.getScreen() instanceof GameScreen) {
World.getInstance().togglePause(false);
}
if (game.getScreen() instanceof CreditsScreen) {
game.setScreen(new MainMenuScreen(game));
}
}
return false;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With