Skip to the content.

RatKing Summary

This was my first collaborative project, and while the scope was ambitious, as is often the case with young development teams, it gave me the opportunity to design and implement a wide range of interconnected gameplay systems.

Developed Systems

Pathfinding and Navigation Graph

Unity’s built-in 2D NavMesh is designed primarily for top-down games and was unsuitable for RatKing’s side-on, tilemap-based platformer layout. To solve this, I developed a custom A* pathfinding system tailored specifically for platform traversal, including support for rigid platforms, one-way tiles, and ladders.

Graph optimization

Instead of using a naive tile-per-node graph, I optimized the system by identifying key traversal nodes (intersctions between platforms and ladders). This reduces the memory footprint of the navigation graph as well as improves its performance.

Results from the system. The green gizmo circles are traversable tiles, the purple ones are the actual nodes in the graph and the red lines represent the connection between them. Branching

Setting traversable/walkable points

Optimizing graph

Once the traversable tiles are known, they are stored in a list. Connective tiles along a platform are defined by having two walkable neighbours symmetrically around them. Those tiles are treated as redundant, as there is only one direction of movement to follow on them. All other tiles are stored in the optimized graph. The connection in the optimized graphs is formed by greedy walks along traversable tiles in the directions right, right-down, right-up, and optionally down (only if ladder). This handles horizontal, vertical, and 45-degree ground and one-way platforms.

Grid Inventory System

Implemented a modular, grid-based inventory system where items of varying shapes occupy multiple cells. The system features placement validation, real-time feedback, and integrates seamlessly with the throwing mechanic when items are dragged outside the inventory grid.

Architecture & Design Patterns

Inventory Item - a data-first approach

Collectible components interact with the proximity-based collection system, acting as the bridge between world objects and the inventory. Each Collectible holds a reference to an InventoryItemData ScriptableObject, which defines key inventory-related properties such as gold value, grid size, sprite, and display name.

When picked up, an InventoryObject is instantiated using the referenced InventoryItemData, creating an inventory-specific version of the item. The InventoryObject stores instance-specific state — including occupied grid cells, in-inventory position, and a reference to the original prefab to be used by the throwing mechanic.

Designer Tools

Throwing Mechanic - Physics-based projectile simulation

The throwing mechanic allows the player to accurately project where a thrown item will land, essential for strategically placing sound sources to distract patrolling enemies. To achieve this, the system predicts projectile trajectories in advance by running a fully isolated physics simulation.

Physics Simulation in an Isolated Scene

To avoid interfering with the main game world, a dedicated physics scene is created at runtime. This scene contains all static and dynamic objects from collision layers that interact with the Collectible layer.

How it works:

On Start (Once):

Before Throw Simulation (Once):

Each Simulation Frame:

After the simulation the line renderer is used to visually display the predicted trajectory to the player.

Designer Tools

The throw mechanic includes several adjustable parameters to support iteration and tuning:

ThrowWeak ThrowBreak

Data Persistence

Game data was persisted using prettified JSON files with a custom .rtk extension. Serialization and deserialization were handled via Unity’s built-in JsonUtility and System.Serializable attributes.

Architecture

A centralized DataPersistenceManager is responsible for coordinating save/load operations across all systems:

When a save file is read from disk:

This modular approach ensures that each system (e.g., inventory, upgrades, player state) can independently serialize and restore its own data without tightly coupling logic to the persistence layer.

back