Crafting the Core: Modular Architecture for our Retro Revival


Hi everyone! Here at Disgruntled Games we are hard at work on our next title, Un-Abandoned Ware - a game where you play as an intern transported into a piece of forgotten software. To escape, you'll explore three unique worlds each inspired by classic 90s video games - a horrific stealth-survival level, an out-of-this-world platforming level, and a fast-paced, laser-filled FPS level. 

This week, I focused on building the core architecture that will make travelling across worlds seamless and bring our game to life. Since our game has three entirely different gameplay experiences, we needed an architecture that would:

  • Cleanly handle different mechanics and controls
  • Easily switch between gameplay styles
  • Maintain cohesion between worlds and throughout the game

Solution? Interfaces!

Since each of our game worlds plays dramatically differently, a single, monolithic player controller script would quickly become a tangled mess of conditionals and duplicated logic. Luckily, that's where interfaces come in! In programming, an interface is like a contract - it defines what needs to happen, but not how. Interfaces allow us to implement unique gameplay styles for each world while staying organized and consistent. Even better, MonoBehavior scripts can inherit from interfaces (unlike abstract base classes). 

For our game, I created two core interfaces that form the backbone of how the player navigates and interacts with the game world:

1. IPlayerMode

The IPlayerMode interface defines everything the player can do - moving, jumping, attacking, etc. - but it does not define how these actions work. The actual implementation of these methods will be handled in the specific PlayerMode scripts.

2. IInteractable

The IInteractable interface defines how the player interacts with objects in the world like NPCs, doors, and items. 

Why this matters and how it helps:

  • Separate logic for each world - our programming team can work in isolation and implement their own unique controls
  • Flexible swapping - when the player enters a new world, we simply assign a new IPlayerMode (more on this later)
  • Easily expandable - we can easily add new types of interactable objects or player controls

But wait, how do these actually work with player input? 

That's where our PlayerController script comes into play! Instead of cramming all of the controls and control schemes into a single script, the PlayerController acts as a bridge between the new Input System and our modular architecture. Unity's new input system handles input from any device - keyboards, mice, controllers, etc. - using a system of Actions. Each action triggers a callback when the input is performed and sends input data to the PlayerController. 

As you can see from this snippet,  the PlayerController receives the input callbacks and forwards the input data to the active IPlayerMode implementation. Then, in our GameManager script, we create and assign the current player mode as needed when the player transitions between worlds. 


Eventually, this all makes its way back to the correct PlayerMode implementation and allows the player to navigate each unique world. 


This modular architecture isn't just about clean code, it's about making our game feel alive, cohesive, and endlessly adaptable. By keeping each world's logic separate and easy to swap in and out, we're ensuring that players can seamlessly jump from each world without ever losing their sense of immersion. Plus, with Unity's new input system controller support is already built-in, letting players choose how they want to play. 

Next up on the agenda, I'll be working on our dynamic camera system so the camera's perspective matches the unique gameplay of each world. Thanks for checking out our game and stay tuned for more updates!

Leave a comment

Log in with itch.io to leave a comment.