Machine Functionality: Part 2


Hello all and welcome to Part 2 of Machine Behaviors: Pair Programming and Refactoring for Inheritance!

First, a little introduction to what pair programming is! Like the name suggests, two programmers work in a pair to program together. Now, unlike popular media suggests, the two programmers are not working off the same keyboard (a la Abby and McGee from NCIS). Instead, one programmer is the “driver” and the other is the “navigator”.

The driver is responsible for writing the code, while the navigator helps guide the driver to ensure that there are fewer defects in the code, if any. When tackling a major refactor, it can help to have two people tackling the issue together, as you can discuss how to solve issues in real-time. It might take a little longer to get through the refactor, but the resulting refactor is of a higher quality than one person taking it on - meaning less time is spent testing as there are little to no bugs found.

Now, getting into the refactoring process for our machine behaviors. Previously, each machine type had its own class that dictated behaviors, and was nearly identical to the other machine classes barring some specific references to what a machine accepts as input and what they produce.

Currently, this is all that is inside the respective machine classes:


Each machine inherits from MachineBehavior, and we are hard coding the resource type it produces (line 3). The enum is stored in a separate script:


Other than that, the entirety of the machine’s behavior is determined in the parent class.

Let’s start with the new parameters in MachineBehavior.

You’ll see that we added quite a bit, namely a dictionary called resourceTypeRelationships with key-value pairs tying the resource types together based on their input-output relationship, and the MachineType set in the child classes.There are also some additional parameters for features we added later or reworked, but those are irrelevant to the refactor (changes to machine durability and upgrades, for example).

Next, let’s head to the production coroutine. First, the production coroutine before the refactor:

Then, after the refactor:

Looks pretty different, eh? In truth, the only difference is rather than returning one object type, we are returning a product based on the type set in MachineType, which is determined by each individual class. We then had to change how objects were being pooled in the object pooler, as each product previously had individual ReturnProduct methods - but they now function off of one method that returns a specific product based off of MachineType. 

The product is then configured in the ConfigureProduct method, which is just a helper method to reduce bloat in the production coroutine:

Finally, the last bit of refactoring occurred in AddInput, as we had to make a universal method to accept any type of product, based on the key-value pairs set in resourceTypeRelationships

Now, AddInput checks the player’s inventory of any given product based off of the resourceTypeRelationships, and ensures that the machine can still take additional product.

If that check passes, it removes the respective product and progresses through the respective processes that update the machine’s UI, play sound effects, and resets the error message if the machine was previously empty.

From there, there were no changes needed to RepairMachine or UpgradeMachine, as those were independent of the machine’s type - they were simply moved to the parent class MachineBehavior. 

In total, this refactor took Zeb and myself approximately two and a half hours, but it went much more smoothly for having worked on it together - there were no extraneous errors and everything worked perfectly after completing the refactor. Which, if you know programming, is a dream come true.

Get Trade N' Transit

Leave a comment

Log in with itch.io to leave a comment.