com.twojeremys.merge.screen.MainMenuScreen.java Source code

Java tutorial

Introduction

Here is the source code for com.twojeremys.merge.screen.MainMenuScreen.java

Source

package com.twojeremys.merge.screen;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextField;
import com.badlogic.gdx.scenes.scene2d.ui.Window;
import com.twojeremys.merge.GameState;
import com.twojeremys.merge.GameStateManager;
import com.twojeremys.merge.Merge;

import java.util.ArrayDeque;
import java.util.Queue;

public class MainMenuScreen implements Screen {

    private static final String TAG = MainMenuScreen.class.getSimpleName();

    protected final Merge game;

    private OrthographicCamera camera;

    private Texture background;

    //Menu attempt using scene2d ui items
    private Table table;
    private Stage stage;
    private TextButton newGameButton;
    private TextButton googlePlayButton;
    private TextButton exitGameButton;
    private TextButton loadGameButton;
    private InputListener googlePlaySignInListen;
    private InputListener googlePlaySignOutListen;
    private Skin skin;

    private Dialog dialog;

    private Label label;

    private TextField textField;

    private float forcedWait = 0f;

    private Queue<String> loadingText;

    //Just playing
    //AudioDevice playbackDevice;

    private boolean assetsLoaded;
    private boolean allDoneLoading;

    public MainMenuScreen(final Merge inMerge) {
        game = inMerge;

        camera = new OrthographicCamera();
        camera.setToOrtho(false, Merge.SCREEN_WIDTH, Merge.SCREEN_HEIGHT);

        game.resetWorld();
    }

    @Override
    public void show() {
        assetsLoaded = false;
        allDoneLoading = false;

        stage = new Stage();

        // Allow the stage to take and process the input, like click or touch.
        Gdx.input.setInputProcessor(stage);

        //Disable the "Exit app when back pressed"
        Gdx.input.setCatchBackKey(true);

        //Load the background texture
        background = new Texture(Gdx.files.internal("data/textures/mainmenu.png"));

        //Login to Google play if preferences show user has already done so previously
        if (this.game.getPrefs().contains("gplayautosignin")
                && this.game.getPrefs().getBoolean("gplayautosignin")) {
            this.game.getGoogleServices().loginGPGS();
        }

        loadingText = new ArrayDeque<String>();
        loadingText.add(".");
        loadingText.add("..");
        loadingText.add("...");
        loadingText.add("....");
        loadingText.add(".....");
        loadingText.add("......");
        loadingText.add(".......");
    }

    @Override
    public void render(float delta) {
        update(delta);

        if (!assetsLoaded) {
            loadAssets(delta);
        }

        if (!allDoneLoading) {
            loadingText.add(loadingText.remove());
        }

        draw(delta, assetsLoaded);

    }

    //Custom method based on XNA style, to extract "update" code out of render
    private void update(float delta) {
        camera.update();
        game.batch.setProjectionMatrix(camera.combined);

        // Allow the stage to execute all its code
        stage.act();
    }

    //Custom method based on XNA style, to extract the "drawing" code out of render
    private void draw(float delta, boolean assetsLoaded) {

        //Clear the screen and draw the background
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        game.batch.begin();
        game.batch.draw(background, 0, 0);

        //TODO: Potential State progress mechanism
        //10 = Load assets
        //11 = Loading Assets Failed
        //19 = Loading Assets Complete

        //20 = Sign into Google Play Services
        //21 = Signing in
        //25 = Failed to Sign in
        //28 = No sign in, not associated/logged in
        //29 = Signed in (Connected)

        //30 = Load save game
        //31 = Loading Game Save
        //35 = Game save load failed - Game does not exist
        //36 = Game save load failed - Connection or load error
        //39 = Game Save Loaded successfully

        //40 = Display menu system

        if (!allDoneLoading) {
            //10 = Load Assets
            if (!assetsLoaded) {
                game.font.draw(game.batch, "Loading Assets" + loadingText.peek(), Merge.SCREEN_WIDTH / 2,
                        Merge.SCREEN_HEIGHT / 2);
            }

            //Key does not exist
            //or
            //Key exists, and value is false
            if ((!this.game.getPrefs().contains("gplayautosignin"))
                    || (this.game.getPrefs().contains("gplayautosignin")
                            && !this.game.getPrefs().getBoolean("gplayautosignin"))) {
                if (assetsLoaded) {
                    setupButtons(); //Load and create all objects needed for the menu
                    allDoneLoading = true; //NOthing else to load but assets because we are not using google play
                    System.out.println("All done loading - NoAndroid");
                }
            } else {
                int result = game.getGoogleServices().getCombinedLoadingState();
                //TODO: Decide if this should be 2 lines (Loading Assets \n Connecting to GOogle Play) or chained displayed and loaded messages (Succession/not parallel)
                switch (game.getGoogleServices().getCombinedLoadingState()) {
                case 21:
                    game.font.draw(game.batch, "Connecting to Google Play" + loadingText.peek(),
                            Merge.SCREEN_WIDTH / 2, (Merge.SCREEN_HEIGHT / 2) + game.font.getLineHeight() + 2);
                    break;
                case 29:
                    game.getGoogleServices().loadSnapshot();
                    System.out.println("Load snap shot - case 29");
                    break;
                case 31:
                    game.font.draw(game.batch, "Loading Save" + loadingText.peek(), Merge.SCREEN_WIDTH / 2,
                            (Merge.SCREEN_HEIGHT / 2) + game.font.getLineHeight() + 2);
                    break;
                case 35:
                    //TODO: What do we do when there was an error loading the save file?
                    break;
                case 36:
                    //TODO: What do we do when there was an error finding the load file?
                    break;
                case 39:
                    //game.getGoogleServices().setState();    //TODO: Find a way to do this inside the loadSnapshot async
                    setupButtons(); //Load and create all objects needed for the menu
                    allDoneLoading = true;
                    System.out.println("All done loading - case 39");

                    //GameState gs = game.getGoogleServices().getGameSave();
                    break;
                }
            }
        }
        game.batch.end();

        //Draw the stage (Menu)
        if (assetsLoaded) {
            stage.draw();
        }
    }

