在使用Libgdx的屏幕时,如何重复使用代码

7

从我阅读其他人编写不同屏幕代码的经验来看,您需要创建一个主处理程序类,并为每个屏幕创建一个新类。

让我困惑的是,每当您创建新屏幕时,都必须重新定义要呈现的所有内容,例如SpriteBatch、sprites、fonts等。是否有任何方法可以在所有屏幕中重用这些东西?我的意思是,如果我有10个屏幕,想在每个屏幕上绘制文本。难道为所有10个屏幕类创建一个新的BitmapFont真的是良好的编程实践吗?

1个回答

11
我创建了一个抽象的屏幕类,其中包含所有屏幕所需的通用对象,我的每个屏幕都是这个抽象类的扩展。代码如下:

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();
    }
}

当我想创建一个新的类时,我只需要扩展抽象屏幕并添加所需内容。例如,我有一个基本的积分屏幕,我只需要创建组件,但抽象屏幕会绘制它:

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();
    }
}

我还有一个单独的类来处理所有屏幕的输入,其特定目的是处理不同屏幕上返回按钮的工作方式。而这个输入处理程序类是在抽象类中创建的。

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;
    }

}

如果解决方案可行,您可以通过点击票旁边的勾号来接受答案。谢谢。 - Steven Trigg
1
+1。解释得很好,形式也很良好。只有一件事@user3335152:您说您想在每个屏幕类中使用BitMapFont。我建议使用一个Assets类,它内部使用AssetManager工作。在那里,您可以存储BitMapFont(由AssetManager在启动时加载),并调用Assets.getFont()等。只是一个想法。 - Robert P
1
然而让我困惑的是,即使已经创建了一个类的实例(比如在后台),你仍然会创建一个新的实例?这是好的做法吗? - JohnyTex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接