Developing Multiplatform Game with LibGDX, part 16: fade in, fade out and progression

Lesson 16: screen transition

Now that we have transactions, let’s switch to gameplay enhancements: first thing – move to next screens on victory.

In GameLogic class, create a new interface.

public interface GameEventListener
{
    void OnGameEnd(boolean playerWon);
}

Modify GameLogic to take the listener as one of the constructor’s parameters:

GameEventListener eventListener;

public GameLogic(DodgingHero _game, GameEventListener _listener)
{
    eventListener = _listener;

We should notify our victory listener at the same time when we mark our player as victorious.

In our AssignPlayerPosition, where we check bonus pickups and mark player victorious on killing enemy, add a new line:

if (enemy.getLives() <= 0)
{
    player.markVictorious();
    eventListener.OnGameEnd(true); // added this line!
}

It will notify the player about the end of the game. Now, make GameScreen implement the said listener.

public class GameScreen extends DefaultScreen implements InputProcessor, GameLogic.GameEventListener {

As usual, press Alt+Enter to implement the missing method.

Now, what do we want to do on GameEnd? We need a smooth fadeout, and then a progression to next level. Well, a restart for now. It is going to be a progression in the next lesson though. Since we are using sprites (and not gamestag eactors), we won’t be able to use libgdx in-built fadeout action. No worries, it’s not hard to implement ourselves. In advance, make two static constants at the beginning of the GameScreen class:

public static final float GAME_END_FADEOUT = 0.5f;
public static final float GAME_START_FADEIN = 0.25f;

Then, get to working on GameEnd function call.

@Override
public void OnGameEnd(boolean playerWon) {
    gameStage.addAction(Actions.sequence(
            new Action() {
                float t = 0;
                @Override
                public boolean act(float delta) {
                    t += delta;
                    float tempt = t / GAME_END_FADEOUT;
                    tempt *= tempt;
                    batch.setColor(1, 1, 1, 1 - tempt);
                    return t >= GAME_END_FADEOUT;
                }
            },
            new Action() {
                @Override
                public boolean act(float delta) {
                    dispose();
                    game.setScreen(new GameScreen(game));
                    return true;
                }
            }
    ));
}

We’ll ignore playerWon Boolean for now (we’ll implement another transaction on loss). Now, what do we want to do on GameEnd? We create a sequence of actions. First is essentially a fade-out timer, we fade the screen out for GAME_END_FADEOUT seconds (0.5 in this case), then we return true, which indicates that that time has been spent. And then actually we create a new GameScreen that restarts the game.

Now, to get further with our implementation, in our logic initialization, add the line:

logic = new GameLogic(game, this);

Now, that we’ve added a smooth fadeout, we should actually add a smooth fadein. In our GameScreen initialization, add a new action to our freshly initialized stage (at the end of GameScreen constructor).

gameStage.addAction(new Action() {
    float t = 0;
    @Override
    public boolean act(float delta) {
        t += delta;
        float tempT = t / GAME_START_FADEIN;
        tempT *= tempT;
        if (tempT > 1.0f)
        {
            tempT = 1.0f;
        }

        batch.setColor(1, 1, 1, tempT);
        return t >= GAME_START_FADEIN;
    }
});

It’s the same quadratic fadein as you’ve seen before: take the time, add the delta, divide by expected time for fadein (0.25) in our case, thus normalizing the value to 0..1. After that, square it. Great! We got a new transparency.

Finally, if the time has passed the necessary fadein time, return true (thus ending the action). Run the game. As you see when screens actually fadeIn, you have a quick flicker (if you look closer: it’s a scaled-down version of your screen). To prevent this, we need to update a gameStage camera before drawing frame one. At the end of GameStage constructor, add:

gameStage.getCamera().update();
batch.setProjectionMatrix(gameStage.getCamera().combined);

Final thing. By now you’ve probably noticed that enemy attacks are very easy to evade. Decrease WARNING_TIME from 0.75 to 0.5f. Try the game out. FadeIns/Fadeouts should be smooth now.

Relevant git commit:

https://github.com/vladimirslav/dodginghero/commit/1a2fb0896293a80e1b12ae4fc60ee73167cdcabf

Leave a Reply

Your email address will not be published. Required fields are marked *