There are many different ways of achieving this depending on how much control you need over what the fade looks like.
If you need very fine-grained control then an option is to render each Screen
to a FrameBuffer
and then write a custom fragement shader that takes both FrameBuffer
's as input and blends them according to some logic.
If what you want is a simple "fade out screen one and then fade in screen two" kind of behaviour then you can get this by creating a Screen
that renders a square over your screen (for example using a ShareRenderer
) and alter the opacity depending on how far along the fade you are.
The example below (which has two different screens, a red and a green) uses a FadeScreen
class that is a Screen
that can take another Screen
as input and then either fade to a solid color or from a solid color. And by chaining two of these FadeScreen
s a fade-out-fade-in effect can be acieved.

Essentially the FadeScreen
class works by first calling render
on the Screen
you want to fade from or to, and then render a blended rect ontop using the ShapeRenderer
:
private void renderFade() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
float f = Math.min(1.0f, elapsed / fade.duration);
float opacity = fade.type == FadeType.OUT ? fade.interpolation.apply(f) : 1.0f - fade.interpolation.apply(f);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(fade.color.r, fade.color.g, fade.color.b, opacity);
shapeRenderer.rect(0, 0, camera.viewportWidth, camera.viewportHeight);
shapeRenderer.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
The opacity is calculated as an interpolation based on the elapsed time, and the amount is either increasing for a fade out or decreasing for a fade in.
Again this method doesn't blend one screen into another, but rather one screen into a color, and then that color into the next screen.
The fade is setup by creating a definition for the fade out and for the fade in, and then setting the current Screen
to an instance of a FadeScreen
that fades from screenA to another FadeScreen
that fades into screenB.
FadeScreen.FadeInfo fadeOut = new FadeScreen.FadeInfo(FadeScreen.FadeType.OUT, Color.WHITE, Interpolation.smoother, 2.0f);
FadeScreen.FadeInfo fadeIn = new FadeScreen.FadeInfo(FadeScreen.FadeType.IN, Color.WHITE, Interpolation.smoother, 2.0f);
fadeScreen = new FadeScreen(this, fadeOut, screenA, new FadeScreen(this, fadeIn, screenB, null));
setScreen(fadeScreen);
Full source code for the FadeScreen
class:
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Interpolation;
public class FadeScreen extends ScreenAdapter {
public enum FadeType { IN, OUT }
public static class FadeInfo {
public final FadeType type;
public final Color color;
public final Interpolation interpolation;
public final float duration;
public FadeInfo(FadeType type, Color color, Interpolation interpolation, float duration) {
this.type = type;
this.color = color;
this.interpolation = interpolation;
this.duration = duration;
}
}
private final FadeInfo fade;
private Screen screen;
private Screen next;
private final Game game;
private final ShapeRenderer shapeRenderer;
private final Camera camera;
private float elapsed;
public FadeScreen(Game game, FadeInfo fade, Screen screen, Screen next) {
this.game = game;
this.fade = fade;
this.screen = screen;
this.next = next;
shapeRenderer = new ShapeRenderer();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(camera.viewportWidth / 2.0f, camera.viewportHeight / 2.0f, 0.0f);
camera.update();
}
private void renderFade() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
float f = Math.min(1.0f, elapsed / fade.duration);
float opacity = fade.type == FadeType.OUT ? fade.interpolation.apply(f) : 1.0f - fade.interpolation.apply(f);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(fade.color.r, fade.color.g, fade.color.b, opacity);
shapeRenderer.rect(0, 0, camera.viewportWidth, camera.viewportHeight);
shapeRenderer.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
public void render(float delta) {
if (screen != null) {
elapsed += delta;
if (elapsed >= fade.duration) {
if (next != null) {
game.setScreen(next);
screen.dispose();
screen = null;
} else
game.setScreen(screen);
}
}
Gdx.gl.glClearColor(0, 0, 0, 0);
if (screen != null)
screen.render(delta);
renderFade();
}
}