Skip to content

Multiple game level

default-jamc edited this page Oct 19, 2021 · 8 revisions

Purpose

To allow for a more engaging, challenging and granular experience for the player, multiple levels have been implemented into the game. In total, there are four playable levels and one tutorial level.

Description

All of the levels differ in difficulty, object placement and terrain layout. The player will experience new challenges and objectives on every level (See the Level Design Wiki Page for the goals & objectives of every level). Once a player successfully completes a level, they can progress onto the next.

Implementation

Key Components

  • PlayerWinActions: Handles the players on-click actions for the Win Popup menu.
  • PopupMenuActions: Handles the players on-click actions for the Next Level button on the Win Popup menu. This determines the next level to progress to based on the current level.
  • ForestGameArea, LevelTwoArea, LevelThreeArea, LevelFourArea: The game areas containing all of the map elements such as obstacles, buffs and enemies.
  • MainGameScreen, LevelTwoScreen, LevelThreeScreen, LevelFourScreen: The game screens for each level. These are the 'frames' that the Areas are loaded into.
  • GdxGame: Contains all the screen types and initialises them.

In the PlayerWinActions create method, an event listener is created for the Next Level button.

entity.getEvents().addListener("continue", this.mainGameUI.getComponent(PopupMenuActions.class)::onNextLevel);

In order to load the next level correctly when the player clicks the Next Level button, we have to determine the current level and load in the next. This has been done using the onNextLevel() method in PopupMenuActions.

Revised Implementation

    /**
     * Method actives when user clicks the next level button after winning
     */
    public void onNextLevel() {
        switch (this.currentLevel) {
            case 1:
                game.setScreenType(GdxGame.ScreenType.LEVEL_TWO_GAME);
                game.setScreen(GdxGame.ScreenType.LOADING);
                break;
            case 2:
                game.setScreenType(GdxGame.ScreenType.LEVEL_THREE_GAME);
                game.setScreen(GdxGame.ScreenType.LOADING);
                break;
            case 3:
                game.setScreenType(GdxGame.ScreenType.LEVEL_FOUR_GAME);
                game.setScreen(GdxGame.ScreenType.LOADING);
                break;
            case 4:
                // Return to main menu
                onHome();
                break;
        }
    }

Where the onHome function is:

    /**
    * Called when the user clicks on the Main Menu button on pop-up screens.
    * Changes the screen to be the main menu screen
    */
    public void onHome() {
        game.setScreen(GdxGame.ScreenType.MAIN_MENU);
    }

This allows for the level to change onto the next, unless they are at the final level. When the player reaches the final level, they will be sent back to the Main Menu.

Original Implementation

    /**
     * Method actives when user clicks the next level button after winning
     */
    public void onNextLevel() {
        if (this.currentLevel == 1) {
            game.setScreenType(GdxGame.ScreenType.LEVEL_TWO_GAME);
            game.setScreen(GdxGame.ScreenType.LOADING);
        } else if (this.currentLevel == 2) {
            game.setScreenType(GdxGame.ScreenType.LEVEL_THREE_GAME);
            game.setScreen(GdxGame.ScreenType.LOADING);
        }
        //game.setScreen(GdxGame.ScreenType.LEVEL_TWO_GAME);
    }

Usage

If more levels are to be added to the game, two main things must occur

  1. A new Area has to be defined for the level. This should extend ForestGameArea.
  2. A new Screen has to be defined for the level. This should extend MainGameScreen.

Example: Let's say we wanted to add a 5th level into the game.

Creating the Area

Since all of the Areas extend the ForestGameArea, there is little functionality that needs to be added into the new Area class

public LevelFiveArea(TerrainFactory terrainFactory, int checkpoint, boolean hasDied) {
    super(terrainFactory, checkpoint, hasDied);
    setupSpawns();
}

Creating the Screen

Similarly, all of the Screens extend MainGameScreen, so minimal additional code is required.

public LevelFiveScreen(GdxGame game, ResourceService resourceService, MainGameScreen.Level level) {
    super(game, resourceService, level);
}

