libGDX - Simple Fade transition between Screens?
<p>I've been looking for days for an easy way to make a simple fade out-fade in transition between game screens implementing <code>Screen</code>. After a certain action I'm calling the <code>game.setScreen</code> method, but I want a transition in between.
I do not use stages and actors. </p>

<p>Should I make <code>stages</code> and make transitions with <code>actions</code> or is there an easier way with for example TweenEngine?</p>

<p>If I should use stages, how do I turn my normal render method into <code>stage.draw</code>? Would it be hard to convert all my render methods into <code>stage</code> with <code>actors</code>? Can you make your whole render method into a <code>stage.draw</code> to use <code>actions</code> in order to fade the <code>Screen</code> out? It doesn't matter if the solution is silly or inefficient, as long as is works.</p>

<p>Thanks</p>

<p><strong>Edit: My complete <code>Game class</code></strong>. There may be thousands of weird things in here. Forgive me as it is my first ever libGDX project.</p>

<pre><code>package com.samuel.kiwi;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.samuel.kiwi.states.MenuState;

public class Kiwi extends Game {

    private Sound point;
    private Sound select;
    private Sound die;
    private Music chirp;

    private Actor fadeActor = new Actor();
    private ShapeRenderer fadeRenderer;


    public SpriteBatch batch;
    public static BitmapFont font;
    public static final int WIDTH = 480;
    public static final int HEIGHT = 800;

    private int currentHighscore;
    private Preferences highscore;

    private int currentTotalScore;
    private Preferences totalScore;

    private int currentDeaths;
    private Preferences deaths;

    private boolean soundOn;
    private Preferences sound;


    Viewport viewport;
    Viewport viewportFont;

    private boolean currentTutMode;
    private Preferences tut;

    public static final String TITLE = "Kiwi";
    private OrthographicCamera cam;

    public static OrthographicCamera fontCam;

    private float aspectRatio;


    @Override
    public void create() {


        batch = new SpriteBatch();

        fontCam = new OrthographicCamera();

        aspectRatio = (float) Gdx.graphics.getHeight() / Gdx.graphics.getWidth();

        cam = new OrthographicCamera();

        viewport = new ExtendViewport((WIDTH / 4) * aspectRatio, HEIGHT / 2, cam);
        viewportFont = new ExtendViewport((WIDTH) * aspectRatio, HEIGHT * 2, fontCam);
        viewport.apply();
        viewportFont.apply();
        cam.position.set(WIDTH / 4, HEIGHT / 4, 0);
        fontCam.position.set(WIDTH, HEIGHT, 0);


        initFonts();

        highscore = Gdx.app.getPreferences("highscore"); //highscore preferencen
        currentHighscore = highscore.getInteger("currentHighscore", 0);

        totalScore = Gdx.app.getPreferences("total_score"); //total score
        currentTotalScore = totalScore.getInteger("totalScore", 0);

        deaths = Gdx.app.getPreferences("deaths");
        currentDeaths = deaths.getInteger("currentDeaths", 0);

        tut = Gdx.app.getPreferences("is tutorial on");
        currentTutMode = tut.getBoolean("currentTutMode", true);

        sound = Gdx.app.getPreferences("sound");
        soundOn = sound.getBoolean("currentSoundMode", true);

        point = Gdx.audio.newSound(Gdx.files.internal("sounds/point.wav"));
        select = Gdx.audio.newSound(Gdx.files.internal("sounds/select.wav"));
        die = Gdx.audio.newSound(Gdx.files.internal("sounds/die.wav"));


        Gdx.gl.glClearColor(0, 0, 0, 1);


        fadeRenderer = new ShapeRenderer(8);


        chirp = Gdx.audio.newMusic(Gdx.files.internal("sounds/chirp.wav"));
        chirp.setLooping(true);
        chirp.setVolume(0);
        chirp.play();
        setScreen(new MenuState(this, cam)); //ändra till splash
    }

