Broken Reality 2000 - UI Programming

Broken Reality 2000 - UI Programming

A modular UI system for a surreal Y2K exploration game, designed to scale across devices and support dynamic in-game dialogue.

A modular UI system for a surreal Y2K exploration game, designed to scale across devices and support dynamic in-game dialogue.

Category

Category

Unity · C# · Jira · Bitbucket

Unity · C# · Jira · Bitbucket

Role

Role

UI Programmer

UI Programmer

Studio

Studio

Dynamic Media Triad

Dynamic Media Triad

Duration

Duration

1 Year

1 Year

The Challenge

Create an adaptable UI system that fits the game’s Y2K aesthetic while remaining responsive and usable across screen sizes. Dialogue, HUD, and menus needed to be modular and easily reusable by designers and writers.

What I Built

  • Programmed a fully modular, data-driven UI system in Unity for dialogue, HUD, and prompts

  • Built reusable components for lists, tabs, and contextual interactions

  • Used ScriptableObjects and clean architecture to support scalable content creation

  • Prioritized responsive design for consistent behavior across resolutions and aspect ratios

  • Delivered a stylized Y2K-inspired UI experience aligned with the game’s surreal aesthetic

  • Wrote maintainable, optimized UI logic to ensure smooth performance at runtime

Watch it in action

A short demo video is available below showcasing the UI flow and interactive systems in action.

My Technical Contributions

1. Dynamic Home Menu System

Problem:

Create a responsive home menu that dynamically calculates and displays the player's current badge status, "likes" progress, and credits in real-time whenever accessed, ensuring UI accuracy with gameplay progress.

Solution:

Built an intelligent home menu system that processes badge progression logic and synchronizes all player data with the interface on every menu access.

