Java tutorial
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); } }