    @Override
    public void render() {

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        super.render();

        cam.update();
        fontCam.update();
        fadeActor.act(Gdx.graphics.getDeltaTime());
        float alpha = fadeActor.getColor().a;
        if (alpha != 0) {
            fadeRenderer.begin(ShapeRenderer.ShapeType.Filled);
            fadeRenderer.setColor(0, 0, 0, alpha);
            System.out.println("alpha: " + alpha); //shows the alpha becoming less and less and then more an more
            fadeRenderer.rect(-1, -1, 2, 2); //full screen rect w/ identity matrix
            fadeRenderer.end();
        }


    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height);
        viewportFont.update(width, height);
        cam.position.set(WIDTH / 4, HEIGHT / 4, 0);
        fontCam.position.set(WIDTH, HEIGHT, 0);

    }


    public void initFonts() {

        FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/Minecraft.ttf"));
        FreeTypeFontGenerator.FreeTypeFontParameter params = new FreeTypeFontGenerator.FreeTypeFontParameter();
        params.characters = "0123456789-.";
        params.size = 80;
        params.color.set(254f / 255f, 208f / 255f, 0, 1f);
        params.shadowColor.set(0 / 255f, 0 / 255f, 0, 0.5f);
        params.shadowOffsetY = 8;
        font = generator.generateFont(params);

        generator.dispose();

    }

    @Override
    public void dispose() {
        super.dispose();
        batch.dispose();
        font.dispose();
        select.dispose();
        point.dispose();
        chirp.dispose();
        die.dispose();
        fadeRenderer.dispose();


    }


    public void setScreenWithFade(final Screen screen, float duration) {
        fadeActor.clearActions();
        fadeActor.setColor(Color.CLEAR);
        fadeActor.addAction(Actions.sequence(
                Actions.color(Color.BLACK, duration / 2f, Interpolation.fade),
                Actions.run(new Runnable() {
                    public void run() {
                        setScreen(screen);
                    }
                }),
                Actions.color(Color.CLEAR, duration / 2f, Interpolation.fade)
        ));
    }


    public void setCurrentHighscore(int currentHighscore) {
        this.currentHighscore = currentHighscore;
    }

    public Preferences getHighscore() {
        return highscore;
    }


    public void setCurrentTotalScore(int currentTotalScore) {
        this.currentTotalScore = currentTotalScore;
    }

    public Preferences getTotalScore() {
        return totalScore;
    }

    public boolean isCurrentTutMode() {
        return currentTutMode;
    }

    public void setCurrentTutMode(boolean currentTutMode) {
        this.currentTutMode = currentTutMode;
    }

    public Preferences getTut() {
        return tut;
    }


    public Sound getPoint() {
        return point;
    }

    public Sound getSelect() {
        return select;
    }

    public Sound getDie() {
        return die;
    }

    public Music getChirp() {
        return chirp;
    }

    public Preferences getDeaths() {
        return deaths;
    }

    public void setSoundOn(boolean soundOn) {

        sound.putBoolean("currentSoundMode", soundOn);
        sound.putBoolean("soundOn", soundOn);
        sound.flush();

    }

    public Preferences getSound() {
        return sound;
    }

    public boolean isSoundOn() {
        return sound.getBoolean("currentSoundMode", true);
    }

    public void setCurrentDeaths(int currentDeaths) {
        this.currentDeaths = currentDeaths;
    }
}
</code></pre>

<p><strong>Edit 2: My <code>MenuState Screen</code></strong></p>

<pre><code>package com.samuel.kiwi.states;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector3;
import com.samuel.kiwi.Kiwi;

/**
 * Created by Samuel on 10/2/2016.
 */

public class MenuState extends InputAdapter implements Screen {

    private Texture bg;
    private Texture playBtn;
    private Texture playBtnDown;

    private Texture gPlayBtn;
    private Texture gPlayBtnDown;

    private Texture settingsBtn;
    private Texture settingsBtnDown;

    private boolean updatePos;

    private Kiwi game;

    private Texture kiwiLogo;
    private Vector3 kiwiLogoPos;
    private Vector3 kiwiLogoVel;

    private Vector3 touchPos;

    private boolean isTouchPlay;
    private boolean isTouchReleased;

