Developing Multiplatform Game with LibGDX, part 15: smooth leave on victory

Player Leaving On Victory

Now that we’ve implemented a smooth approach- let’s work on smooth leave. Whenever player wins a battle – let’s make him move to the right side of the screen (to make an illussion of leaving and progressing further).

In our Player.java, add two variables:

private boolean winning = false;
private float winTime = 0;

Now, we need to add an extra condition to our draw:

if (timeAlive < APPROACH_TIME)
{
    float t = timeAlive / APPROACH_TIME; // 0..1
    t = t * t;
    setPosition(
            t * sizeEvaluator.getBaseScreenX(fieldX),
            sizeEvaluator.getBaseScreenY(fieldY));
}
else if (winning)
{
    float t = 1;
    if (timeAlive - winTime < APPROACH_TIME)
    {
        t = (timeAlive - winTime) / APPROACH_TIME; // 0..1
        t = t * t;
    }
    float fx = sizeEvaluator.getBaseScreenX(fieldX);
    setPosition(
            fx + t * (sizeEvaluator.getRightSideX() - fx),
            sizeEvaluator.getBaseScreenY(fieldY));
}
else
{
    setPosition(sizeEvaluator.getBaseScreenX(fieldX),
            sizeEvaluator.getBaseScreenY(fieldY));
}

As you see, we need to know the right side of the screen. In our SizeEvaluator, let’s add methods setRightSideX and getRightSideX. Since the width of our window (and therefore screen) can change, we need to keep it updated. SizeEvaluator constructor should also accept right side x.

private float rightSideX;

public SizeEvaluator(Stage _stage, Resources _res, int maxBaseX, int maxBaseY, float _rightSideX)
{
    measuredStage = _stage;
    resources = _res;
    maxTileBaseX = maxBaseX;
    maxTileBaseY = maxBaseY;
    rightSideX = _rightSideX;
}

public void setRightSideX(float value)
{
    rightSideX = value;
}

public float getRightSideX() {
    return rightSideX;
}

Now adjust GameScreen constructor to pass gameStage.getWidth() as the last parameter into SizeEvaluator constructor.

sizeEvaluator = new SizeEvaluator(gameStage,
        game.res,
        GameLogic.MAX_BASE_X,
        GameLogic.MAX_BASE_Y,
        gameStage.getWidth());

Then, we have to take care that sizeEvaluator adjusts properly on screen resize. In our GameScreen’s resize method, add the call to sizeEvaluator’s setRightSideX function.

@Override
public void resize(int width, int height)
{
    super.resize(width, height);
    gameStage.getViewport().update(width, height, true);
    sizeEvaluator.setRightSideX(gameStage.getWidth());
}

One more thing: we need to tell our player class that the game is won. There’s also a problem now: the player’s time is updated inside our logic calls. But we’re not updating the logic if the game has ended (enemy or player died). Time for some refactoring! Change GameScreen’s update function from:

public void update(float delta)
{
    gameStage.act(delta);
    if (player.getLives() > 0 && logic.getEnemy().getLives() > 0)
    {
        logic.update(delta);
    }
}

To:

public void update(float delta)
{
    gameStage.act(delta);
    logic.update(delta);
}

And adjust GameLogic accordingly:

public void update(float delta)
{
    gameTime += delta;
    player.update(delta);

    if (player.getLives() > 0 && enemy.getLives() > 0) {
        effectEngine.update(delta);
        enemy.update(delta);

        if (lastBonusSpawn + BONUS_SPAWN_INTERVAL < gameTime &&
                bonuses.size() < MAX_BONUSES_ON_FIELD) {
            SpawnRandomBonus();
        }
    }
}

Player is always updated, but all the other stuff gets updated only if both player and enemy are alive. Now the only thing is left is to tell our player object that we won! In our Player class, add new function:


public void markVictorious()
{
    winTime = timeAlive;
    winning = true;
}

Then, in our gamelogic, when we damage the enemy, we have to check enemy health. If it equals zero – tell the player that we won! Adjust the part of code with attack bonus pickup:

else if (currentBonus.getBonusType() == Bonus.BONUS_TYPE_ATTACK)
{
    enemy.takeDamage(1);
    if (enemy.getLives() <= 0)
    {
        player.markVictorious();
    }
}

Great! Now our player leaves after the game ends, marking the continuation of the journey. Looks much better!

Leave a Reply

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