From 4cd18fb9f4780fd4a50a79611baffd057e4c7462 Mon Sep 17 00:00:00 2001 From: ckoch Date: Tue, 21 Jul 2026 15:58:37 -0400 Subject: [PATCH] UI tuner: handle both canvas modes, echo knob values In-game capture revealed two canvas families: ScreenSpaceOverlay/ ScaleWithScreenSize (the HUD, ref 1920x1080 match=1) and WorldSpace/ ConstantPixelSize (NamePlate and friends). Unity ignores referenceResolution in ConstantPixelSize mode, so the old HUD_SCALE knob could never affect the in-world labels. Split into HUD_SCALE (referenceResolution) and WORLD_SCALE (scaleFactor), applied per mode. Also echoes the knob values and logs APPLIED lines, so a stale console edit is immediately obvious instead of looking like the fix did nothing. Co-Authored-By: Claude Opus 4.8 --- tools/unity_uitune.cs | 65 ++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/tools/unity_uitune.cs b/tools/unity_uitune.cs index eb7e7c7..fc5975f 100644 --- a/tools/unity_uitune.cs +++ b/tools/unity_uitune.cs @@ -1,56 +1,63 @@ -// LIVE UI TUNER — paste into UnityExplorer's C# Console. Edit the knobs, Run, look, -// repeat. Nothing persists; relaunching reverts everything. +// LIVE UI TUNER — paste into UnityExplorer's C# Console. Edit knobs, Run, look, repeat. +// Nothing persists; a scene change or relaunch reverts everything. // -// IMPORTANT: run this IN-GAME (not the main menu). Different scenes have different -// canvases, and the overlapping text is in the gameplay HUD. +// This game has TWO canvas families, tuned by DIFFERENT properties: +// 1. ScreenSpaceOverlay + ScaleWithScreenSize ("Canvas", "Canvas in front") +// -> the HUD. Controlled by matchWidthOrHeight + referenceResolution. +// 2. WorldSpace + ConstantPixelSize ("NamePlate", etc.) +// -> in-world labels. Unity IGNORES referenceResolution here; +// ONLY scaleFactor does anything. // -// scaleFactor = (screenW/refW)^(1-match) * (screenH/refH)^match -// match=1 scales by HEIGHT (logical height stays 1080 = the design height). -// Lowering match shrinks logical height below 1080 and CRAMPS things vertically. +// The tuner prints the knob values it actually used, so you can confirm your edit took. // ---- KNOBS ----------------------------------------------------------------- -float MATCH = 1.0f; // 0 = scale by width, 1 = scale by height -// HUD_SCALE shrinks/grows the HUD *without* cramping the layout. -// <1 = smaller HUD + MORE logical room (use this to cure overlapping text) -// Implemented by raising referenceResolution.y, because CanvasScaler.scaleFactor -// is IGNORED in ScaleWithScreenSize mode (it only applies to ConstantPixelSize). -float HUD_SCALE = 1.0f; // try 0.95, 0.9, 0.85 -bool LIST_ONLY = false; // true = report current state, change nothing +float MATCH = 1.0f; // ScaleWithScreenSize only. 0=scale by width, 1=by height +float HUD_SCALE = 1.0f; // ScaleWithScreenSize only. <1 = smaller HUD + more room +float WORLD_SCALE = 1.0f; // ConstantPixelSize only. <1 = smaller in-world labels +bool LIST_ONLY = false; // true = report only, change nothing // ---------------------------------------------------------------------------- var log = new System.Text.StringBuilder(); +log.AppendLine($"KNOBS match={MATCH} hudScale={HUD_SCALE} worldScale={WORLD_SCALE} listOnly={LIST_ONLY}"); log.AppendLine($"SCREEN {UnityEngine.Screen.width}x{UnityEngine.Screen.height} " + $"aspect={(float)UnityEngine.Screen.width / UnityEngine.Screen.height:F4}"); foreach (var cs in UnityEngine.Object.FindObjectsOfType()) { - log.AppendLine($"BEFORE {cs.name}: mode={cs.uiScaleMode} ref={cs.referenceResolution} " + + var cv = cs.GetComponent(); + string render = cv ? cv.renderMode.ToString() : "?"; + log.AppendLine($"BEFORE {cs.name} [{cs.uiScaleMode}/{render}] ref={cs.referenceResolution} " + $"match={cs.matchWidthOrHeight} scaleFactor={cs.scaleFactor}"); if (!LIST_ONLY) { - cs.matchWidthOrHeight = MATCH; - if (HUD_SCALE > 0f && System.Math.Abs(HUD_SCALE - 1f) > 0.0001f) + if (cs.uiScaleMode == UnityEngine.UI.CanvasScaler.ScaleMode.ScaleWithScreenSize) { - // effective scale = screenH / refH, so refH = designH / HUD_SCALE - var r = cs.referenceResolution; - cs.referenceResolution = new UnityEngine.Vector2(r.x, 1080f / HUD_SCALE); - log.AppendLine($" refResolution {r} -> {cs.referenceResolution}"); + cs.matchWidthOrHeight = MATCH; + // effective scale = screenH / refH => refH = 1080 / HUD_SCALE + if (HUD_SCALE > 0f && System.Math.Abs(HUD_SCALE - 1f) > 0.0001f) + { + var r = cs.referenceResolution; + cs.referenceResolution = new UnityEngine.Vector2(r.x, 1080f / HUD_SCALE); + log.AppendLine($" APPLIED ref {r} -> {cs.referenceResolution}"); + } + } + else if (cs.uiScaleMode == UnityEngine.UI.CanvasScaler.ScaleMode.ConstantPixelSize) + { + // referenceResolution is ignored in this mode; scaleFactor is the only lever + if (WORLD_SCALE > 0f && System.Math.Abs(WORLD_SCALE - 1f) > 0.0001f) + { + float old = cs.scaleFactor; + cs.scaleFactor = WORLD_SCALE; + log.AppendLine($" APPLIED scaleFactor {old} -> {cs.scaleFactor}"); + } } } - // report the resulting logical canvas the UI is laid out in - var cv = cs.GetComponent(); float sf = cv ? cv.scaleFactor : 0f; if (sf > 0) log.AppendLine($"AFTER {cs.name}: effectiveScale={sf:F4} " + $"logicalCanvas={UnityEngine.Screen.width / sf:F0}x{UnityEngine.Screen.height / sf:F0}"); } -// Every canvas in the scene — the overlapping text may live on one we haven't touched -foreach (var cv in UnityEngine.Object.FindObjectsOfType()) - log.AppendLine($"CANVAS {cv.name} mode={cv.renderMode} scale={cv.scaleFactor:F4} " + - $"hasScaler={(cv.GetComponent() != null)} " + - $"sortOrder={cv.sortingOrder}"); - UnityExplorer.ExplorerCore.Log(log.ToString());