    private void loadAssets(float delta) {
        forcedWait += delta;

        if (Merge.assetManager.update() && forcedWait >= 5f) {
            assetsLoaded = true;

            //TODO: Figure out real music to use

            //http://incompetech.com/music/royalty-free/index.html?isrc=USUAN1100052
            // Attribution:
            /*
            Copy and paste the following text into your video's credits:
            "That's a Wrap" Kevin MacLeod (incompetech.com)
                Licensed under Creative Commons: By Attribution 3.0
            http://creativecommons.org/licenses/by/3.0/
            */
            game.setMusic((Music) Merge.assetManager.get("data/sounds/Thats_a_Wrap.mp3"));
            game.startMusic(1.0f);
        }
    }

    @Override
    public void resize(int width, int height) {
        System.out.println("MainMenuScreen.resize() method called");
    }

    @Override
    public void pause() {
        System.out.println("MainMenuScreen.pause() method called");
    }

    @Override
    public void resume() {
        System.out.println("MainMenuScreen.resume() method called");
    }

    @Override
    public void hide() {
        System.out.println("MainMenuScreen.hide() method called");
    }

    @Override
    public void dispose() {
        System.out.println("MainMenuScreen.dispose() method called");
        background.dispose();

        //Dispose of all the MENU items
        skin.dispose();
        stage.dispose();
    }

    //Custom Methods for "Main Menu"

    private void setupButtons() {

        /*
        *   Lets create a menu to display choices to the user
        */

        skin = new Skin(Gdx.files.internal("ui/skin/uiskin.json"));

        // Create the table and add the "skin" to it
        table = new Table(skin);

        GameState androidGameState = null;
        GameState desktopGameState = null;

        if (GameStateManager.saveExists()) {
            desktopGameState = GameStateManager.loadState();
        }

        if (this.game.getPrefs().contains("gplayautosignin")
                && this.game.getPrefs().getBoolean("gplayautosignin")) {
            androidGameState = game.getGoogleServices().getGameSave();
        }

        final boolean showSelectSaveDialog;
        final GameState tmpGameState;
        // Check to see if we need to compare the android and local saves
        if (androidGameState != null && desktopGameState != null) {
            showSelectSaveDialog = true;
            tmpGameState = androidGameState;
        } else {
            if (androidGameState != null) {
                tmpGameState = androidGameState;
            } else {
                tmpGameState = desktopGameState;
            }
            showSelectSaveDialog = true;
        }

        if (tmpGameState != null) {

            // Create a new row so the buttons are not side-by-side
            table.row();

            // Create the Load Game Button, pass in "loadgame" to the listener
            loadGameButton = new TextButton("Resume", skin, "default");

            //loadGameButton.addListener(new DefaultMenuActionListener("loadgame"));
            loadGameButton.addListener(new InputListener() {

                public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                    return true;
                }

                //This only fires when the button is first let up
                @Override
                public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                    if (showSelectSaveDialog) {
                        selectSavePopup();
                    } else {
                        dispose();
                        game.setScreen(new GameScreen(game, tmpGameState));
                    }
                }
            });

