Hybrid Combat RPG

-A Level Computer Science NEA Project-


Summary

This was a school project that I made for my A-level Computer Science course. This project lengthed up to 6 months, of which half was invested on documentation and analysis of it.

Functionally, this game is a hybrid roguelike RPG where the player can choose for each enemy encounter, whether to fight them in a turn based combat system or a real time one.


Core Gameplay Functionality

The player is first introduced to a randomly generated map, consisting of enemies, physical obstacles and items.
Their objective is to clear the map of all enemies, and survive following maps until their character's death. Enemies become stronger per iteration of map generation.


Combat System Selection

Upon contact with an enemy on the map, the player is sent to a separate scene, where they can choose their style of combat. The player, along with the required data for setting the enemy's difficulty level, is sent to a new scene which accords to which combat system they chose.


Collision

Despite the project being made in Unity, I decided to create my own collision system revolving around the quadtree structure.

To explain what a quadtree is, it is a space-partioning structure that quarters a space to query if more than a certain number of subjects are within that space. This, in the context of a collision system, allows the code to only check collision for subjects that are near each other rather than each subject checking with every other one in the scene; which, in effect, reduces fps loss compared to its brute-force counterpart.*

* = Reduces the time complexity for the query celled per frame, from O(n^2) to O(n log n ).


Real Time Enemy AI

First, for the enemy to be a constant threat to the player, they will need to chase the player down a path. Here is where I implemented an A* algorithm for the enemies to swiftly and efficiently form a path around wall objects.

Now, whilst the orthodox A* algorithm requires a predefined grid on the scene, I made a different approach of forming the grid from the starting point (the enemy) until one of the formed nodes finds the player character. This is because I feared that there may be errors if I used a predefined grid, and the enemy at some point in the game would call the algorithm at the crossing point of multiple nodes in that grid.

The enemy AI is otherwise simple: it chases the player in the scene and shoots projectiles at them when within a certain distance from each other - since, I allocated the vast majority of my time working on the A* algorithm, and other more complex implementations for the game, in order to get the highest marks in my course.


Turn Based Enemy AI

The turn based combat system revolves around both the player and enemy characters' hidden "speed" attribute. to explain what the speed system is:

  • Each character has a default "turn" value, defualted by their "speed".

  • The "turn" value for that character increases, the value increase depending on what action the character took (e.g. block, attack).

  • The turn queue will constantly sort the order of the character's turns, in ascending order.


  • Randomly Generated Maps and Saving the Game

    Generating a map just involves picking a random number of each type of objects (e.g. walls, enemies, items) within a certain threshold, and placing them within a certain area, whilst avoiding objects to be generated in the same position as another.

    Saving the game involves accumulating essential data from objects in the game (e.g. positions of objects in the generated map, current state of the player character, etc.), into a single object of a "Game Data" class, and then saving a json formatted file of it. Following this, loading the data is done by parsing the json and then the required objects taking required data from the parsed Game Data object.