    private boolean isGDown;
    private boolean isGReleased;

    private boolean isSettingsDown;
    private boolean isSettingsReleased;

    private OrthographicCamera cam;
    private boolean handleInput;


    public MenuState(final Kiwi game, OrthographicCamera cam) {

        this.game = game;
        this.cam = cam;

        kiwiLogo = new Texture("pics/menu/kiwiLogo.png");
        bg = new Texture("pics/bg.png");
        playBtn = new Texture("pics/menu/play_button.png");
        playBtnDown = new Texture("pics/menu/play_button_down.png");

        gPlayBtn = new Texture("pics/menu/g_play_button.png");
        gPlayBtnDown = new Texture("pics/menu/g_play_button_down.png");

        settingsBtn = new Texture("pics/menu/settings_button.png");
        settingsBtnDown = new Texture("pics/menu/settings_button_down.png");
    }


    public void handleInput() {


        if (isTouchReleased &amp;&amp; isTouchPlay) {

            Gdx.input.setInputProcessor(null);
            game.setScreenWithFade(new PlayState(game, cam), 5);
            handleInput = false;
        }

        if (isGReleased) {
            //glöm inte disposa... eller?
            //google playa dude


        }

        if (isSettingsReleased &amp;&amp; isSettingsDown) {

            Gdx.input.setInputProcessor(null);
            game.setScreenWithFade(new SettingsState(game, cam), 5);
            handleInput = false;

        }


    }


    public void update(float delta) {
        if (handleInput)
            handleInput();
        if (updatePos) {
            if (kiwiLogoPos.y &lt; cam.position.y + 30)
                kiwiLogoVel.add(0, 3, 0);
            else
                kiwiLogoVel.add(0, -3, 0);
            kiwiLogoVel.scl(delta);
            kiwiLogoPos.add(0, kiwiLogoVel.y, 0);

            kiwiLogoVel.scl(1 / delta);

        }
    }


    @Override
    public void show() {
        handleInput = true;
        updatePos = true;
        if (game.isSoundOn())
            game.getChirp().setVolume(1);
        else
            game.getChirp().setVolume(0);
        Gdx.input.setInputProcessor(this);
        kiwiLogoPos = new Vector3(cam.position.x - kiwiLogo.getWidth(), cam.position.y + 25, 0);
        kiwiLogoVel = new Vector3(0, 0, 0);

        isTouchPlay = false;
        touchPos = new Vector3();


    }

