diff --git a/core/src/io/github/lonamiwebs/klooni/Klooni.java b/core/src/io/github/lonamiwebs/klooni/Klooni.java index fecdca1..fbb5e18 100644 --- a/core/src/io/github/lonamiwebs/klooni/Klooni.java +++ b/core/src/io/github/lonamiwebs/klooni/Klooni.java @@ -4,12 +4,14 @@ import com.badlogic.gdx.Application; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import io.github.lonamiwebs.klooni.screens.MainMenuScreen; +import io.github.lonamiwebs.klooni.screens.TransitionScreen; public class Klooni extends Game { @@ -82,6 +84,15 @@ public class Klooni extends Game { super.render(); } + // TransitionScreen will also dispose by default the previous screen + public void transitionTo(Screen screen) { + transitionTo(screen, true); + } + + public void transitionTo(Screen screen, boolean disposeAfter) { + setScreen(new TransitionScreen(this, getScreen(), screen, disposeAfter)); + } + //endregion //region Disposing diff --git a/core/src/io/github/lonamiwebs/klooni/screens/CustomizeScreen.java b/core/src/io/github/lonamiwebs/klooni/screens/CustomizeScreen.java index 8ff0549..3d7d92d 100644 --- a/core/src/io/github/lonamiwebs/klooni/screens/CustomizeScreen.java +++ b/core/src/io/github/lonamiwebs/klooni/screens/CustomizeScreen.java @@ -145,8 +145,7 @@ class CustomizeScreen implements Screen { //region Private methods private void goBack() { - CustomizeScreen.this.game.setScreen(lastScreen); - dispose(); + CustomizeScreen.this.game.transitionTo(lastScreen); } //endregion diff --git a/core/src/io/github/lonamiwebs/klooni/screens/MainMenuScreen.java b/core/src/io/github/lonamiwebs/klooni/screens/MainMenuScreen.java index 04ea472..9e9b542 100644 --- a/core/src/io/github/lonamiwebs/klooni/screens/MainMenuScreen.java +++ b/core/src/io/github/lonamiwebs/klooni/screens/MainMenuScreen.java @@ -46,9 +46,8 @@ public class MainMenuScreen extends InputListener implements Screen { 0, GameScreen.hasSavedData() ? "play_saved_texture" : "play_texture"); playButton.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - MainMenuScreen.this.game.setScreen( + MainMenuScreen.this.game.transitionTo( new GameScreen(MainMenuScreen.this.game, GameScreen.GAME_MODE_SCORE)); - dispose(); } }); table.add(playButton).colspan(3).fill().space(16); @@ -70,9 +69,8 @@ public class MainMenuScreen extends InputListener implements Screen { statsButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { - MainMenuScreen.this.game.setScreen( + MainMenuScreen.this.game.transitionTo( new GameScreen(MainMenuScreen.this.game, GameScreen.GAME_MODE_TIME)); - dispose(); } }); table.add(statsButton).space(16); @@ -81,8 +79,9 @@ public class MainMenuScreen extends InputListener implements Screen { final SoftButton paletteButton = new SoftButton(3, "palette_texture"); paletteButton.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - MainMenuScreen.this.game.setScreen(new CustomizeScreen(MainMenuScreen.this.game, MainMenuScreen.this.game.getScreen())); // Don't dispose because then it needs to take us to the previous screen + MainMenuScreen.this.game.transitionTo(new CustomizeScreen( + MainMenuScreen.this.game, MainMenuScreen.this.game.getScreen()), false); } }); table.add(paletteButton).space(16); diff --git a/core/src/io/github/lonamiwebs/klooni/screens/PauseMenuStage.java b/core/src/io/github/lonamiwebs/klooni/screens/PauseMenuStage.java index afb56d7..7881730 100644 --- a/core/src/io/github/lonamiwebs/klooni/screens/PauseMenuStage.java +++ b/core/src/io/github/lonamiwebs/klooni/screens/PauseMenuStage.java @@ -59,8 +59,7 @@ class PauseMenuStage extends Stage { homeButton.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - game.setScreen(new MainMenuScreen(game)); - dispose(); + game.transitionTo(new MainMenuScreen(game)); } }); @@ -72,8 +71,7 @@ class PauseMenuStage extends Stage { @Override public void changed(ChangeEvent event, Actor actor) { // false, don't load the saved game state; we do want to replay - game.setScreen(new GameScreen(game, gameMode, false)); - dispose(); + game.transitionTo(new GameScreen(game, gameMode, false)); } }); @@ -86,8 +84,8 @@ class PauseMenuStage extends Stage { paletteButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { - game.setScreen(new CustomizeScreen(game, game.getScreen())); // Don't dispose because then it needs to take us to the previous screen + game.transitionTo(new CustomizeScreen(game, game.getScreen()), false); } }); diff --git a/core/src/io/github/lonamiwebs/klooni/screens/TransitionScreen.java b/core/src/io/github/lonamiwebs/klooni/screens/TransitionScreen.java new file mode 100644 index 0000000..65a2474 --- /dev/null +++ b/core/src/io/github/lonamiwebs/klooni/screens/TransitionScreen.java @@ -0,0 +1,141 @@ +package io.github.lonamiwebs.klooni.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.FrameBuffer; + +import io.github.lonamiwebs.klooni.Klooni; + +public class TransitionScreen implements Screen { + + //region Members + + // Rendering + private FrameBuffer frameBuffer; + private TextureRegion bufferTexture; + private final SpriteBatch spriteBatch; + private float fadedElapsed; + private boolean fadingOut; + private int width, height; + + // From, to, and game to change the screen after the transition finishes + private final Screen fromScreen, toScreen; + private final Klooni game; + + // Should the previous screen be disposed afterwards? Not desirable + // if it was stored somewhere else, for example, to return to it later + private final boolean disposeAfter; + + //endregion + + //region Static variables + + // Time it takes to fade out and in, 0.15s (0.3s total) + private static final float FADE_INVERSE_DELAY = 1f / 0.15f; + + //endregion + + //region Constructor + + public TransitionScreen(Klooni game, Screen from, Screen to, boolean disposeAfter) { + this.disposeAfter = disposeAfter; + this.game = game; + fromScreen = from; + toScreen = to; + + spriteBatch = new SpriteBatch(); + } + + //endregion + + //region Rendering + + @Override + public void show() { + fadedElapsed = 0f; + fadingOut = true; + } + + @Override + public void render(float delta) { + // Black background since we're fading to black + Gdx.gl.glClearColor(0, 0, 0, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + // Render on another buffer so then we can set its opacity. This + // second buffer also would allow us to do more stuff, since then + // we can use a texture, which we could move across the screen. + frameBuffer.begin(); + + float opacity; + if (fadingOut) { + fromScreen.render(delta); + opacity = 1 - Math.min(fadedElapsed * FADE_INVERSE_DELAY, 1); + if (opacity == 0) { + fadedElapsed = 0; + fadingOut = false; + } + } + else { + toScreen.render(delta); + opacity = Math.min(fadedElapsed * FADE_INVERSE_DELAY, 1); + } + + frameBuffer.end(); + + // Render the faded texture + spriteBatch.begin(); + spriteBatch.setColor(1, 1, 1, opacity); + spriteBatch.draw(bufferTexture, 0, 0, width, height); + spriteBatch.end(); + fadedElapsed += delta; + + // We might have finished fading if the opacity is full + if (opacity == 1 && !fadingOut) { + game.setScreen(toScreen); + dispose(); + } + } + + @Override + public void resize(int width, int height) { + this.width = width; + this.height = height; + if (frameBuffer != null) + frameBuffer.dispose(); + + frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, width, height, false); + bufferTexture = new TextureRegion(frameBuffer.getColorBufferTexture()); + bufferTexture.flip(false, true); + } + + //endregion + + //region Disposing + + @Override + public void dispose() { + frameBuffer.dispose(); + if (disposeAfter) + fromScreen.dispose(); + } + + //endregion + + //region Unused methods + + @Override + public void pause() { } + + @Override + public void resume() { } + + @Override + public void hide() { } + + //endregion +}