The MainGameScreen's Level enum holds all of the different levels in the game. Differentiating between the levels is required to ensure the correct Area is loaded by the Screen. Add in FIVE to the current options list as:

public enum Level {
    ONE, TWO, THREE, FOUR, FIVE 
}

Letting GdxGame know when to change to the Screen

GdxGame has a function newScreen which handles the screen changes based on it's current ScreenType. The different ScreenType is selected when the player clicks particular buttons within the game.

  /**
   * Create a new screen of the provided type.
   * @param screenType screen type
   * @return new screen
   */
  private Screen newScreen(ScreenType screenType) {
    switch (screenType) {
      case MAIN_MENU:
        return new MainMenuScreen(this);
      case MAIN_GAME:
        return new MainGameScreen(this, resourceService, MainGameScreen.Level.ONE);
      case LEVEL_TWO_GAME:
        return new LevelTwoScreen(this, resourceService MainGameScreen.Level.TWO);
      case LEVEL_THREE_GAME:
        return new LevelThreeScreen(this, resourceService MainGameScreen.Level.THREE);
      case LEVEL_FOUR_GAME:
        return new LevelFourScreen(this, resourceService MainGameScreen.Level.FOUR);
      case LEVEL_FIVE_GAME:
        return new LevelFiveScreen(this, resourceService MainGameScreen.Level.FIVE); /* Added in option for 5th level */
      case RESPAWN:
        ...
      default:
        return null;
    }
  }

In order for the LEVEL_FIVE_GAME to work within the switch statement, it must be added to the GdxGame ScreenType enum:

public enum ScreenType {
    MAIN_MENU, MAIN_GAME ....
    LEVEL_FIVE_GAME, LEVEL_FOUR_GAME, LEVEL_THREE_GAME, LEVEL_TWO_GAME,
    ...
}

After the new Area and Screen have been created for the level, it should be added into the onNextLevel method in PopupMenuActions.

Revised Implementation

    /**
     * Method actives when user clicks the next level button after winning
     */
    public void onNextLevel() {
        switch (this.currentLevel) {
            case 1:
                ...
            case 4:
                game.setScreenType(GdxGame.ScreenType.LEVEL_FIVE_GAME)
                game.setScreen(GdxGame.ScreenType.LOADING)
                break;
            case 5:
                // Return to main menu
                onHome();
                break;
        }
    }

Finally, in order for the currentLevel value to yield 5, the PopupMenuActions constructor must be extended

public PopupMenuActions(GdxGame game, ForestGameArea area) {
    this.game = game;
    switch(area.getType()) {
        case ONE:
            ...
        case FIVE:
            this.areaFive = (LevelFiveArea) area;
            this.currentLevel = 5;
            break;
    }
}

Then, we see that PopupMenuActions needs a new attribute, areaFive:

public class PopupMenuActions extends Component {
    ...

    /* The current Area */
    private ForestGameArea area = null;
    private LevelTwoArea area = null;
    private LevelThreeArea area = null;
    private LevelFourArea area = null;

    /* Add in level 5 option */
    private LevelFiveArea area = null;
  
    ...
}

Original Implementation

    /**
     * Method actives when user clicks the next level button after winning
     */
    public void onNextLevel() {
        if (this.currentLevel == 1) {
            game.setScreenType(GdxGame.ScreenType.LEVEL_TWO_GAME);
            game.setScreen(GdxGame.ScreenType.LOADING);
        } else if (this.currentLevel == 2) {
            game.setScreenType(GdxGame.ScreenType.LEVEL_THREE_GAME);
            game.setScreen(GdxGame.ScreenType.LOADING);
        }
        //game.setScreen(GdxGame.ScreenType.LEVEL_TWO_GAME);
    }

UML diagram

Original UML Diagram

image

Table of Contents

Home

Introduction

Main Menu

Main Game Screen

Gameplay

Player Movement

Character Animations

Enemy Monster Design and Animations

Game basic functionalities

User Testing

GitHub Wiki Tutorial

Game Engine

Getting Started

Documentation

Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Game Screens and Areas

Terrain

Concurrency & Threading

Settings

Troubleshooting

MacOS Setup Guide

Clone this wiki locally