    @Override
    public void render(float delta) {
        update(delta);
        game.batch.begin();
        game.batch.setProjectionMatrix(cam.combined);

        game.batch.draw(bg, cam.position.x - cam.viewportWidth / 2, cam.position.y - cam.viewportHeight / 2, cam.viewportWidth, cam.viewportHeight);

        game.batch.draw(kiwiLogo, kiwiLogoPos.x, kiwiLogoPos.y, kiwiLogo.getWidth() * 2, kiwiLogo.getHeight() * 2);


        if (!isTouchPlay) {
            game.batch.draw(playBtn, cam.position.x - playBtn.getWidth(), cam.position.y - 100, playBtn.getWidth() * 2, playBtn.getHeight() * 2);
        } else {

            game.batch.draw(playBtnDown, cam.position.x - playBtn.getWidth(), cam.position.y - 100, playBtn.getWidth() * 2, playBtn.getHeight() * 2);
        }

        if (!isGDown) {

            game.batch.draw(gPlayBtn, cam.position.x - playBtn.getWidth(), cam.position.y - gPlayBtn.getHeight() * 2 - 112, gPlayBtn.getWidth() * 2, gPlayBtn.getHeight() * 2);
        } else {

            game.batch.draw(gPlayBtnDown, cam.position.x - playBtn.getWidth(), cam.position.y - gPlayBtn.getHeight() * 2 - 112, gPlayBtn.getWidth() * 2, gPlayBtn.getHeight() * 2);
        }
        if (!isSettingsDown) {

            game.batch.draw(settingsBtn, cam.position.x + playBtn.getWidth() - settingsBtn.getWidth() * 2, cam.position.y - gPlayBtn.getHeight() * 2 - 112, gPlayBtn.getWidth() * 2, gPlayBtn.getHeight() * 2);
        } else {

            game.batch.draw(settingsBtnDown, cam.position.x + playBtn.getWidth() - settingsBtn.getWidth() * 2, cam.position.y - gPlayBtn.getHeight() * 2 - 112, gPlayBtn.getWidth() * 2, gPlayBtn.getHeight() * 2);
        }

        game.batch.end();


    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void pause() {


    }

    @Override
    public void resume() {
    }

    @Override
    public void hide() {

        dispose();
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        cam.unproject(touchPos.set(screenX, screenY, 0));
        //gobutton
        if (touchPos.x &gt; cam.position.x - playBtn.getWidth() &amp;&amp; touchPos.x &lt; cam.position.x + playBtn.getWidth()
                &amp;&amp; touchPos.y &lt; cam.position.y - 100 + playBtn.getHeight() * 2 &amp;&amp; touchPos.y &gt; cam.position.y - 100) {
            isTouchPlay = true;
            if (game.isSoundOn())
                game.getSelect().play();
        }
//gplay
        if (touchPos.x &gt; cam.position.x - playBtn.getWidth() &amp;&amp; touchPos.x &lt; cam.position.x - playBtn.getWidth() + gPlayBtn.getWidth() * 2
                &amp;&amp; touchPos.y &lt; cam.position.y - 112 &amp;&amp; touchPos.y &gt; cam.position.y - gPlayBtn.getHeight() * 2 - 112) {
            isGDown = true;
            if (game.isSoundOn())
                game.getSelect().play();
        }
//settings
        if (touchPos.x &gt; cam.position.x + playBtn.getWidth() - settingsBtn.getWidth() * 2 &amp;&amp; touchPos.x &lt; cam.position.x + playBtn.getWidth()
                &amp;&amp; touchPos.y &lt; cam.position.y - 112 &amp;&amp; touchPos.y &gt; cam.position.y - gPlayBtn.getHeight() * 2 - 112) {
            isSettingsDown = true;
            if (game.isSoundOn())
                game.getSelect().play();
        }


        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {

        cam.unproject(touchPos.set(screenX, screenY, 0));
        //gobutton
        if (touchPos.x &gt; cam.position.x - playBtn.getWidth() &amp;&amp; touchPos.x &lt; cam.position.x + playBtn.getWidth()
                &amp;&amp; touchPos.y &lt; cam.position.y - 100 + playBtn.getHeight() * 2 &amp;&amp; touchPos.y &gt; cam.position.y - 100 &amp;&amp; isTouchPlay)
            isTouchReleased = true;
        else
            isTouchPlay = false;

        //gplay
        if (touchPos.x &gt; cam.position.x - playBtn.getWidth() &amp;&amp; touchPos.x &lt; cam.position.x - playBtn.getWidth() + gPlayBtn.getWidth() * 2
                &amp;&amp; touchPos.y &lt; cam.position.y - 112 &amp;&amp; touchPos.y &gt; cam.position.y - gPlayBtn.getHeight() * 2 - 112)
            isGReleased = true;
        else
            isGDown = false;

//settings
        if (touchPos.x &gt; cam.position.x + playBtn.getWidth() - settingsBtn.getWidth() * 2 &amp;&amp; touchPos.x &lt; cam.position.x + playBtn.getWidth()
                &amp;&amp; touchPos.y &lt; cam.position.y - 112 &amp;&amp; touchPos.y &gt; cam.position.y - gPlayBtn.getHeight() * 2 - 112)
            isSettingsReleased = true;
        else
            isSettingsDown = false;
        return true;
    }


    @Override
    public void dispose() {
        bg.dispose();
        playBtn.dispose();
        playBtnDown.dispose();
        gPlayBtn.dispose();
        gPlayBtnDown.dispose();
        settingsBtn.dispose();
        settingsBtnDown.dispose();
        kiwiLogo.dispose();
    }


}
</code></pre>