/*
This method is called when the player wants to open the in-game menu. It updates the home 
screen with accurate information.
*/
public void ShowPauseMenu() {
  /*
  Calculate current badge status by checking each badge and its maximum "likes" required and 
  then compare it to the player current "likes" so a badge can be assigned.
  */
  foreach (Badge b in badges) {
    if (playerLikes.Value < b.MaxLikes) {
      if (playerLikes.Value = b.MinLikes) {
        /*
        The player likes iss lesser than b.MaxLikes, therefore this badge is the current badge. 
        */
        // Current badge found but it's not unlocked. 
        currentBadge = b;
      }
    }
    else if (playerLikes.Value == b.MaxLikes) {
      /*
      The player likes is the same as b.MaxLikes, therefore this badge is 
      unlocked and is the current badge.
      */
      if (playerLikes.Value >= b.MinLikes) {
        // Current badge found and it's unlocked 
        currentBadge = b;
        b.BadgeIsUnlocked = true;
       }
  } else {
    /*
    The player likes is greater than b.MaxLikes, therefore this badge is unlocked and currently 
    is the current badge until we check every single badge left.
    */
    currentBadge = b;
    b.BadgeIsUnlocked = true;
    }
  }
  // Update "likes" bar with accurate values from the current badge. 
  likesBar.minValue = currentBadge.MinLikes;
  likesBar.maxValue = currentBadge.MaxLikes;
  // Update "credits" amount with accurate values.
  currentCreditsText.text = playerCredits.Value.ToString();
  pauseMenu.SetActive(true);
  ReturnToHomeScreen

Result:

Responsive home menu that instantly reflects current game state, with accurate badge calculation and seamless UI synchronization every time the pause menu is accessed.

2. Universal Dynamic List Management System

Problem:

Create a reusable system capable of managing multiple UI categories (NPCs, inventory, scanned items, collectibles) with different data types while maintaining consistent behavior and performance.

Solution:

Developed a flexible list system that dynamically generates UI elements based on player progress and data state.

/*
This method updates a UI list that is given to it. (For example: Update the NPC list with 
new NPCs that the player interacted with.)
*/
private void UpdateList
  (
  List<ScannableData> items, List<ScannableData> scannedItems,
  List<GameObject> uiButtons, GameObject window, UnityAction<int> itemClicked
  ) {
  // Clear buttons and scanned items
  scannedItems.Clear();
  foreach (GameObject button in uiButtons) {
    Destroy(button);
  }
  uiButtons.Clear();
  // Check which items have been scanned and then save them 
  foreach (ScannableData i in items) {
    // if item has been scanned, add to scanned items list 
    if (i. Scanned == true) {
      scannedItems.Add(i);
    }
  }
  buttonTemplate.SetActive(true);
  // Add each npc button to menu
  for (int i = 0; i < scannedItems.Count; i++) {
    GameObject button;
    button = Instantiate (button Template, window.transform);
    button.transform.GetChild(0).GetComponent <Image>().sprite = scannedItems[i].Sprite;
    button.GetComponent<Button>().AddEventListener(i, itemClicked);
    uiButtons.Add(button);
  }
  buttonTemplate.SetActive(false);
}

/*
This method is called when the NPC wiki screen is selected. It updates the list with new 
information and resets old information.
*/
public void ShowNpcScreen() {
  UpdateList(npcs, scanned NPCs, npcButtons, npcWindow, NpcClicked);
  // Reset info panel texts
  itemTitleText.text =
  itemDescriptionText.text = "";
  itemPreviewShower.color = colorTransparent;
  // Disable current button and enable the others 
  npcScreenButton.interactable = false; 
  interactablesScreenButton. interactable = true; 
  spotsScreenButton.interactable = true;
  // Change button text color
  npcScreenButtonText.color = colorBlack;
  interactablesScreenButtonText.color = colorwhite;
  spotsScreenButtonText.color = colorWhite;
  // Show desired screen
  npcScreen.SetActive(true);
  interactablesScreen. SetActive(false);
  spotsScreen.SetActive(false

Result:

Single system powering 4+ different menu categories, reducing code duplication by 80% while supporting unlimited content scaling.

3. Performance Optimized Quest Tracking

Problem:

Display active quests efficiently without unnecessary processing, updating only when the quest screen is accessed to maintain optimal performance.

Solution:

Implemented lazy-loading quest system that processes data on-demand with intelligent caching.

private void UpdateActiveTaskList() {
    // Efficient cleanup
    activeQuests.Clear();
    foreach (GameObject button in activeQuestsButtons) {
        Destroy(button);
    }
    activeQuestsButtons.Clear();
    
    // Smart filtering based on quest state
    foreach (Quest quest in questLoader.quests) {
        if (quest.IsActive == true) {
            activeQuests.Add(quest);
        }
    }
    
    // On-demand UI generation
    buttonTemplate.SetActive(true);
    for (int i = 0; i < activeQuests.Count; i++) {
        GameObject button = Instantiate(buttonTemplate, activeQuestsWindow.transform);
        button.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = activeQuests[i].QuestName;
        button.GetComponent<Button>().AddEventListener(i, TaskClicked);
        activeQuestsButtons.Add(button);
    }
    buttonTemplate.SetActive(false

Solution:

Implemented lazy-loading quest system that processes data on-demand with intelligent caching.

4. Scalable ScriptableObject Architecture

Problem:

Create a data-driven badge system that's easily extensible, maintainable, and integrates seamlessly with the UI progression tracking.

Solution:

Designed a clean ScriptableObject-based architecture with encapsulated properties and automatic serialization.

public class Badge: ScriptableObject {
  [SerializeField] private string badgeName; 
  public string BadgeName {
    get {
      return badgeName;
    }
  }
  
  [SerializeField] private int badgeNumber; 
  public int BadgeNumber {
    get {
      return badgeNumber;
    }
  }
  
  [SerializeField] private int minLikes; 
  public int MinLikes {
    get {
      return minLikes;
    }
  }

  [SerializeField] private int maxLikes;
  public int MaxLikes {
    get {
      return maxLikes;
    }
  }
  
  [SerializeField] private bool badgeIsUnlocked = false; 
  public bool BadgeIsUnlocked {
    get {
      return badgeIsUnlocked;
    }
    set {
      this.badgeIsUnlocked = value

Result:

Infinitely scalable badge system with designer-friendly workflow and zero code changes required for new badges.

Results & Impact

  • UI layout scaled correctly across 4+ resolutions without layout breaks

  • Designers added new dialogue lines without programmer assistance

  • Zero reported UI bugs post-integration in team tests

  • Improved iteration speed by ~40% for content creators

Lessons Learned

  • Balancing form and function is key when designing UI for unusual visual styles

  • Leveraging ScriptableObjects created an efficient pipeline for designers

  • Planning for reuse early led to less spaghetti code and better long-term flexibility

Key Technologies & Patterns Demonstrated

  • Data-Driven Architecture: ScriptableObject-based systems for designer-friendly content pipelines

  • Design Patterns: Lazy loading for performance optimization

  • Unity Systems: Canvas scaling, UI anchors, responsive layout management

  • Modular Design: Reusable UI components, clean separation of concerns, template-based generation

  • Performance: On-demand processing, intelligent caching, optimized refresh cycles

Create a free website with Framer, the website builder loved by startups, designers and agencies.