Generics and the power of Factory Patterns

Check out the Repo here!

The problem - Why bother adding complexity?

I’ve recently been working on a personal project that demands scaling support like nothing I’ve worked on before, this is entirely by choice, and if I wanted this project to be limited by poorly designed systems I could have definitely opted for that approach.

However, this project aims to be a lot more than basic prototype and could potentially have hundreds of gameplay elements, exponentially increasing the complexity of designing and implementing features. This will inevitably lead to increasingly poor performance from badly structured systems exponentially increasing in complexity when adding new content to the project.

An example of how a poorly structured system would be accessed

Classes and Base Typing

One of the most important aspects of a looter shooter styled game is the item management system and how we can optimise the processes of creating, accessing and deleting class instances to better streamline the accessibility of type-sensitive functionality. This can be achieved through the combination of multiple techniques, but lets design an appropriate structure for our item classes first.

We want our items to share appropriate methods so function calls can be streamlined through generic instances. This can be achieved through the use of class inheritance and interfaces - allowing us to add modular functionality without increasing the complexity of the project.

An example of how abstract classes and interfaces can be used to introduce modular functionality

In the above code sample, I’m declaring a couple of very important classes, although not actually present physically, these abstract classes define some important properties that will allow us to differentiate between how an interactable item should behave from a physical one. Although an interactable item inherits the properties from its physical base, it’s important to note that we are adding to this functionality with interfaces instead of regular function declarations as this insures presence of the functions we’re interested in.

In this snippet we can see why we would add functionality in this way - In the previous snippet our functionality was largely generic and could be assumed with casts fairly effectively. However, for this particular implementation I wanted to allow weapons modular options for their basic functions.

For the case of reloading, we can check if the gun type should reload by checking for the presence of the interface. Even from a generic cast we can still check for this data, making it an optimal solution for scenarios where we can’t be sure of the type of object our player is holding.

By using interfaces, we can check if a gun is reloadable from as generic as an InteractableItem

Ok, so we’ve got some solid foundations for a pretty neat item system. But how can we retrieve this data? We can’t store hundreds of weapons, items, abilities, etc. at all times whilst we play, that would be terrible for performance and highly redundant. Instead, we can use a factory pattern to streamline the creation, deletion, and management of our class instances leaving us to simply query the factory for our required object. This setup is great for when you don’t know what type you specifically want (Think mob loot drops or the mystery box from cod zombies) and we can extend the factory functionality quite easily to support this through the use of generics.

Examples of queries possible with the current factory system

So there we have it, the system is far from perfect and is yet to undergo some proper tests but I’m pretty happy with how things have progressed so far. Modular behaviours are a challenging aspect of object oriented design and I’d like to say that I’ve taken the appropriate precautions to avoid some of those nasty refactors during later development. With that being said, I’m gonna continue working on this, I’m looking forward to making another one of these in 2022, and I hope to have something visual to present for my next update :D

Previous
Previous

Checkers: A social ranked experiment.

Next
Next

Optimizing: Open World