MainControl.cs in Undertale-Changer Template: Purpose, Architecture, and Usage
MainControl.cs is the central MonoBehaviour orchestrator that initializes core services, manages scene states (Normal, Overworld, Battle), and provides a singleton gateway for the Undertale-Changer Template's runtime systems.
Located at Assets/Scripts/UCT/Core/MainControl.cs in the arch-aik/undertale-changer-template repository, this script functions as the brain of the game. It bootstraps the initialization pipeline, maintains global state across scenes, and coordinates high-level subsystems including audio, combat, and UI management.
Core Responsibilities of MainControl.cs
Singleton Pattern and Global Access
MainControl implements a thread-safe singleton pattern to ensure exactly one master controller exists throughout the game lifecycle. The implementation exposes a static instance property at line 111:
public static MainControl Instance { get; private set; }
This design allows any script to access global game state without direct references:
// Access the master controller from any context
var main = MainControl.Instance;
main.SettingsStorage.Pause = true;
Scene State Management
The controller tracks three distinct high-level modes through the SceneState enum defined at lines 34-39:
public enum SceneState { Normal, Overworld, Battle }
The StartWithSceneState() method (lines 48-90) instantiates appropriate subsystems based on the current enum value. When sceneState changes, the controller automatically triggers initialization routines for battle mechanics or overworld navigation accordingly.
Service Initialization
The initialization pipeline follows a strict lifecycle:
- Awake() (lines 22-47) – Loads saved preferences, assigns the singleton instance, and triggers first-time setup
- Start() (lines 66-99) – Configures fade transitions, volume levels, UI components, and event tables
- Initialization() & InitializationScene() (lines 43-104) – Loads language packs, item databases, and localized UI text
Key Methods and Implementation Details
HitPlayer() and Combat Utilities
The HitPlayer() method (lines 59-83) provides standardized damage application with integrated feedback:
// Reduce player HP by 10 and trigger effects
bool tookDamage = MainControl.Instance.HitPlayer(10);
if (tookDamage)
{
// Damage applied successfully; visual flash and audio play automatically
}
This method handles damage calculation, sound-effect triggering, and screen-flash coordination through the AudioControl and PlayerControl subsystems.
Chase Mode Visual Effects
When enemies detect the player in overworld sections, EnterChase() (lines 85-122) and ExitChase() animate global lighting and UI elements to create urgency:
// Trigger red-alert lighting and speed lines
MainControl.Instance.EnterChase();
// Restore normal lighting when escape succeeds
MainControl.Instance.ExitChase();
These methods manipulate global light tweens and post-processing effects to signal pursuit states without modifying core game logic.
Debug Utilities
The DebugUpdate() method (lines 100-131) provides hot-key shortcuts for rapid iteration:
- F5 – Reloads the current scene via
GameUtilityService.RefreshTheScene() - Ctrl+I – Toggles invincibility by flipping
playerControl.keepInvincible
These tools execute only in development builds, allowing designers to test combat scenarios without restarting the application.
Practical Code Examples
Accessing Subsystem References
MainControl maintains cached references to frequently accessed controllers:
// Reference pattern used throughout the codebase
MainControl.Instance.AudioControl.PlaySound("UI_Select");
MainControl.Instance.BattleControl.StartEncounter("Enemy_Papyrus");
Switching Game Modes
Transition between exploration and combat states programmatically:
// Change state and trigger battle initialization
MainControl.Instance.sceneState = MainControl.SceneState.Battle;
MainControl.Instance.InitializationBattle();
Global Visual Transitions
Coordinate fade effects through the central controller:
// Trigger scene-wide fade-out
MainControl.Instance.StartCoroutine(
MainControl.Instance.FadeOutTransition()
);
Related Subsystems and Dependencies
MainControl.cs directly references the following core files to maintain system coherence:
PlayerControl.cs(Assets/Scripts/UCT/Control/PlayerControl.cs) – Stores player statistics, inventory, and debug invincibility flagsOverworldControl.cs(Assets/Scripts/UCT/Control/OverworldControl.cs) – Handles map navigation and overworld entity managementBattleControl.cs(Assets/Scripts/UCT/Control/BattleControl.cs) – Manages turn-based combat flow and enemy configurationAudioControl.cs(Assets/Scripts/UCT/Control/AudioControl.cs) – Centralizes audio mixer routing and sound-effect playbackLanguagePackControl.cs(Assets/Scripts/UCT/Control/LanguagePackControl.cs) – Loads localized UI strings based on player settingsSettingsStorage.cs(Assets/Scripts/UCT/Settings/SettingsStorage.cs) – Persists global preferences including volume and resolution
These dependencies are wired during the Awake() and Start() phases (lines 27-30, 46-50, 70-84), ensuring all subsystems are available before gameplay begins.
Summary
- MainControl.cs serves as the singleton orchestrator at
Assets/Scripts/UCT/Core/MainControl.cs, providing global access viaMainControl.Instance - It manages three distinct scene states (Normal, Overworld, Battle) through the
SceneStateenum andStartWithSceneState()method - Initialization occurs in two phases:
Awake()for singleton setup andStart()for subsystem configuration - Combat utilities like
HitPlayer()integrate damage calculation with audiovisual feedback - Debug shortcuts (F5 for reload, Ctrl+I for invincibility) streamline development workflows through
DebugUpdate()
Frequently Asked Questions
Where is MainControl.cs located in the Undertale-Changer Template repository?
The file resides at Assets/Scripts/UCT/Core/MainControl.cs according to the source tree in arch-aik/undertale-changer-template. This location follows Unity's standard Assets folder structure, placing core architecture scripts in a dedicated Core subdirectory for organizational clarity.
How does MainControl.cs implement the singleton pattern?
The script uses a static auto-property public static MainControl Instance { get; private set; } defined at line 111, populated during the Awake() lifecycle method. This approach guarantees exactly one instance persists across scene loads while preventing external modification of the reference.
What scene states does MainControl.cs manage?
The controller defines three states in the SceneState enum at lines 34-39: Normal (menu/initialization), Overworld (exploration and NPC interaction), and Battle (turn-based combat encounters). The StartWithSceneState() method routes initialization logic based on the active state value.
How do I access player health data through MainControl.cs?
Access player statistics through the cached PlayerControl reference: MainControl.Instance.playerControl.hp. For damage application, use the abstraction method MainControl.Instance.HitPlayer(damageAmount), which modifies health internally while triggering associated sound and visual effects.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →