Skip to content

Game Transition Loop

Jantoom edited this page Aug 31, 2021 · 6 revisions

Introduction

Switching between Game Screens while in-game is a key part of the user experience, designed to tell the player whether they are winning or losing. These transitions can be summarised as "Gameplay" to "Results", and back again. This mechanism is known as the Game Loop.

To facilitate results being displayed to the player, the End Game Screen was created. Currently, the class EndGameScreen is implemented similarly to MainMenuScreen. It displays the result as an image, and allows the player to click back into the MainMenuScreen.

To reach the EndGameScreen, a win or lose condition must be met. These conditions are observed inside the MainGameScreen, and directly determine the appearance of EndGameDisplay, a UIComponent of EndGameScreen.

Code Implementation

Changes to GdxGame

To facilitate the new screen, cases for newScreen and enumerations for ScreenType were added:

  private Screen newScreen(ScreenType screenType) {
    switch (screenType) {
      ...
      case WIN_DEFAULT:
        return new EndGameScreen(this, ScreenType.WIN_DEFAULT);
      case LOSS_TIMED:
        return new EndGameScreen(this, ScreenType.LOSS_TIMED);
      case LOSS_CAUGHT:
        return new EndGameScreen(this, ScreenType.LOSS_CAUGHT);
      ...
   }

   public enum ScreenType {
    MAIN_MENU, MAIN_GAME, SETTINGS, WIN_DEFAULT, LOSS_TIMED, LOSS_CAUGHT
   }

Notably, each ScreenType does not correlate to a unique Screen. This is because the current logic for Win and Lose screens are very similar. Therefore, their implementations were combined.

Changes to MainGameActions

New events and methods had to be added for each new ScreenType:

  public void create() {
    ...
    entity.getEvents().addListener("winDefault", this::onWinDefault);
    entity.getEvents().addListener("lossTimed", this::onLossTimed);
    entity.getEvents().addListener("lossCaught", this::onLossCaught);
  }

Once a condition is met, the alerted listener will call one of the screen transition methods to switch to EndGameScreen:

  private void onWinDefault() {
    ...
    game.setScreen(GdxGame.ScreenType.WIN_DEFAULT);
  }

  private void onLossTimed() {
    ...
    game.setScreen(GdxGame.ScreenType.LOSS_TIMED);
  }

  private void onLossCaught() {
    ...
    game.setScreen(GdxGame.ScreenType.LOSS_CAUGHT);
  }

Creation of EndGameScreen, EndGameEvents and EndGameDisplay

Called directly from MainGameScreen, the EndGameScreen constructor takes the win/loss condition as a result that determines the list of textures that will be displayed:

  private GdxGame.ScreenType result;
  private String[] activeDisplayTextures;

  public EndGameScreen(GdxGame game, GdxGame.ScreenType result) {
    ...
    this.result = result;
    switch (this.result) {
      case WIN_DEFAULT:
        this.activeScreenTextures = winScreenTextures;
        break;
      case LOSS_TIMED:
      case LOSS_CAUGHT:
      default:
        this.activeScreenTextures = loseScreenTextures;
    }
    ...
    createUI();
  }

The EndGameDisplay passes itself by reference to the EndGameDisplay constructor in the createUI method. The display can call methods on the reference to retrieve the level result and active textures this way. It is assumed that the first path location in the String of loaded assets is the chosen screen background:

  public EndGameDisplay(EndGameScreen screen) {
    super();
    this.screen = screen;
  }

  private void addActors() {
    table = new Table();
    ...
    Image background =
            new Image(
                    ServiceLocator.getResourceService()
                            .getAsset(this.screen.getActiveScreenTextures()[0], Texture.class));
    ...
    table.setFillParent(true);
    table.setBackground(bakground.getDrawable());
    ...
  }

The nextLevelBtn and mainMenuBtn functions very similar to the ones found in MainGameDisplay. It allows the player to go to the next MainGameScreen level or MainMenuScreen respectively. A player can only go to the next level if they won the previous one:

  private void addActors() {
    ...
    if (this.screen.getResult() == GdxGame.ScreenType.WIN_DEFAULT) {
      TextButton nextLevelBtn.addListener(
        new ChangeListener() {
          @Override
          public void changed(ChangeEvent changeEvent, Actor actor) {
            logger.debug("Next level button clicked");
            entity.getEvents().trigger("nextLevel");
          }
        });
        buttonContainer.addActor(nextLevelBtn);
    }
    ...
  }

Suggestions for change

  • In future iterations where desired win/lose displays are more design-dependent, EndGameScreen could be split into WinGameScreen and LoseGameScreen to facilitate whatever major differences that may appear
  • Once design becomes a more important factor against programming, we expect win/lose backgrounds to be redrawn. A simple change to the hardcoded filepath in EndGameScreen will suffice this
Clone this wiki locally