LibGDX: как многократно показывать / скрывать всплывающее меню наложения на главном экране игры

Я делаю игру под названием Fuego Peligro (основанную на другом проекте LibGDX «Учебное пособие» Ninja Rabbit от nfantone, https://github.com/nfantone/ninja-rabbit ) в качестве моей диссертации на моем курсе BIT в моем университете, и я хочу, чтобы какое-то меню наложения отображалось / скрывалось на главном экране игры.

Всплывающее меню похоже на контрольную точку, которая отображает простую мини-игру типа викторины из основной платформерской игры. Он вызывается через метод Telegraph (handleMessage). Единственная проблема - когда сообщение повторяется, и если всплывающее окно было показано ранее, оно не хочет повторно показываться снова.

Все файлы и другие детали находятся здесь по этой ссылке: https://github.com/NinjaSiren/FuegoPeligro

Все файлы .java находятся здесь: https://github.com/NinjaSiren/FuegoPeligro/tree/master/core/src/com/mygdx/fuegopeligro

Вот класс Java, который вызывает все внутриигровые оверлеи для рендеринга: LevelGraphicsProcessor.java

public class LevelGraphicsProcessor implements GraphicsProcessor, Telegraph {
    private final LevelRenderer mapRenderer;
    private final GameOverOverlay gameOver;
    private final LevelEndOverlay levelEnd;
    private MultipleChoice multipleChoice;
    private FourPicsOneWord fourPicsOneWord;
    private LetterPuzzle letterPuzzle;
    private Wordscapes wordscapes;

    private boolean renderGameOver;
    private boolean renderLevelEnd;
    private boolean minicamSelection;
    private final CurrentPlayerStatus status;
    private final NinjaRabbit ninja;
    private final Entity entity;

    public LevelGraphicsProcessor(final AssetManager assets, final LevelRenderer mapRenderer,
                                  final FuegoPeligro game, final NinjaRabbit ninjaRabbit,
                                  final CurrentPlayerStatus player) {
        status = player;
        ninja = ninjaRabbit;
        if (ninjaRabbit == null) {
            throw new IllegalArgumentException("'character' cannot be null"); }
        this.entity = ninjaRabbit;

        gameOver = new GameOverOverlay(game.getBatch(), assets, game);
        levelEnd = new LevelEndOverlay(game.getBatch(), assets, game);
        multipleChoice = new MultipleChoice(assets, game, ninjaRabbit);
        fourPicsOneWord = new FourPicsOneWord(assets, game, ninjaRabbit);
        letterPuzzle = new LetterPuzzle(assets, game, ninjaRabbit);
        wordscapes = new Wordscapes(assets, game, ninjaRabbit);
        this.mapRenderer = mapRenderer;
        MessageManager.getInstance().addListeners(this, MessageType.GAME_OVER.code());
        MessageManager.getInstance().addListeners(this, MessageType.FINISH_LEVEL.code());
        MessageManager.getInstance().addListeners(this, MessageType.COLLECTED.code());
    }

    @Override
    public void update(final Entity character, final Camera camera) {
        mapRenderer.render((OrthographicCamera) camera);
    }

    /*
     * (non-Javadoc)
     *
     * @see com.mygdx.fuegopeligro.graphics.GraphicsProcessor#draw(com.mygdx.fuegopeligro.entity.Entity,
     * com.badlogic.gdx.graphics.g2d.Batch)
     */
    @Override
    public void draw(final Entity entity, final Batch batch) {
        mapRenderer.update();

        if (renderGameOver) {
            gameOver.render(Gdx.graphics.getDeltaTime());
        } else if (renderLevelEnd) {
            levelEnd.render(Gdx.graphics.getDeltaTime());
        } else if (minicamSelection) {
            multipleChoice.render(Gdx.graphics.getDeltaTime());
            wordscapes.render(Gdx.graphics.getDeltaTime());
            letterPuzzle.render(Gdx.graphics.getDeltaTime());
            fourPicsOneWord.render(Gdx.graphics.getDeltaTime());

            entity.changeState(NinjaRabbitState.IDLE);
            byte worldValue = status.getCurrentWorld();
            //short levelValue = status.getCurrentLevel();
            short mgValue = status.getMGValue();

            if (worldValue == 1) {
                //short easyValue = status.getEqaValue();
                if (mgValue == 1) {
                    multipleChoice.setVisible(true);
                    Gdx.input.setInputProcessor(multipleChoice.stage);
                    if (multipleChoice.enterAnswer.isPressed()) {
                        multipleChoice.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 2) {
                    wordscapes.setVisible(true);
                    Gdx.input.setInputProcessor(wordscapes.stage);
                    if (wordscapes.enterAnswer.isPressed()) {
                        wordscapes.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 3) {
                    letterPuzzle.setVisible(true);
                    Gdx.input.setInputProcessor(letterPuzzle.stage);
                    if (letterPuzzle.enterAnswer.isPressed()) {
                        letterPuzzle.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 4) {
                    fourPicsOneWord.setVisible(true);
                    Gdx.input.setInputProcessor(fourPicsOneWord.stage);
                    if (fourPicsOneWord.enterAnswer.isPressed()) {
                        fourPicsOneWord.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                }
            } else if (worldValue == 2) {
                //short hardValue = status.getHqaValue();
                if (mgValue == 1) {
                    multipleChoice.setVisible(true);
                    Gdx.input.setInputProcessor(multipleChoice.stage);
                    if (multipleChoice.enterAnswer.isPressed()) {
                        multipleChoice.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 2) {
                    wordscapes.setVisible(true);
                    Gdx.input.setInputProcessor(wordscapes.stage);
                    if (wordscapes.enterAnswer.isPressed()) {
                        wordscapes.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 3) {
                    letterPuzzle.setVisible(true);
                    Gdx.input.setInputProcessor(letterPuzzle.stage);
                    if (letterPuzzle.enterAnswer.isPressed()) {
                        letterPuzzle.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                } else if (mgValue == 4) {
                    fourPicsOneWord.setVisible(true);
                    Gdx.input.setInputProcessor(fourPicsOneWord.stage);
                    if (fourPicsOneWord.enterAnswer.isPressed()) {
                        fourPicsOneWord.setVisible(false);
                        Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
                    }
                }
            }
        }
    }

    @Override
    public boolean handleMessage(final Telegram msg) {
        renderGameOver = msg.message == MessageType.GAME_OVER.code();
        renderLevelEnd = msg.message == MessageType.FINISH_LEVEL.code();
        minicamSelection = msg.message == MessageType.COLLECTED.code();
        return true;
    }

    @Override
    public void resize(final int width, final int height) {
        gameOver.resize(width, height);
        levelEnd.resize(width, height);
        multipleChoice.resize(width, height);
        wordscapes.resize(width, height);
        letterPuzzle.resize(width, height);
        fourPicsOneWord.resize(width, height);
    }

    @Override
    public void dispose() {
        gameOver.dispose();
        levelEnd.dispose();
        multipleChoice.dispose();
        wordscapes.dispose();
        letterPuzzle.dispose();
        fourPicsOneWord.dispose();
    }
}

Вот одна из всплывающих мини-игр, которую я хочу показать при получении сообщения и скрыть при нажатии кнопки .: MultipleChoice.java

public class MultipleChoice implements Disposable {
    private static final String QUESTION_LABEL = "CHECKPOINT: MULTIPLE CHOICE";
    private static final String ENTER_ANSWER = "ENTER";
    private static final String HINT_ANSWER = "HINT";

    public final Stage stage;
    private final NinjaRabbit ninja;
    private final Label QuestionLabel;
    private final Label QuestionText;
    private final TextButton answer1;
    private final TextButton answer2;
    private final TextButton answer3;
    private final TextButton answer4;
    public final TextButton enterAnswer;
    private final TextButton enterHints;
    private final Table table;

    public MultipleChoice(final AssetManager assets, final FuegoPeligro game,
                          final NinjaRabbit ninjaRabbit) {
        stage = new Stage(new ScreenViewport(), game.getBatch());
        ninja = ninjaRabbit;

        Label.LabelStyle style = new Label.LabelStyle();
        AssetManager assetManager = new AssetManager();
        assetManager.load(Assets.GAME_UI_SKIN);
        assetManager.finishLoading();
        Skin skin = assetManager.get(Assets.GAME_UI_SKIN);

        style.fontColor = Color.WHITE;
        style.font = assets.get(Assets.HUD_FONT);
        QuestionLabel = new Label(QUESTION_LABEL, style);

        style.fontColor = Color.WHITE;
        style.font = assets.get(Assets.HUD_FONT);
        QuestionText = new Label("", style);

        answer1 = new TextButton("", skin);
        answer1.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });
        answer2 = new TextButton("", skin);
        answer2.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });
        answer3 = new TextButton("", skin);
        answer3.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });
        answer4 = new TextButton("", skin);
        answer4.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });

        // enter answer
        enterAnswer = new TextButton(ENTER_ANSWER, skin);
        enterAnswer.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });

        // enter hints
        enterHints = new TextButton(HINT_ANSWER, skin);
        enterHints.addListener(new ClickListener() {
            @Override
            public void clicked(final InputEvent event, final float x, final float y) {

            }
        });

        table = new Table();
        table.setFillParent(true);
        table.setDebug(true);

        table.add(QuestionLabel).expand(true, false).center();
        table.row().pad(20, 0, 0, 10);
        table.add(QuestionText).expand(true, false);
        table.row().pad(10, 0, 0, 20);
        table.add(answer1).expand(true, false);
        table.add(answer2).expand(true, false);
        table.row().pad(10, 0, 0, 20);
        table.add(answer3).expand(true, false);
        table.add(answer4).expand(true, false);
        table.row().pad(10, 0, 0, 20);
        table.add(enterAnswer).expand(true, false);
        table.add(enterHints).expand(true, false);
        table.setVisible(false);

        stage.addActor(table);
        stage.setKeyboardFocus(table);
    }

    public void render(final float delta) {
        Gdx.gl20.glEnable(GL20.GL_BLEND);
        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

        Gdx.gl20.glDisable(GL20.GL_BLEND);
        stage.getBatch().end();
        stage.act(delta);
        stage.draw();
        stage.getBatch().begin();
    }

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

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

    public void setVisible(boolean value) {
        table.setVisible(value);
    }
}