            // Add the load game button to the table
            table.add(loadGameButton).size(150f, 40f).uniform().spaceBottom(10);
        }

        // Add another row
        table.row();

        /* *******************************************
         *  Create the buttons and add them to the table
         ***********************************************/

        // Create the new game button, and pass in the word "newGame" to a listener which is called on the DOWN/UP events
        newGameButton = new TextButton("New Game", skin, "default");

        newGameButton.addListener(new InputListener() {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                return true;
            }

            //This only fires when the button is first let up
            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                dispose();
                game.setScreen(new GameScreen(game));
            }
        });

        // add the start-game button to the table
        //  Using the returned [CELL] object, change that cell's size, make it uniform, and add space below it.
        //  - I think this is harder because we have to guess the width, vs just using the padding.
        //  - However, this could be beneficial for creating static/standard width buttons regardless of content (text)
        //  - I'm oldschool I suppose and would rather create an instance of Cell, and call size, uniform, and spaceBottom separately.
        table.add(newGameButton).size(150f, 40f).uniform().spaceBottom(10);

        // Add another row to the table
        table.row();

        //TODO maybe change all this gplay stuff to be an icon in one of the corners? icon packs are here: https://developers.google.com/games/services/downloads/graphics
        googlePlaySignInListen = new InputListener() {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                return true;
            }

            //This only fires when the button is first let up
            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                game.getGoogleServices().loginGPGS();
                googlePlayButton.setText("Google Play - sign out");
                googlePlayButton.clearListeners();
                game.getPrefs().putBoolean("gplayautosignin", true).flush();
                googlePlayButton.addListener(googlePlaySignOutListen);
            }
        };

        googlePlaySignOutListen = new InputListener() {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                return true;
            }

            //This only fires when the button is first let up
            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                game.getGoogleServices().logoutGPGS();
                googlePlayButton.setText("Google Play - sign in");
                googlePlayButton.clearListeners();
                game.getPrefs().putBoolean("gplayautosignin", false).flush();
                googlePlayButton.addListener(googlePlaySignInListen);
            }
        };

        // Create the google play sign-in button
        if (this.game.getPrefs().contains("gplayautosignin")
                && this.game.getPrefs().getBoolean("gplayautosignin")) {
            googlePlayButton = new TextButton("Google Play - sign out", skin, "default");
            googlePlayButton.addListener(googlePlaySignOutListen);
        } else {
            googlePlayButton = new TextButton("Google Play - sign in", skin, "default");
            googlePlayButton.addListener(googlePlaySignInListen);
        }

        // Add some padding all the way around the button this time
        googlePlayButton.pad(10);

        // Add the extGameButton to the table so it is active/displayed
        table.add(googlePlayButton).size(150f, 40f).uniform().spaceBottom(10);

        // Add another row to the table
        table.row();

        // Create another button using the same style, passing in the word "extiGame" to the listener for handling later
        exitGameButton = new TextButton("Exit", skin, "default");
        exitGameButton.addListener(new InputListener() {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                return true;
            }

            //This only fires when the button is first let up
            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                Gdx.app.debug(TAG, "exit button pressed. bye now.");
                Gdx.app.exit();
            }
        });

        // Add some padding all the way around the button this time
        exitGameButton.pad(10);

        // Add the extGameButton to the table so it is active/displayed
        table.add(exitGameButton).size(150f, 40f).uniform().spaceBottom(10);

        //Set the table off the screen, to use actions to add "tween" flare
        table.setPosition(Gdx.graphics.getWidth() / 2, 0);

        //        MoveToAction bounceAction = new MoveToAction();
        //        bounceAction.setInterpolation(Interpolation.swing);
        //        bounceAction.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
        //        bounceAction.setDuration(0.5f);
        //        table.addAction(bounceAction);

        //Make the menu move up from off the screen with flare and "tween" by adding Interpolation.swing
        table.addAction(Actions.moveTo(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0.5f,
                Interpolation.swing));

        // add the table onto the stage
        stage.addActor(table);
    }

    private void selectSavePopup() {
        Window w = new Window("My Fancy Window", skin, "default");

        w.setMovable(false);
        w.setKeepWithinStage(true);
        w.setResizable(false);
        w.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
        w.setModal(true);

        w.getTitleTable().add(new TextButton("X", skin)).height(w.getPadTop());

        w.add("My Fancy Lable");

        //Create Cloud Save label details
        //Labels should have listeners that pass that GameState to GameScreen.

        //  Add padding

        //Create Local Save label details

        // Add cancel button

        w.pack();

        stage.addActor(w);
    }

}