Options live in GameSettings (inside SaveData.cs) and are drawn by one method, SettingsView.DrawOptions, which
both the SETTINGS popup (menu icon in the top bar) and the PAUSED menu use. Add a field with a sensible
default, a row or slider in DrawOptions, and read it where it matters. Old saves just get the default.
Steps
Field. Add it to class GameSettings in Assets/_Project/Scripts/Progression/SaveData.cs, with its default
and a comment naming who reads it:
public bool showFps; // the FPS counter in the corner (UI/FpsCounter)
Use JsonUtility-friendly types (bool, int, float, string; no Dictionary).
Draw it in SettingsView.DrawOptions (Assets/_Project/Scripts/UI/SettingsView.cs):
On/off: add a button to a Row(...) and flip the field on click, then save:
Slider:UIDraw.LayoutSlider("LABEL", value, min, max, format). Sliders apply live and save once, when the
mouse is released (the _dirty flag); add your slider to that comparison.
Labels are in caps, like the others.
Read it where it applies, through GameRoot.Instance.Save.settings or game.Save.settings (for example
GameAudio.MusicVolume, AtBatController reading aimSensitivity for aim speed, UI/FpsCounter).
Display options (window, resolution, frame rate) go through UI/DisplaySettings.Apply, which runs at startup
(GameRoot) and after each change (SettingsView.ApplyAndSave).
Today’s settings
MUSIC, SOUND, AIM SPEED (0.5x to 2.5x in 0.05 steps), TIMING RING, FPS COUNTER, CUTSCENES, REPLAYS, FULLSCREEN /
WINDOWED, V-SYNC, FPS CAP (MAX, 30, 60, 120, 144, 240; only with V-Sync off), and the resolution arrows.
CUTSCENES and REPLAYS (#40, #42) are the newest and a good model for an on/off option. They are stored inverted, so
“on” is the default for old saves and new players alike (false is JsonUtility’s default):
public bool skipCutscenes; // the match intro and the end-of-game cutscenes; on by default (false = play them)public bool noReplays; // the instant replay after a big home run (Batting/AtBatController.HitShow); on by default
and the row shows !settings.skipCutscenes. RunManager reads skipCutscenes before the intro and the end scenes
(Cutscenes); the hit show reads noReplays (Hit Show).
Check it works
Press Play, change it in SETTINGS (title screen) and in the PAUSED menu (Esc in an at-bat), quit, press Play
again and check it stuck. Tools → Home Run Derby → Delete Save File resets to the defaults.
Gotchas
The panels have fixed heights. The settings popup is 460 x 480 (LobbyNav) and the pause panel 400 x 616, or
668 in the batting cage (UIRoot.DrawPause). A new row may need those heights raised, or the bottom buttons spill
out.
No save version bump or migration is needed: JsonUtility fills a missing field with the class default. For a bool
that should default to on, name it the negative way (skipCutscenes, noReplays) or give it an initializer.
The panel sizes did not change when CUTSCENES and REPLAYS joined the toggle row (still 460 x 480 and 400 x 616 /
668), so check the row still fits at small window sizes.
Fullscreen and resolution do nothing in the Editor’s Game view; they apply in a build.