No edit summary
No edit summary
Line 1: Line 1:
= Main menu =
The '''main menu''' is the first interactive screen in '''PC Simulator''' after the '''Menu''' scene loads. It is driven by the <code>MainMenu</code> behaviour, which initializes localization, restores settings, coordinates child pages through <code>MenuManager</code>, and starts asynchronous scene loads behind a '''Loading''' screen.
The '''main menu''' is the first interactive screen in '''PC Simulator''' after the '''Menu''' scene loads. It is driven by the <code>MainMenu</code> behaviour, which initializes localization, restores settings, coordinates child pages through <code>MenuManager</code>, and starts asynchronous scene loads behind a '''Loading''' screen.



Revision as of 18:13, 22 March 2026

The main menu is the first interactive screen in PC Simulator after the Menu scene loads. It is driven by the MainMenu behaviour, which initializes localization, restores settings, coordinates child pages through MenuManager, and starts asynchronous scene loads behind a Loading screen.

Quick facts
Unity scene Menu (project: Assets/Scenes/Menu.unity)
Core scripts MainMenu.cs, MenuManager.cs, FileMenu.cs
Singleton MainMenu.Instance
Save loads SaveManager.Loader + scene startRoomSceneIndex + GameData.room
Examples StreamingAssets/Examples/*.pc

Overview

The main menu is the hub for:

  • Opening and starting games from user save files (.pc) in the save folder
  • Launching the Tutorial scene and recording that the current tutorial revision was shown
  • Loading example presets from streaming assets (e.g. Classic.pc, versioned examples, Hidden Room.pc when triggered from in-game)
  • Navigating sub-pages (options, language, about, file tools, etc.) via a stacked UI managed by MenuManager
  • Quitting the application where supported

The title line alternates every 0.5 seconds between PC Simulator and PC Simulator_, with PC in orange using Unity UI Rich Text.

Localization

On Awake, MainMenu:

  1. Calls Localization.CreateContent()
  2. Sets language from PlayerPrefs key "Language", or from Application.systemLanguage mapped to codes such as EN, DE, ZH-CN, JA, etc.
  3. Subscribes to Localization.LanguageChanged to write the active language back to PlayerPrefs

Settings restored at menu start

Start restores:

  • FPSFpsSetting.RestoreSetting()
  • ResolutionResolutionSetting.RestoreSetting()
  • VolumeAudioListener.volume from PlayerPrefs "Volume" (default 1f)

Tutorial prompt

If PlayerPrefs.GetInt("TutorialVersion", -1) is less than the inspector field tutorialVersion, the object guideToTutorial is enabled; otherwise it is hidden. Calling Tutorial() sets TutorialVersion to the current value and loads the scene named "Tutorial".

Navigation stack (MenuManager)

MenuManager keeps a stack of active menu GameObject pages:

  • ShowMenu(string pageName) — finds a child whose hierarchy name equals pageName (e.g. Loading, FileInformation), hides the previous top if different, pushes and shows the new page
  • Back() — pops one level if the stack has more than one entry, reactivates the previous page
  • HideMenu(bool hide) — toggles visibility of the top page without changing the stack

Optional UI click sounds can play on ShowMenu and Back when enabled in the inspector.

Scene loads always call ShowMenu("Loading") first so the loading panel is visible during the async operation.

Loading screen behaviour

Loads use SceneManager.LoadSceneAsync with allowSceneActivation == false until progress reaches 0.9f.

  • Displayed percent: Mathf.Clamp01(operation.progress / 0.9f) * 100f
  • When progress >= 0.9f, the text shows 100%, waits 0.5 seconds, then sets allowSceneActivation = true
  • Label text: localized "Loading..." plus a new line and [percentage%]

Save files and examples

User saves (FileMenu)

  • Scans the save directory for files matching the save extension
  • Sorts by last write time, newest first
  • Each slot shows GameData.roomName and a Hardcore marker when GameData.hardcore is true
  • Clicking the name runs MainMenu.Instance.LoadFile(loader), which sets SaveManager.Loader and loads build index startRoomSceneIndex + GameData.room

Example presets

LoadExample(string name) reads StreamingAssets/Examples/ + name + .pc. On Android and WebGL the file is read via UnityWebRequest; elsewhere via File.ReadAllText. The string is parsed with DataLoader.LoadFromString, then the same LoadFile path as a normal save.

Scene index convention

LoadScene(int sceneBuildIndex) loads startRoomSceneIndex + sceneBuildIndex. Saves store a small integer room; the inspector base index aligns that id with the correct Unity scene in build order.

Exit

Exit() calls Application.Quit() (no visible effect in the Unity Editor).

Implementation reference

Components
Script Role
MainMenu Singleton; localization; tutorial gating; title blink (InvokeRepeating every 0.5 s); example and scene loading; quit
MenuManager Stack of menu pages; show, back, hide; optional click sound
FileMenu Lists saves, rename/metadata UI, delete, import external .pc

In-depth: source code

MainMenu.cs — lifecycle

Awake

  • Sets MainMenu.Instance so other scripts (e.g. FileMenu, HiddenRoom) can invoke LoadFile / LoadExample without serialized references.
  • Runs localization setup and applies stored or system-default language.
  • Persists language changes through Localization.LanguageChanged.

Start

  • Restores FPS and resolution from saved settings.
  • Shows or hides the tutorial guide based on TutorialVersion vs tutorialVersion.
  • Applies master volume to AudioListener.
  • Starts the repeating title animation.

Blinking

Toggles between two Rich Text strings on the title Text component for a blinking underscore effect.

LoadExample(string name)

Resolves StreamingAssets/Examples/{name}.pc, reads file bytes as text (platform-specific), then DataLoader.LoadFromString and LoadFile. On Android/WebGL the implementation uses UnityWebRequest and waits synchronously for completion.

LoadFile(DataLoader loader)

Assigns SaveManager.Loader = loader and loads startRoomSceneIndex + loader.GameData.room.

Tutorial()

Writes PlayerPrefs "TutorialVersion" and loads the "Tutorial" scene by name via LoadScene(string).

LoadAsync coroutine

  1. Shows the Loading menu page by name.
  2. Holds allowSceneActivation false while updating loadingText from async progress.
  3. After 0.9f progress, shows 100%, waits 0.5 s, then allows activation.

MenuManager.cs

Start

Initializes the stack: whichever entry in the menus array is already active is pushed as the initial page.

ShowMenu(string pageName)

Linear search for menu.name == pageName. If the stack top is a different object, deactivate it, push the new page, activate it. Same reference as current top results in no duplicate push.

Back

If menuStack.Count <= 1, return. Otherwise pop, deactivate popped page, activate new top.

HideMenu(bool hide)

Sets SetActive(!hide) on the stack top without popping.

FileMenu.cs

Start

Enumerates save files, maps path → last write time, sorts descending, calls AddSlot for each. Shows empty when the list is empty.

AddSlot(string path)

Wrapped in try/catch; failures are skipped. Instantiates a row, binds roomName and hardcore flag, wires Edit to file information and Name to MainMenu.Instance.LoadFile.

RefreshLoadButton / DeleteLoadButton

Refresh updates labels after metadata changes. Delete removes the file, destroys the row, updates empty state.

Import

Uses native file picker filtered to .pc. Verifies read permission, validates via DataLoader.LoadFromPath, copies into the save folder with SaveUtility.GetNewPath, then clears and rebuilds the slot list from disk.

Data flow summary

Action Code path
Player starts a save from the list MainMenu.LoadFileSaveManager.Loader → async load startRoomSceneIndex + room
Example or secret loads a preset LoadExample reads StreamingAssets/Examples/<name>.pcLoadFile
Any scene load from menu MenuManager.ShowMenu("Loading") then LoadAsync
Player confirms tutorial Tutorial() updates TutorialVersion → load "Tutorial"

See also

  • Tutorial scene and Tutorial.cs in-game steps
  • Pause menu and in-game MenuManager usage
  • Save format: DataLoader, GameData, SaveUtility