Level System Overview - UQcsse3200/2024-studio-3 GitHub Wiki

Table of Contents

Introduction

Coding Overview

   Summary

      Rationale

      Implementation Summary

      Usage Summary

         Accessing LevelService

         Accessing the EventHandler

         Triggering a New Level

         Using Gold

         Prelude Levels

Test Plan

Introduction

The Level System is what defines the number of customers spawning depending on the level, and how 'difficult' each level should be - with 'difficulty' being defined as the number of interactions required to successfully get through the day, meaning levels with a 'higher difficulty' require more interactions in order for the player to get complete the day. It also stores the player's gold, so that between levels it is not reset.

The back-end of the Level System is comprised of two parts, a LevelService and a LevelComponent. The LevelService acts as a way of globally handling and tracking events related to levels - mainly for triggering them. The LevelComponent acts as sort of spawn controller which is added to an Entity in order to control when and what customers are spawned on screen.

To Top

Coding Overview

UML Diagrams

Sequence Diagram drawio

Sequence Diagram showcasing how customers are spawned. This diagram is very simplified, and does not showcase certain stages such as registering events and initialising classes.

UML Diagram drawio

UML Diagram showing the relations between all classes involved in the Level System (NOTE: Does not contain any implemented interfaces)

To Top

Summary

The Level System as a whole consists of two separate classes, LevelService and LevelComponent. The LevelService acts as a globally accessible service which can be registered to the ServiceLocator and allows for the control - triggering a levels spawning pattern and other related events - and tracking of various level related variables - e.g. what the current level is. This is done by having LevelService store an EventHandler as well as several private variables and methods. The two most important events that the EventHandler has listeners for is the startLevel and startSpawning events. The startLevel event calls the levelControl() method in the registered LevelService object. When levelControl() is called, it calculates what the spawn cap of the level should be, and then triggers the startSpawning event, which is parsed the spawn cap variable. The startSpawning event is related heavily to the LevelComponent class.

The LevelComponent when added to an Entity makes it (the Entity) act as a spawn controller, controlling when customers spawn on screen and which customer spawns on screen. When the startSpawning event is triggered, the method initSpawning() is called. When called, this method ensures that all private variables in the LevelComponent object are set to default values and then calls a method called toggleNowSpawning(). When this method is called, a check present in the update() method now passes, which then allows for customers to be spawned. When customer spawning is allowed, a check is done to see if it has been three seconds since the last customer spawned, if another customer can be spawned (the spawn cap has not been reached yet) and if another customer can join the line up. If all of these conditions are true, then another customer is spawned. When the spawn cap is reached, then toggleNowSpawning() is called again, preventing anymore customer spawning from occurring.

To Top

Rationale

In order to make a spawn controller, it was decided the best course of action would be to create a class that extends Component, as the update() method could be overwritten, which, when an instance of LevelComponent is added to an Entity, allows for easy asynchronous checks due to the EntityService. To be completely honest, I also had no other ideas of what possibly I could do and I had no idea about scheduling events. Oh well. Additionally, using a Component allowed for a factory design pattern to be used to instantiate a "spawning controller Entity."

Creating a new type of service for use with the ServiceLocator was done because it is a very robust and preexisting method of global access, with several other services already being implemented for similar purposes.

To Top

Implementation Summary

Below is the constructor for the LevelService, which initialise some private variables, and most importantly registers some listeners.

image

The levelControl() method called by the startLevel event currently takes one parameter. All it does for now is limit the number of customers that spawn.

image image

This is in the MainGameScreen class, at the bottom of the constructor. The first two statements become more relevant in later photos.

image

This is from the LevelComponent class. The event startSpawning, if you remember, is triggered in LevelService by levelControl()

image

This is what the event startSpawning calls. This method basically just ensures that all private variables are reset, but most importantly, enabled spawning through the toggleNowSpawning() method.

image

Speaking of, here is the toggleNowSpawning() method

image

Now the reason why I use a Component in the first place is because the Entity class has a very nice method which is update() for asynchronous code which can be called constantly (I didn't know about scheduledEvents). When the conditions are correct, a few methods are called.

image

Most importantly, spawnCustomer(), which calls a random event from an Entity in ForestGameArea to spawn a customer.

image

This is the method for creating the Entity object that has the EventHandler which listens for all the customer spawning events.

image

These are the various methods called by the multiple spawning events.

image

And this is what the spawnCustomer() method looks like, again, in the ForestGameArea class

image

To Top

Usage Summary

Accessing LevelService

In order to access the LevelService then ServiceLocator.getLevelService(); must be used, which returns the LevelService.

Example:

LevelService levelService = ServiceLocator.getLevelService();

Accessing the EventHandler

In order to access the EventHandler, use .getEvents();, which returns the EventHandler stored in LevelService. When accessed, the EventHandler has the standard methods, most importantly, trigger() and addListener().

Example:

EventHandler eventHandler = levelService.getEvents();
eventHandler.addListener("exampleEvent", this::exampleMethod);
eventHandler.trigger("exampleEvent");

Triggering a new level

As previously outlined, in order to go to a new level, the event startLevel must be triggered. To trigger this event, an integer between 0 and 10 (inclusive) must be parsed. This event requires the existence of an Entity with the LevelComponent added to it, otherwise, no event will be triggered.

Example:

Entity spawnController = LevelFactory.createSpawnControllerEntity();
eventHandler.trigger("startLevel", 1);

Using Gold

In order to use gold, there are two very simple set and get methods that can be called at any time. These are .getCurrGold() and .setCurrGold(int):

Example:

int gold = ServiceLocator.getLevelService.getCurrGold();
ServiceLocator.getLevelService.setCurrGold(50);

Prelude Levels

There are, 7 prelude levels in total. It is an enum in GDXGame.java

image

Level 0 -> is only used in Tutorials as it has not increment. Level 1,2,3,4,5,Done -> Are playable levels in the MainGame.

image

To Top

Test Plan

Several tests were written under LevelComponentTest and LevelSystemTest in order to automatically test various methods and logics. Visual tests also played a substantial role for verifying logic, mainly for spawning, incrementing levels and gold persistence. In order to verify spawning, levels have a predetermined number of customers they should spawn, therefore, in order to test this, run the game, enter the game and count how many customers spawn on screen. Totals can be seen under Implementation Summary.

To verify levels were incrementing correctly, then enter the game, wait for all customers to spawn and quit back to the main menu. Re-enter the game. The same amount of customers should spawn, signifying the level did not increase. In order to go to a new level, the player must press P in order to display the end of day display. When exiting this, the level should increment, and this can be verified by cross referencing how many customers spawned vs how many should spawn according to the level.

With gold preservation, this can be tested by generating gold either through the service window or waiting for a docket to expire, and when going to the next level, the gold will remain the same.

⚠️ **GitHub.com Fallback** ⚠️