Всего 1 ответ


При использовании LibGDX стандартным соглашением для пользовательского интерфейса является использование Scene2D, а объекты Scene2D должны содержаться в рабочей области - для использования окна, такого как наложение, можно использовать специальную производную Table : класс Window .

Любой Actor вы хотите видеть в оверлее, может быть добавлен в экземпляр Window и помещен в него так же, как его собственная Stage или Table , а Window может быть добавлено в сцену и удалено из сцены - даже постепенно исчезает с помощью fade(In/Out) (вместо непосредственного добавления и удаления, как в следующем примере):

public class ExampleClass {

    ...
    private Stage stage = new Stage(...);
    private Window popUp = new Window("...");
    private TextButton windowButton1 = ..., windowButton2 = ...;
    ...

    public ExampleClass() {
        ...

        Gdx.setInputProcessor(stage); //Allows input to Scene2D components - important!
        //Register click listeners to buttons to close window when clicked
        windowButton1.addListener(new CloseButtonListener(this));
        windowButton2.addListener(new CloseButtonListener(this));
        ...
        //Add buttons to window
        popUp.add(windowButton1);
        popUp.add(windowButton2);
        ...
    }

    //Run when message is received
    public void messageReceived() {
        ...
        stage.add(popUp); //Add window to stage you want to overlay
        ...
    }

    ...

    public Stage getStage() {
        return stage;
    }

    public Window getPopUp() {
        return popUp;
    }

    ...
}

class CloseButtonListener implements ClickListener { //Inner class for handling button clicks, multiple can be created for different button types with different logic when window is closed.

    private ExampleClass exampleInstance;

    public CloseButtonListener(ExampleClass exampleInstance) {
        this.exampleInstance = exampleInstance;
    }

    //Remove the window from the stage when the button is clicked, handles any other logic too depending on button.
    @Override
    public void clicked(InputEvent event, float x, float y) {
        ...
        exampleInstance.getStage().removeActor(exampleInstance.getPopUp());
        ...
    }

}


Есть идеи?

10000