From 13de0ea9ea1b0d76946603f631e738f8977d2212 Mon Sep 17 00:00:00 2001 From: John Seong Date: Fri, 20 Mar 2026 15:26:40 -0400 Subject: [PATCH 01/14] Updated --- .../Scripts/Functions/FunctionPlotter.cs | 26 ++++++++++++++----- .../Game/GraphCalculatorAnalysisControls.cs | 4 +-- .../Assets/Scripts/Game/LevelManager.cs | 8 ++++-- .../Assets/Scripts/UI/LineRendererUI.cs | 6 +++-- .../Scripts/UI/RiemannStripRendererUI.cs | 8 ++++-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs index e253d30..35e28ac 100644 --- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs +++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs @@ -131,7 +131,12 @@ void UpdateGraphRevealAnimation() } float dur = Mathf.Max(0.05f, graphRevealDurationSeconds); - _graphRevealT01 = Mathf.MoveTowards(_graphRevealT01, 1f, Time.deltaTime / dur); + // Lorenz butterfly already animates via _lorenzPhaseScroll; horizontal alpha reveal uses grid-x and + // can zero the whole polyline when revealX sits on gx0 (progress 0 → all vertices faded). + if (functionType == FunctionType.ChaosLorenzButterflyX) + _graphRevealT01 = 1f; + else + _graphRevealT01 = Mathf.MoveTowards(_graphRevealT01, 1f, Time.deltaTime / dur); if (functionType == FunctionType.ChaosLorenzButterflyX) { @@ -158,16 +163,17 @@ void PushGraphRevealToRenderers() float gx0 = MapDisplayX(xStart) + go.x; float gx1 = MapDisplayX(xEnd) + go.x; - lineRenderer.SetGraphRevealFade(_graphRevealT01, gx0, gx1); + float revealT = functionType == FunctionType.ChaosLorenzButterflyX ? 1f : _graphRevealT01; + lineRenderer.SetGraphRevealFade(revealT, gx0, gx1); if (derivRenderer != null) - derivRenderer.SetGraphRevealFade(_graphRevealT01, gx0, gx1); + derivRenderer.SetGraphRevealFade(revealT, gx0, gx1); if (functionType == FunctionType.AeroDragPolarTriple) { if (overlayParasitic != null) - overlayParasitic.SetGraphRevealFade(_graphRevealT01, gx0, gx1); + overlayParasitic.SetGraphRevealFade(revealT, gx0, gx1); if (overlayInduced != null) - overlayInduced.SetGraphRevealFade(_graphRevealT01, gx0, gx1); + overlayInduced.SetGraphRevealFade(revealT, gx0, gx1); } } @@ -177,7 +183,8 @@ public void ApplyGraphRevealToLineRenderer(LineRendererUI lr) if (lr == null || lineRenderer == null) return; Vector2Int go = lineRenderer.gridSize / 2; - lr.SetGraphRevealFade(_graphRevealT01, MapDisplayX(xStart) + go.x, MapDisplayX(xEnd) + go.x); + float revealT = functionType == FunctionType.ChaosLorenzButterflyX ? 1f : _graphRevealT01; + lr.SetGraphRevealFade(revealT, MapDisplayX(xStart) + go.x, MapDisplayX(xEnd) + go.x); } public void InitPlotFunction() @@ -331,6 +338,13 @@ private void PlotFunction(FunctionType type) lineRenderer = LineRendererUI.FindPrimaryCurve(); derivRenderer = FindAnyObjectByType(); + // Lorenz: disable per-vertex horizontal fade (see UpdateGraphRevealAnimation); derivative uses same flag. + bool lorenzButterfly = type == FunctionType.ChaosLorenzButterflyX; + if (lineRenderer != null) + lineRenderer.enableHorizontalGraphReveal = !lorenzButterfly; + if (derivRenderer != null) + derivRenderer.enableHorizontalGraphReveal = !lorenzButterfly; + if (lineRenderer != null) { points.Clear(); diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs index 19d4463..5834069 100644 --- a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs +++ b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs @@ -107,7 +107,7 @@ void LateUpdate() && (!Mathf.Approximately(integralCachedXStart, plotter.xStart) || !Mathf.Approximately(integralCachedXEnd, plotter.xEnd))) { - riemann.RebuildForGraphingCalculator(plotter, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill); + riemann.RebuildForGraphingCalculator(plotter, primaryCurve, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill); integralCachedXStart = plotter.xStart; integralCachedXEnd = plotter.xEnd; if (primaryCurve.transform.parent != null) @@ -168,7 +168,7 @@ void OnIntegralPressed() integralBarsActive = true; RefreshButtonInteractable(); - riemann.RebuildForGraphingCalculator(plotter, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill); + riemann.RebuildForGraphingCalculator(plotter, primaryCurve, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill); integralCachedXStart = plotter.xStart; integralCachedXEnd = plotter.xEnd; if (primaryCurve != null && primaryCurve.transform.parent != null) diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index af7be04..0196009 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -947,9 +947,10 @@ private void EnsureRiemannRenderer() { var curveLineRt = curveRenderer.GetComponent(); Transform lineParent = curveLineRt != null ? curveLineRt.parent : null; - if (lineParent != null && riemannRenderer.transform.parent != lineParent) + if (lineParent != null) { - riemannRenderer.transform.SetParent(lineParent, false); + if (riemannRenderer.transform.parent != lineParent) + riemannRenderer.transform.SetParent(lineParent, false); var riemannRt = riemannRenderer.GetComponent(); if (curveLineRt != null && riemannRt != null) { @@ -960,6 +961,9 @@ private void EnsureRiemannRenderer() riemannRt.sizeDelta = curveLineRt.sizeDelta; riemannRt.localScale = curveLineRt.localScale; } + + riemannRenderer.gameObject.SetActive(true); + riemannRenderer.enabled = true; riemannRenderer.transform.SetSiblingIndex(0); } } diff --git a/First Principles/Assets/Scripts/UI/LineRendererUI.cs b/First Principles/Assets/Scripts/UI/LineRendererUI.cs index 33ffefa..bcdb053 100644 --- a/First Principles/Assets/Scripts/UI/LineRendererUI.cs +++ b/First Principles/Assets/Scripts/UI/LineRendererUI.cs @@ -16,7 +16,9 @@ public class LineRendererUI : Graphic /// public static LineRendererUI FindPrimaryCurve() { - var all = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include); + // Active hierarchy only: inactive clones / hidden UI must not steal grid sizing from the visible graph + // (breaks Riemann strips & anything sampling f(x) with a mismatched grid origin). + var all = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); foreach (var lr in all) { if (lr == null || lr.gameObject == null) @@ -29,7 +31,7 @@ public static LineRendererUI FindPrimaryCurve() return lr; } - return all != null && all.Length > 0 ? all[0] : null; + return null; } public Vector2Int gridSize; diff --git a/First Principles/Assets/Scripts/UI/RiemannStripRendererUI.cs b/First Principles/Assets/Scripts/UI/RiemannStripRendererUI.cs index aff750a..c11b479 100644 --- a/First Principles/Assets/Scripts/UI/RiemannStripRendererUI.cs +++ b/First Principles/Assets/Scripts/UI/RiemannStripRendererUI.cs @@ -144,7 +144,8 @@ public void Rebuild(LevelDefinition def, FunctionPlotter plotter) } /// Riemann rectangles over the graphing calculator window (no ). - public void RebuildForGraphingCalculator(FunctionPlotter plotter, int rectCount, RiemannRule rule, Color fillColor) + /// Main for this graph (same as calculator); avoids wrong grid if multiple curves exist. + public void RebuildForGraphingCalculator(FunctionPlotter plotter, LineRendererUI primaryCurve, int rectCount, RiemannRule rule, Color fillColor) { strips.Clear(); color = fillColor; @@ -155,7 +156,10 @@ public void RebuildForGraphingCalculator(FunctionPlotter plotter, int rectCount, return; } - SyncGridSizeFromPrimaryCurve(); + if (primaryCurve != null && primaryCurve.gridSize.x >= 1 && primaryCurve.gridSize.y >= 1) + gridSize = primaryCurve.gridSize; + else + SyncGridSizeFromPrimaryCurve(); if (grid == null) grid = GetComponentInParent(); if (grid != null && (gridSize.x < 1 || gridSize.y < 1)) From d1eb1bf6f9724594c07044e56aaee796134d80d6 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 18:30:18 -0400 Subject: [PATCH 02/14] Updated --- Assets/Scripts.meta | 8 + Assets/Scripts/Game.meta | 8 + .../Game/DerivativePopAnimator.cs.meta | 2 + .../Assets/Resources/Localization/ar.txt | 14 +- .../Assets/Resources/Localization/cs.txt | 15 +- .../Assets/Resources/Localization/de.txt | 14 +- .../Assets/Resources/Localization/en.txt | 17 +- .../Assets/Resources/Localization/es.txt | 14 +- .../Assets/Resources/Localization/fr.txt | 14 +- .../Assets/Resources/Localization/hi.txt | 14 +- .../Assets/Resources/Localization/it.txt | 15 +- .../Assets/Resources/Localization/ja.txt | 14 +- .../Assets/Resources/Localization/ko.txt | 15 +- .../Assets/Resources/Localization/pl.txt | 15 +- .../Assets/Resources/Localization/ru.txt | 15 +- .../Assets/Resources/Localization/ur.txt | 14 +- .../Assets/Resources/Localization/zh.txt | 14 +- First Principles/Assets/Scenes/Menu.unity | 4 +- .../Scripts/Functions/FunctionPlotter.cs | 57 +- .../Assets/Scripts/Game/GameLevelCatalog.cs | 18 +- .../Scripts/Game/GameplayViewportBounds.cs | 12 +- .../Scripts/Game/GraphCalculatorToolbar.cs | 4 + .../Scripts/Game/GraphObstacleGenerator.cs | 46 + .../Assets/Scripts/Game/GraphPinchZoom.cs | 4 + .../Assets/Scripts/Game/LevelManager.cs | 368 +++++++- .../Scripts/Game/PlayerControllerUI2D.cs | 32 +- .../Scripts/Game/StageRoleplayLibrary.cs | 22 +- .../Scripts/Math/LorenzAttractorSamples.cs | 56 +- .../Assets/Scripts/UI/DeviceLayout.cs | 13 +- .../Scripts/UI/GameplayScreenTouchZones.cs | 129 +++ .../UI/GameplayScreenTouchZones.cs.meta | 2 + .../Assets/Scripts/UI/LabelManager.cs | 22 +- .../Assets/Scripts/UI/MathArticlesOverlay.cs | 69 +- .../Assets/Scripts/UI/MenuTutorialOverlay.cs | 4 +- .../Assets/Scripts/UI/MobileInputBridge.cs | 46 +- .../Assets/Scripts/UI/MobileTouchControls.cs | 310 ------ .../Scripts/UI/MobileTouchControls.cs.meta | 11 - .../LiberationSans SDF - Fallback.asset | 305 +++++- .../UserSettings/Layouts/default-6000.dwlt | 305 ++++-- Packages/manifest.json | 39 + Packages/packages-lock.json | 287 ++++++ ProjectSettings/AudioManager.asset | 23 + ProjectSettings/ClusterInputManager.asset | 6 + ProjectSettings/DynamicsManager.asset | 45 + ProjectSettings/EditorBuildSettings.asset | 8 + ProjectSettings/EditorSettings.asset | 52 + ProjectSettings/GraphicsSettings.asset | 68 ++ ProjectSettings/InputManager.asset | 296 ++++++ ProjectSettings/MemorySettings.asset | 35 + ProjectSettings/MultiplayerManager.asset | 9 + ProjectSettings/NavMeshAreas.asset | 93 ++ ProjectSettings/PackageManagerSettings.asset | 42 + ProjectSettings/Physics2DSettings.asset | 57 ++ ProjectSettings/PresetManager.asset | 7 + ProjectSettings/ProjectSettings.asset | 893 ++++++++++++++++++ ProjectSettings/ProjectVersion.txt | 2 + ProjectSettings/QualitySettings.asset | 347 +++++++ ProjectSettings/TagManager.asset | 46 + ProjectSettings/TimeManager.asset | 14 + ProjectSettings/UnityConnectSettings.asset | 40 + ProjectSettings/VFXManager.asset | 20 + ProjectSettings/VersionControlSettings.asset | 7 + 62 files changed, 3969 insertions(+), 528 deletions(-) create mode 100644 Assets/Scripts.meta create mode 100644 Assets/Scripts/Game.meta create mode 100644 Assets/Scripts/Game/DerivativePopAnimator.cs.meta create mode 100644 First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs create mode 100644 First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs.meta delete mode 100644 First Principles/Assets/Scripts/UI/MobileTouchControls.cs delete mode 100644 First Principles/Assets/Scripts/UI/MobileTouchControls.cs.meta create mode 100644 Packages/manifest.json create mode 100644 Packages/packages-lock.json create mode 100644 ProjectSettings/AudioManager.asset create mode 100644 ProjectSettings/ClusterInputManager.asset create mode 100644 ProjectSettings/DynamicsManager.asset create mode 100644 ProjectSettings/EditorBuildSettings.asset create mode 100644 ProjectSettings/EditorSettings.asset create mode 100644 ProjectSettings/GraphicsSettings.asset create mode 100644 ProjectSettings/InputManager.asset create mode 100644 ProjectSettings/MemorySettings.asset create mode 100644 ProjectSettings/MultiplayerManager.asset create mode 100644 ProjectSettings/NavMeshAreas.asset create mode 100644 ProjectSettings/PackageManagerSettings.asset create mode 100644 ProjectSettings/Physics2DSettings.asset create mode 100644 ProjectSettings/PresetManager.asset create mode 100644 ProjectSettings/ProjectSettings.asset create mode 100644 ProjectSettings/ProjectVersion.txt create mode 100644 ProjectSettings/QualitySettings.asset create mode 100644 ProjectSettings/TagManager.asset create mode 100644 ProjectSettings/TimeManager.asset create mode 100644 ProjectSettings/UnityConnectSettings.asset create mode 100644 ProjectSettings/VFXManager.asset create mode 100644 ProjectSettings/VersionControlSettings.asset diff --git a/Assets/Scripts.meta b/Assets/Scripts.meta new file mode 100644 index 0000000..bad281c --- /dev/null +++ b/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c194c683aa28491a8619be39f6eb721 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Game.meta b/Assets/Scripts/Game.meta new file mode 100644 index 0000000..7cb8ef5 --- /dev/null +++ b/Assets/Scripts/Game.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83d33fbff670449c3946494137623be9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Game/DerivativePopAnimator.cs.meta b/Assets/Scripts/Game/DerivativePopAnimator.cs.meta new file mode 100644 index 0000000..1ab328a --- /dev/null +++ b/Assets/Scripts/Game/DerivativePopAnimator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1af5b27b1c8234106ab2bc0f7907f835 \ No newline at end of file diff --git a/First Principles/Assets/Resources/Localization/ar.txt b/First Principles/Assets/Resources/Localization/ar.txt index 8204374..b23ec65 100644 --- a/First Principles/Assets/Resources/Localization/ar.txt +++ b/First Principles/Assets/Resources/Localization/ar.txt @@ -12,7 +12,6 @@ ui.jump=قفز ui.move=تحرك ui.keyboard_hint_mobile=(لوحة المفاتيح: الأسهم / المسافة) hud.stage=المرحلة -controls.mobile=تحرك ◀ ▶ · قفز مس (لوحة المفاتيح: الأسهم / المسافة) controls.desktop=تحرك · قفز مسافة controls.calculator=آلة رسومية اكتب f(u) · Trans · Scale · قرصة · رجوع graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=زعيم: لولب النسبة الذهبية (قطبي لوغاريت level.46=تحويلات: فورييه — طيف sinc level.47=تحويلات: لابلاس — تضاؤل أسي level.48=زعيم: ماندلبروت — الختام (شريحة هروب كسيرية) -level.49=زعيم: فراشة لورينز — الختام (جذاب غريب) -level.50=فيزياء C: نابض–كتلة حركة توافقية (قانون هوك، بلا تخميد) +level.49=زعيم: جاذب لورينز — نظرية الفوضى (جذاب غريب) +level.50=زعيم: ثقب أسود — بئر جاذبية (مقطع 1/r) +level.51=فيزياء C: نابض–كتلة حركة توافقية (قانون هوك، بلا تخميد) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/cs.txt b/First Principles/Assets/Resources/Localization/cs.txt index ec1eef5..1178c7b 100644 --- a/First Principles/Assets/Resources/Localization/cs.txt +++ b/First Principles/Assets/Resources/Localization/cs.txt @@ -11,6 +11,7 @@ level_select.cat.finale=Pokročilé a boss level_select.cat.transforms=Transformace level_select.cat.final_boss=Finální boss level_select.cat.spring_physics=Pružina a SHM +level_select.cat.big_o=Notace Big O ui.math_tips=Tipy k matematice ui.back_menu=Zpět do menu ui.graphing_calculator_mode=Grafická kalkulačka @@ -24,7 +25,6 @@ ui.jump=Skok ui.move=Pohyb ui.keyboard_hint_mobile=(klávesnice: šipky / Mezerník) hud.stage=FÁZE -controls.mobile=Pohyb ◀ ▶ · Skok klepnutí (klávesnice: šipky / Mezerník) controls.desktop=Pohyb · Skok Mezerník controls.calculator=Grafická kalkulačka Zadejte f(u) · Trans · Měřítko · Špetka · Zpět graph.label_fu=f(u) = @@ -100,5 +100,14 @@ level.45=BOSS: zlatá spirála (logaritmická polární) level.46=Transformace: Fourier — sinc (spektrum) level.47=Transformace: Laplace — exponenciální pokles level.48=BOSS: Mandelbrot — finále (fraktálový únikový řez) -level.49=BOSS: Lorenzův motýl — finále (podivný atraktor) -level.50=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení) \ No newline at end of file +level.49=BOSS: Lorenzův atraktor — teorie chaosu (podivný atraktor) +level.50=BOSS: černá díra — gravitační jáma (řez ∝ 1/r) +level.51=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) \ No newline at end of file diff --git a/First Principles/Assets/Resources/Localization/de.txt b/First Principles/Assets/Resources/Localization/de.txt index c44dffe..a694657 100644 --- a/First Principles/Assets/Resources/Localization/de.txt +++ b/First Principles/Assets/Resources/Localization/de.txt @@ -12,7 +12,6 @@ ui.jump=Sprung ui.move=Bewegen ui.keyboard_hint_mobile=(Tastatur: Pfeile / Leertaste) hud.stage=PHASE -controls.mobile=Bewegen ◀ ▶ · Sprung Tipp (Tastatur: Pfeile / Leertaste) controls.desktop=Bewegen · Sprung Leertaste controls.calculator=Grafikrechner f(u) eingeben · Trans · Maßstab · Pinch · Zurück graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=BOSS: Goldener-Spiralen-Logarithmus (Polar) level.46=Transformationen: Fourier — sinc-Spektrum level.47=Transformationen: Laplace — exponentieller Abfall level.48=BOSS: Mandelbrot — Finale (Fraktal-Escape-Schnitt) -level.49=BOSS: Lorenz-Attraktor — Finale (seltsamer Attraktor) -level.50=Physik C: Feder–Masse SHM (Hooke, ungedämpft) +level.49=BOSS: Lorenz-Attraktor — Chaos-Theorie (seltsamer Attraktor) +level.50=BOSS: Schwarzes Loch — Gravitationsbrunnen (1/r-Schnitt) +level.51=Physik C: Feder–Masse SHM (Hooke, ungedämpft) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index 4313118..373e3f3 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -12,6 +12,7 @@ level_select.cat.finale=Advanced & boss level_select.cat.transforms=Transforms level_select.cat.final_boss=Final boss level_select.cat.spring_physics=Spring & SHM +level_select.cat.big_o=Big O notation ui.math_tips=Math tips & snippets ui.back_menu=Back to Menu ui.graphing_calculator_mode=Graphing\ncalculator @@ -25,7 +26,8 @@ ui.jump=Jump ui.move=Move ui.keyboard_hint_mobile=(keyboard: arrows / Space) hud.stage=STAGE -controls.mobile=Move ◀ ▶ · Jump tap (keyboard: arrows / Space) +controls.mobile=Left hold ◀ · Right hold ▶ · Swipe up jump (keyboard: arrows / Space) +controls.guide_overlay=Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nSwipe up anywhere — jump\n\nKeyboard: Arrow keys move · Space jumps controls.desktop=Move · Jump Space controls.calculator=Graphing calculator Type f(u) · Deriv · · Trans · Scale · Pinch · Back graph.calc_deriv=Deriv @@ -112,5 +114,14 @@ level.45=BOSS: golden ratio spiral (logarithmic polar) level.46=Transforms: Fourier — sinc spectrum (rect ↔ sinc) level.47=Transforms: Laplace — causal exponential decay level.48=BOSS: Mandelbrot — finale (fractal escape slice) -level.49=BOSS: Lorenz butterfly — finale (strange attractor) -level.50=Physics C: spring–mass SHM (Hooke's law, undamped) +level.49=BOSS: Lorenz attractor — Chaos Theory (strange attractor) +level.50=BOSS: Black hole — gravity well (1/r slice) +level.51=Physics C: spring–mass SHM (Hooke's law, undamped) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/es.txt b/First Principles/Assets/Resources/Localization/es.txt index 3e5dd9b..99375f2 100644 --- a/First Principles/Assets/Resources/Localization/es.txt +++ b/First Principles/Assets/Resources/Localization/es.txt @@ -12,7 +12,6 @@ ui.jump=Saltar ui.move=Mover ui.keyboard_hint_mobile=(teclado: flechas / Espacio) hud.stage=FASE -controls.mobile=Mover ◀ ▶ · Saltar tocar (teclado: flechas / Espacio) controls.desktop=Mover · Saltar Espacio controls.calculator=Calculadora gráfica Escribir f(u) · Trans · Escala · Pellizco · Atrás graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=JEFE: espiral áurea (polar logarítmica) level.46=Transformadas: Fourier — sinc (espectro) level.47=Transformadas: Laplace — decaimiento exponencial level.48=JEFE: Mandelbrot — final (corte de escape fractal) -level.49=JEFE: mariposa de Lorenz — final (atractor extraño) -level.50=Física C: resorte–masa SHM (ley de Hooke, sin amortiguación) +level.49=JEFE: atractor de Lorenz — teoría del caos (atractor extraño) +level.50=JEFE: agujero negro — pozo gravitatorio (corte 1/r) +level.51=Física C: resorte–masa SHM (ley de Hooke, sin amortiguación) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/fr.txt b/First Principles/Assets/Resources/Localization/fr.txt index 515a3d3..1ef83a4 100644 --- a/First Principles/Assets/Resources/Localization/fr.txt +++ b/First Principles/Assets/Resources/Localization/fr.txt @@ -12,7 +12,6 @@ ui.jump=Saut ui.move=Déplacer ui.keyboard_hint_mobile=(clavier : flèches / Espace) hud.stage=NIVEAU -controls.mobile=Déplacer ◀ ▶ · Saut tapoter (clavier : flèches / Espace) controls.desktop=Déplacer · Saut Espace controls.calculator=Calculatrice graphique Saisir f(u) · Trans · Échelle · Pincer · Retour graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=BOSS : spirale d’or (polaire logarithmique) level.46=Transformations : Fourier — sinc (spectre) level.47=Transformations : Laplace — décroissance exponentielle level.48=BOSS : Mandelbrot — finale (tranche d’échappement fractale) -level.49=BOSS : papillon de Lorenz — finale (attracteur étrange) -level.50=Physique C : ressort–masse SHM (loi de Hooke, non amorti) +level.49=BOSS : attracteur de Lorenz — théorie du chaos (attracteur étrange) +level.50=BOSS : trou noir — puits de gravité (tranche 1/r) +level.51=Physique C : ressort–masse SHM (loi de Hooke, non amorti) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/hi.txt b/First Principles/Assets/Resources/Localization/hi.txt index aa2fc05..160f050 100644 --- a/First Principles/Assets/Resources/Localization/hi.txt +++ b/First Principles/Assets/Resources/Localization/hi.txt @@ -13,7 +13,6 @@ ui.jump=कूद ui.move=चलें ui.keyboard_hint_mobile=(कीबोर्ड: तीर / स्पेस) hud.stage=चरण -controls.mobile=चलें ◀ ▶ · कूद टैप (कीबोर्ड: तीर / स्पेस) controls.desktop=चलें · कूद स्पेस controls.calculator=ग्राफ़िंग कैलकुलेटर f(u) लिखें · Trans · Scale · पिंच · वापस graph.label_fu=f(u) = @@ -82,5 +81,14 @@ level.45=BOSS: स्वर्ण अनुपात सर्पिल (लघ level.46=रूपांतरण: फूरियर — सिंक स्पेक्ट्रम level.47=रूपांतरण: लाप्लास — घातांकी क्षय level.48=BOSS: मैंडेलब्रॉट — अंतिम (फ्रैक्टल एस्केप स्लाइस) -level.49=BOSS: लोरेंज तितली — अंतिम (विलक्षण आकर्षक) -level.50=फिजिक्स C: स्प्रिंग–द्रव्यमान SHM (हूक का नियम, अवमंदन रहित) +level.49=BOSS: लोरेंज आकर्षक — अराजकता सिद्धांत (विलक्षण आकर्षक) +level.50=BOSS: ब्लैक होल — गुरुत्वाकर्षण कुआँ (1/r स्लाइस) +level.51=फिजिक्स C: स्प्रिंग–द्रव्यमान SHM (हूक का नियम, अवमंदन रहित) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/it.txt b/First Principles/Assets/Resources/Localization/it.txt index e109b7e..5f28fa9 100644 --- a/First Principles/Assets/Resources/Localization/it.txt +++ b/First Principles/Assets/Resources/Localization/it.txt @@ -11,6 +11,7 @@ level_select.cat.finale=Avanzati e boss level_select.cat.transforms=Trasformate level_select.cat.final_boss=Boss finale level_select.cat.spring_physics=Molla e SHM +level_select.cat.big_o=Notazione Big O ui.math_tips=Suggerimenti di matematica ui.back_menu=Torna al menu ui.graphing_calculator_mode=Calcolatrice grafica @@ -24,7 +25,6 @@ ui.jump=Salta ui.move=Muoviti ui.keyboard_hint_mobile=(tastiera: frecce / Spazio) hud.stage=STADIO -controls.mobile=Muoviti ◀ ▶ · Salta tocco (tastiera: frecce / Spazio) controls.desktop=Muoviti · Salta Spazio controls.calculator=Calcolatrice grafica Digita f(u) · Trasf · Scala · Pizzica · Indietro graph.label_fu=f(u) = @@ -100,5 +100,14 @@ level.45=BOSS: spirale aurea (polare logaritmica) level.46=Trasformate: Fourier — sinc (spettro) level.47=Trasformate: Laplace — decadimento esponenziale level.48=BOSS: Mandelbrot — finale (sezione escape frattale) -level.49=BOSS: farfalla di Lorenz — finale (attrattore strano) -level.50=Fisica C: molla–massa SHM (legge di Hooke, non smorzato) +level.49=BOSS: attrattore di Lorenz — teoria del caos (attrattore strano) +level.50=BOSS: buco nero — pozzo gravitazionale (sezione 1/r) +level.51=Fisica C: molla–massa SHM (legge di Hooke, non smorzato) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ja.txt b/First Principles/Assets/Resources/Localization/ja.txt index e2ba1ae..f1d219c 100644 --- a/First Principles/Assets/Resources/Localization/ja.txt +++ b/First Principles/Assets/Resources/Localization/ja.txt @@ -12,7 +12,6 @@ ui.jump=ジャンプ ui.move=移動 ui.keyboard_hint_mobile=(キーボード:矢印/スペース) hud.stage=ステージ -controls.mobile=移動 ◀ ▶ · ジャンプ タップ (キーボード:矢印/スペース) controls.desktop=移動 · ジャンプ スペース controls.calculator=グラフ電卓 f(u) を入力 · Trans · Scale · ピンチ · 戻る graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=BOSS:黄金螺旋(対数・極座標) level.46=変換:フーリエ — sincスペクトラム level.47=変換:ラプラス — 指数減衰 level.48=BOSS:マンデルブロ — フィナーレ(フラクタル脱出断面) -level.49=BOSS:ローレンツの蝶 — フィナーレ(ストレンジアトラクター) -level.50=物理C:ばね–質点の単振動(フックの法則、減衰なし) +level.49=BOSS:ローレンツアトラクター — カオス理論(ストレンジアトラクター) +level.50=BOSS:ブラックホール — 重力の井戸(1/r 断面) +level.51=物理C:ばね–質点の単振動(フックの法則、減衰なし) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ko.txt b/First Principles/Assets/Resources/Localization/ko.txt index b703cd5..ae8ee1b 100644 --- a/First Principles/Assets/Resources/Localization/ko.txt +++ b/First Principles/Assets/Resources/Localization/ko.txt @@ -17,6 +17,7 @@ level_select.cat.finale=심화 & 보스 level_select.cat.transforms=변환 level_select.cat.final_boss=최종 보스 level_select.cat.spring_physics=스프링·단진동 +level_select.cat.big_o=빅오 표기법 ui.math_tips=수학 팁 모음 ui.back_menu=메뉴로 ui.graphing_calculator_mode=그래프 계산기 @@ -29,7 +30,6 @@ ui.jump=점프 ui.move=이동 ui.keyboard_hint_mobile=(키보드: 방향키 / 스페이스) hud.stage=스테이지 -controls.mobile=이동 ◀ ▶ · 점프 (키보드: 방향키 / 스페이스) controls.desktop=이동 · 점프 스페이스 controls.calculator=그래프 계산기 f(u) 입력 · Trans · Scale · 핀치 · 뒤로 graph.label_fu=f(u) = @@ -98,5 +98,14 @@ level.45=보스: 황금비 나선 (로그 극좌표) level.46=변환: 푸리에 — sinc 스펙트럼 level.47=변환: 라플라스 — 지수 감쇠 level.48=보스: 만델브로 — 피날레 (프랙탈 탈출 단면) -level.49=보스: 로렌츠 나비 — 피날레 (이상한 끌개) -level.50=물리 C: 스프링–질점 SHM (훅의 법칙, 비감쇠) +level.49=보스: 로렌츠 어트랙터 — 카오스 이론 (이상한 끌개) +level.50=보스: 블랙홀 — 중력 우물 (1/r 단면) +level.51=물리 C: 스프링–질점 SHM (훅의 법칙, 비감쇠) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/pl.txt b/First Principles/Assets/Resources/Localization/pl.txt index fe27aa8..9f9def5 100644 --- a/First Principles/Assets/Resources/Localization/pl.txt +++ b/First Principles/Assets/Resources/Localization/pl.txt @@ -11,6 +11,7 @@ level_select.cat.finale=Zaawansowane i boss level_select.cat.transforms=Transformaty level_select.cat.final_boss=Finałowy boss level_select.cat.spring_physics=Sprężyna i SHM +level_select.cat.big_o=Notacja dużego O ui.math_tips=Wskazówki matematyczne ui.back_menu=Powrót do menu ui.graphing_calculator_mode=Kalkulator graficzny @@ -24,7 +25,6 @@ ui.jump=Skok ui.move=Ruch ui.keyboard_hint_mobile=(klawiatura: strzałki / Spacja) hud.stage=ETAP -controls.mobile=Ruch ◀ ▶ · Skok dotknij (klawiatura: strzałki / Spacja) controls.desktop=Ruch · Skok Spacja controls.calculator=Kalkulator graficzny Wpisz f(u) · Trans · Skala · Szczyp · Wstecz graph.label_fu=f(u) = @@ -100,5 +100,14 @@ level.45=BOSS: spirala złotego podziału (logarytmiczna, biegunowa) level.46=Transformaty: Fourier — sinc (widmo) level.47=Transformaty: Laplace — wykładniczy zanik level.48=BOSS: Mandelbrot — finał (fraktalny przekrój ucieczki) -level.49=BOSS: motyl Lorenza — finał (dziwny atraktor) -level.50=Fizyka C: sprężyna–masa SHM (prawo Hooka, nietłumione) +level.49=BOSS: atraktor Lorenza — teoria chaosu (dziwny atraktor) +level.50=BOSS: czarna dziura — studnia grawitacji (przekrój 1/r) +level.51=Fizyka C: sprężyna–masa SHM (prawo Hooka, nietłumione) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ru.txt b/First Principles/Assets/Resources/Localization/ru.txt index 38e7881..0201b7b 100644 --- a/First Principles/Assets/Resources/Localization/ru.txt +++ b/First Principles/Assets/Resources/Localization/ru.txt @@ -11,6 +11,7 @@ level_select.cat.finale=Сложные и босс level_select.cat.transforms=Преобразования level_select.cat.final_boss=Финальный босс level_select.cat.spring_physics=Пружина и ГС +level_select.cat.big_o=О-нотация ui.math_tips=Советы по математике ui.back_menu=В меню ui.graphing_calculator_mode=Графический калькулятор @@ -24,7 +25,6 @@ ui.jump=Прыжок ui.move=Движение ui.keyboard_hint_mobile=(клавиатура: стрелки / Пробел) hud.stage=ЭТАП -controls.mobile=Движение ◀ ▶ · Прыжок тап (клавиатура: стрелки / Пробел) controls.desktop=Движение · Прыжок Пробел controls.calculator=Граф. калькулятор Ввод f(u) · Транс · Масштаб · Щипок · Назад graph.label_fu=f(u) = @@ -100,5 +100,14 @@ level.45=БОСС: золотая спираль (логарифмическая level.46=Преобразования: Фурье — sinc-спектр level.47=Преобразования: Лаплас — затухание level.48=БОСС: Мандельброт — финал (фрактальный срез побега) -level.49=БОСС: эффект бабочки Лоренца — финал (странный аттрактор) -level.50=Физика C: пружина–масса ГС (закон Гука, без затухания) +level.49=БОСС: аттрактор Лоренца — теория хаоса (странный аттрактор) +level.50=БОСС: чёрная дыра — гравитационная яма (сечение 1/r) +level.51=Физика C: пружина–масса ГС (закон Гука, без затухания) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ur.txt b/First Principles/Assets/Resources/Localization/ur.txt index e9c290f..f7651c9 100644 --- a/First Principles/Assets/Resources/Localization/ur.txt +++ b/First Principles/Assets/Resources/Localization/ur.txt @@ -13,7 +13,6 @@ ui.jump=چھلانگ ui.move=حرکت ui.keyboard_hint_mobile=(کی بورڈ: تیر / اسپیس) hud.stage=اسٹیج -controls.mobile=حرکت ◀ ▶ · چھلانگ تھپتھی (کی بورڈ: تیر / اسپیس) controls.desktop=حرکت · چھلانگ اسپیس controls.calculator=گرافنگ کیلکولیٹر f(u) لکھیں · Trans · Scale · پنچ · واپس graph.label_fu=f(u) = @@ -82,5 +81,14 @@ level.45=بوس: سنہری تناسب سنئلی (لوگ قطبی) level.46=تبدیل: فوریے — سینک سپیکٹرم level.47=تبدیل: لاپلاس — نماتی زوال level.48=بوس: مینڈلبرو — اختتام (فرکٹل فرار سلائس) -level.49=بوس: لورینز تیتلی — اختتام (عجیب اٹریکٹر) -level.50=فزکس C: سپرنگ–عنصر جرم SHM (ہوک کا قانون، ڈیمپنگ کے بغیر) +level.49=بوس: لورینز اٹریکٹر — کیس تھیوری (عجیب اٹریکٹر) +level.50=باس: بلیک ہول — کشش ثقل کنواں (1/r سلائس) +level.51=فزکس C: سپرنگ–عنصر جرم SHM (ہوک کا قانون، ڈیمپنگ کے بغیر) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/zh.txt b/First Principles/Assets/Resources/Localization/zh.txt index 6f990e4..08e3fbf 100644 --- a/First Principles/Assets/Resources/Localization/zh.txt +++ b/First Principles/Assets/Resources/Localization/zh.txt @@ -12,7 +12,6 @@ ui.jump=跳跃 ui.move=移动 ui.keyboard_hint_mobile=(键盘:方向键 / 空格) hud.stage=阶段 -controls.mobile=移动 ◀ ▶ · 跳跃 点按 (键盘:方向键 / 空格) controls.desktop=移动 · 跳跃 空格 controls.calculator=图形计算器 输入 f(u) · Trans · Scale · 双指缩放 · 返回 graph.label_fu=f(u) = @@ -80,5 +79,14 @@ level.45=BOSS:黄金比例螺旋(对数极坐标) level.46=变换:傅里叶 — sinc 频谱 level.47=变换:拉普拉斯 — 指数衰减 level.48=BOSS:曼德博 — 终章(分形逃逸截面) -level.49=BOSS:洛伦兹蝴蝶 — 终章(奇异吸引子) -level.50=物理C:弹簧–质点简谐振动(胡克定律,无阻尼) +level.49=BOSS:洛伦兹吸引子 — 混沌理论(奇异吸引子) +level.50=BOSS:黑洞 — 引力势阱(1/r 切片) +level.51=物理C:弹簧–质点简谐振动(胡克定律,无阻尼) +level.52=Big O: O(1) — constant time +level.53=Big O: O(log n) — logarithmic growth +level.54=Big O: O(√n) — sublinear root growth +level.55=Big O: O(n) — linear growth +level.56=Big O: O(n log n) — n log n growth +level.57=Big O: O(n²) — quadratic growth +level.58=Big O: O(n³) — cubic growth +level.59=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Scenes/Menu.unity b/First Principles/Assets/Scenes/Menu.unity index d03d1c7..12d6ced 100644 --- a/First Principles/Assets/Scenes/Menu.unity +++ b/First Principles/Assets/Scenes/Menu.unity @@ -436,8 +436,8 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: -380} - m_SizeDelta: {x: 964.3611, y: 110} + m_AnchoredPosition: {x: 0, y: -392} + m_SizeDelta: {x: 964.3611, y: 118} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1004057114 MonoBehaviour: diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs index 35e28ac..5508128 100644 --- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs +++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs @@ -131,7 +131,7 @@ void UpdateGraphRevealAnimation() } float dur = Mathf.Max(0.05f, graphRevealDurationSeconds); - // Lorenz butterfly already animates via _lorenzPhaseScroll; horizontal alpha reveal uses grid-x and + // Lorenz / chaos-theory stage already animates via _lorenzPhaseScroll; horizontal alpha reveal uses grid-x and // can zero the whole polyline when revealX sits on gx0 (progress 0 → all vertices faded). if (functionType == FunctionType.ChaosLorenzButterflyX) _graphRevealT01 = 1f; @@ -201,6 +201,8 @@ public void RefreshLine() public void RefreshDeriv() { + if (derivRenderer == null) + return; derivRenderer.enabled = false; derivRenderer.enabled = true; } @@ -382,9 +384,13 @@ private void PlotFunction(FunctionType type) else if (differentiate == false) { dPoints.Clear(); - - // Refresh ONLY the derivative graph & hide on the UI - RefreshDeriv(); + // Do not call RefreshDeriv() here — it re-enabled the Graphic every frame while stale + // points could remain on DerivRendererUI (list is only aliased to dPoints when differentiate is true). + if (derivRenderer != null) + { + derivRenderer.points.Clear(); + derivRenderer.enabled = false; + } } // Boss: show classic Mandelbrot set in c-plane behind the grid (1D slice curve on top). @@ -591,9 +597,15 @@ private float EvaluateFunctionY(FunctionType type, float transA, float transK, f FunctionType.TransformFourierSinc => TransformFourierSincY(u, transA, transC), FunctionType.TransformLaplaceCausalDecay => TransformLaplaceCausalDecayY(u, transA, transC, baseN), - // Final boss: Lorenz x(t) slice (normalized), “butterfly” chaotic sensitivity. + // Final boss: Lorenz x(t) slice (normalized); chaos theory / sensitive dependence. FunctionType.ChaosLorenzButterflyX => ChaosLorenzButterflyYEval(u, transA, transC), + // Boss: Newtonian-style potential slice Φ ∝ −1/√(r²+ε²) (softened 1/r “gravity well”). + FunctionType.PhysicsGravityWellInverseSqrt => GravityWellInverseSqrtY(u, transA, transC, transD), + + // CS / algorithms: growth shape n ln n for n>0 (u plays the role of n on the horizontal axis). + FunctionType.BigONLogN => BigONLogNY(u, transA, transC), + _ => 0f }; } @@ -743,6 +755,19 @@ float ChaosLorenzButterflyYEval(float u, float a, float c) return a * LorenzAttractorSamples.SampleNormalizedX(t) + c; } + static float GravityWellInverseSqrtY(float u, float a, float c, float softFromD) + { + float eps = Mathf.Max(0.08f, Mathf.Abs(softFromD)); + float r2 = u * u + eps * eps; + return a * (-1f / Mathf.Sqrt(r2)) + c; + } + + static float BigONLogNY(float u, float a, float c) + { + float n = Mathf.Max(u, 0.02f); + return a * (n * Mathf.Log(n)) + c; + } + /// y = k + √(R² − u²) for |u|≤R; outside domain uses k so samples stay finite (flat shoulder). private static float CircleUpperY(float u, float radiusSigned, float k) { @@ -1026,9 +1051,19 @@ private void UpdateEquationText(FunctionType type, float transA, float transK, f } case FunctionType.ChaosLorenzButterflyX: equationText.text = - $@"\(\text{{Butterfly effect}}\) — Lorenz \(x(t)\), \(\sigma=10,\rho=28,\beta=8/3\), \(u={k}(x-{d})\approx t\)\n" + + $@"\(\text{{Chaos theory}}\) — Lorenz \(x(t)\), \(\sigma=10,\rho=28,\beta=8/3\), \(u={k}(x-{d})\approx t\)\n" + $@"Tiny initial changes diverge on the attractor — this curve is a time slice of that chaos, normalized to read on the grid."; break; + case FunctionType.PhysicsGravityWellInverseSqrt: + equationText.text = + $@"\(\text{{Gravity well}}\) slice \(f \propto -1/\sqrt{{u^{2}+\varepsilon^{2}}}+C,\; u={k}(x-{d}),\; \varepsilon\sim |{d}|\)\n" + + $@"Softened \(1/r\) potential — steep near the center, flattens away; a readable stand-in for “falling into” a deep well."; + break; + case FunctionType.BigONLogN: + equationText.text = + $@"\(O(n\log n)\) growth mood: \(f \propto u\ln u + C,\; u=\max({k}(x-{d}),\text{{small}})\)\n" + + $@"Classic merge-sort / balanced-tree flavor: work grows a bit faster than linear, slower than quadratic."; + break; case FunctionType.CustomExpression: { string esc = EscapeTmpRichText(customExpression); @@ -1202,8 +1237,14 @@ public enum FunctionType /// Causal \(H(t)\,e^{-st}\) — Laplace-table exponential decay for \(t\ge 0\); \(s\sim \texttt{baseN}/100\). TransformLaplaceCausalDecay, - /// Final boss: Lorenz attractor \(x(t)\) (normalized), butterfly / sensitive dependence visualization. - ChaosLorenzButterflyX + /// Final boss: Lorenz attractor \(x(t)\) (normalized); chaos theory / sensitive dependence visualization. + ChaosLorenzButterflyX, + + /// Boss: softened \(1/r\) gravitational potential slice (deep well at \(u=0\)). + PhysicsGravityWellInverseSqrt, + + /// CS: \(O(n\log n)\) growth shape via \(u\ln u\) (positive branch). + BigONLogN } /* diff --git a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs index 0c01328..06784b2 100644 --- a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs +++ b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs @@ -85,8 +85,17 @@ public static class GameLevelCatalog "Transforms: Fourier — sinc spectrum (rect ↔ sinc)", "Transforms: Laplace — causal exponential decay", "BOSS: Mandelbrot — finale (fractal escape slice)", - "BOSS: Lorenz butterfly — finale (strange attractor)", - "Physics C: spring–mass SHM (Hooke's law, undamped)" + "BOSS: Lorenz attractor — Chaos Theory (strange attractor)", + "BOSS: Black hole — gravity well (1/r slice)", + "Physics C: spring–mass SHM (Hooke's law, undamped)", + "Big O: O(1) — constant time", + "Big O: O(log n) — logarithmic growth", + "Big O: O(√n) — sublinear root growth", + "Big O: O(n) — linear growth", + "Big O: O(n log n) — n log n growth", + "Big O: O(n²) — quadratic growth", + "Big O: O(n³) — cubic growth", + "Big O: O(2ⁿ) — exponential (base 2)" }; public static int LevelCount => DisplayNames.Length; @@ -103,8 +112,9 @@ public static class GameLevelCatalog new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 34, 40), new LevelSelectCategory("level_select.cat.finale", "Advanced & boss", 41, 45), new LevelSelectCategory("level_select.cat.transforms", "Transforms", 46, 47), - new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 48, 49), - new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 50, 50), + new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 51, 51), + new LevelSelectCategory("level_select.cat.big_o", "Big O notation", 52, 59), + new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 48, 50), }; /// First index of the contiguous Aerospace: block (must match sample levels). diff --git a/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs b/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs index 4a88c1b..36c59c0 100644 --- a/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs +++ b/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs @@ -42,11 +42,21 @@ public static GameplayPlayBounds Compute(RectTransform cartesianPlane, Vector2In ? Mathf.Max(16f, w * 0.022f) : Mathf.Max(10f, w * 0.018f); + // Narrow portrait: reserve a bit more side margin so the playfield matches the visibly inset graph. + float aspectTall = h / Mathf.Max(1f, w); + if (!DeviceLayout.IsTabletLike() && aspectTall > 1.45f) + hPad = Mathf.Max(hPad, w * 0.026f); + float topPad = Mathf.Max(44f, h * 0.065f); float bottomPad = Mathf.Max(12f, h * 0.022f); if (DeviceLayout.PreferOnScreenGameControls) - bottomPad = Mathf.Max(bottomPad, DeviceLayout.TouchControlBarHeight + 36f); + { + if (DeviceLayout.GameplayUsesFullScreenTouchZones) + bottomPad = Mathf.Max(bottomPad, 28f); + else + bottomPad = Mathf.Max(bottomPad, DeviceLayout.TouchControlBarHeight + 36f); + } float xMin = hPad / unitX; float xMax = gridSize.x - hPad / unitX; diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs index b7d2402..75797ca 100644 --- a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs +++ b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs @@ -128,6 +128,10 @@ private void ApplyZoomWindow(float halfWidthMultiplier) plot.xStart = mid - half; plot.xEnd = mid + half; plot.step = Mathf.Clamp((plot.xEnd - plot.xStart) / 480f, 0.004f, 0.42f); + plot.InitPlotFunction(); + var lm = FindAnyObjectByType(); + if (lm != null) + lm.RefreshAllTickLabels(); } private void RefreshHint() diff --git a/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs b/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs index 3312a34..3a89be4 100644 --- a/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs +++ b/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs @@ -43,6 +43,36 @@ public class GraphWorld /// When true, keeps the avatar inside horizontally and uses them for fall death. public bool hasPlayBounds; public GameplayPlayBounds playBounds; + + /// Call after is recomputed (e.g. rotation) so the exit band stays in the padded region. + public void RefreshFinishFromPlayBounds() + { + if (!hasPlayBounds) + return; + const float finishWidth = 1f; + var b = playBounds; + finish = new GridRect(Mathf.Max(b.XMax - finishWidth, b.XMin), b.XMax, b.YMin, b.YMax); + } +} + +/// Caches grid-space AABB for a platform/hazard/finish visual; reapplies pixel rect when the plane size changes. +public sealed class GraphObstacleUILayout : MonoBehaviour +{ + public GridRect gridRect; + + public void ApplyPixelLayout(float unitWidth, float unitHeight) + { + var rt = transform as RectTransform; + if (rt == null) + return; + + float pxX = gridRect.xMin * unitWidth; + float pxY = gridRect.yMin * unitHeight; + float pxW = (gridRect.xMax - gridRect.xMin) * unitWidth; + float pxH = (gridRect.yMax - gridRect.yMin) * unitHeight; + rt.anchoredPosition = new Vector2(pxX, pxY); + rt.sizeDelta = new Vector2(pxW, pxH); + } } /// @@ -67,6 +97,16 @@ public void SetLayout(RectTransform obstaclesRoot, Vector2Int gridSize, float un obstacleSprite = RuntimeUiPolish.Rounded9Slice != null ? RuntimeUiPolish.Rounded9Slice : TryGetSquareSprite(); } + /// Repositions platform/hazard/finish quads after the Cartesian plane is scaled (rotation, safe area). + public void RefreshObstaclePixelLayout() + { + if (obstaclesRoot == null) + return; + var layouts = obstaclesRoot.GetComponentsInChildren(true); + for (int i = 0; i < layouts.Length; i++) + layouts[i].ApplyPixelLayout(unitWidth, unitHeight); + } + /// Required for Riemann stair mode; used to evaluate exact f at sample x. /// Inset AABB in grid units; null = full grid, no player hard clamp. public GraphWorld GenerateWorld( @@ -433,6 +473,9 @@ private void CreateFinishExitGradient(GridRect finishBand) rt.anchoredPosition = new Vector2(pxX, pxY); rt.sizeDelta = new Vector2(pxW, pxH); + var finishLayout = go.AddComponent(); + finishLayout.gridRect = rect; + var grad = go.AddComponent(); grad.raycastTarget = false; grad.SetGradientColors( @@ -463,6 +506,9 @@ private void CreateRectVisual(string name, GridRect rect, Color color) rt.anchoredPosition = new Vector2(pxX, pxY); rt.sizeDelta = new Vector2(pxW, pxH); + var layout = go.AddComponent(); + layout.gridRect = rect; + var img = go.AddComponent(); img.sprite = obstacleSprite; bool isHazard = name.StartsWith("Hazard", System.StringComparison.OrdinalIgnoreCase); diff --git a/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs b/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs index 7d54d90..c850611 100644 --- a/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs +++ b/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs @@ -52,5 +52,9 @@ private void ApplyHalfWidthScale(float ratio) plot.xStart = mid - half; plot.xEnd = mid + half; plot.step = Mathf.Clamp((plot.xEnd - plot.xStart) / 520f, 0.004f, 0.42f); + plot.InitPlotFunction(); + var lm = FindAnyObjectByType(); + if (lm != null) + lm.RefreshAllTickLabels(); } } diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 0196009..6cb9045 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -41,6 +41,9 @@ public class LevelManager : MonoBehaviour private DerivRendererUI derivRenderer; private GridRendererUI gridRenderer; private RectTransform cartesianPlaneRect; + /// Scene-authored Cartesian plane size (fallback 1820×980); used to scale down on narrow portrait screens. + private Vector2 _cartesianGameplayDesignSize = new Vector2(1820f, 980f); + private Vector2 _lastSyncedCartesianRectSize = new Vector2(-1f, -1f); private GraphObstacleGenerator obstacleGenerator; private PlayerControllerUI2D playerController; @@ -82,6 +85,9 @@ public class LevelManager : MonoBehaviour [Tooltip("Total time from level ready until controls unlock from spotlight (fade in + hold + fade out).")] [SerializeField] private float spawnSpotlightTotalSeconds = 1.5f; + [Tooltip("Full-screen touch control instructions (mobile only), shown before spawn spotlight.")] + [SerializeField] private float mobileControlGuideSeconds = 1.5f; + [Tooltip("Optional; if null, loads Resources/UI_SpotlightDim then Shader.Find.")] [SerializeField] private Shader spawnSpotlightShader; @@ -241,6 +247,13 @@ private void SetupReferences() if (cartesianPlaneRect == null) cartesianPlaneRect = curveRenderer.GetComponent(); + if (cartesianPlaneRect != null) + { + Vector2 sd = cartesianPlaneRect.sizeDelta; + if (sd.sqrMagnitude > 10_000f) + _cartesianGameplayDesignSize = sd; + } + obstacleGenerator = GetComponent(); if (obstacleGenerator == null) obstacleGenerator = gameObject.AddComponent(); @@ -259,7 +272,7 @@ private void SetupReferences() EnsureRiemannRenderer(); var mainCanvas = FindAnyObjectByType(); if (mainCanvas != null && !graphCalculatorMode) - MobileTouchControls.EnsureForGameCanvas(mainCanvas.transform); + GameplayScreenTouchZones.EnsureForGameCanvas(mainCanvas.transform); // Wire callbacks. playerController.SetDeathCallback(RestartCurrentLevel); @@ -267,6 +280,91 @@ private void SetupReferences() if (derivRenderer != null) playerController.BindDerivativeRenderer(derivRenderer); ConfigureGameBackButtonDestination(); + + if (!graphCalculatorMode) + FitCartesianPlaneForGameplay(); + } + + /// + /// Scales the fixed-design Cartesian plane to fit the grid background (portrait phones, notches, touch HUD). + /// + private void FitCartesianPlaneForGameplay() + { + if (graphCalculatorMode || cartesianPlaneRect == null) + return; + + var parent = cartesianPlaneRect.parent as RectTransform; + if (parent == null) + return; + + float pw = parent.rect.width; + float ph = parent.rect.height; + if (pw < 2f || ph < 2f) + return; + + bool mobile = DeviceLayout.PreferOnScreenGameControls; + float hPad = mobile ? 8f : 14f; + float topReserve = mobile ? 172f : 138f; + float bottomReserve = mobile ? DeviceLayout.TouchHintVerticalOffset + 32f : 70f; + + float maxW = Mathf.Max(64f, pw - hPad * 2f); + float maxH = Mathf.Max(64f, ph - topReserve - bottomReserve); + + float baseW = Mathf.Max(1f, _cartesianGameplayDesignSize.x); + float baseH = Mathf.Max(1f, _cartesianGameplayDesignSize.y); + float s = Mathf.Min(1f, maxW / baseW, maxH / baseH); + + Vector2 newSize = new Vector2(baseW * s, baseH * s); + float yNudge = mobile ? (bottomReserve - topReserve) * 0.2f : 0f; + + cartesianPlaneRect.anchorMin = new Vector2(0.5f, 0.5f); + cartesianPlaneRect.anchorMax = new Vector2(0.5f, 0.5f); + cartesianPlaneRect.pivot = new Vector2(0.5f, 0.5f); + + if ((cartesianPlaneRect.sizeDelta - newSize).sqrMagnitude < 0.25f && + Mathf.Abs(cartesianPlaneRect.anchoredPosition.y - yNudge) < 0.5f) + return; + + cartesianPlaneRect.sizeDelta = newSize; + cartesianPlaneRect.anchoredPosition = new Vector2(0f, yNudge); + } + + private void SyncGameplayLayoutToCartesianPlane() + { + if (graphCalculatorMode || cartesianPlaneRect == null || gridRenderer == null || + obstacleGenerator == null || playerController == null) + return; + + Vector2 sz = cartesianPlaneRect.rect.size; + var gridSize = gridRenderer.gridSize; + + if (obstaclesRoot != null) + { + obstaclesRoot.sizeDelta = sz; + float uw = sz.x / gridSize.x; + float uh = sz.y / gridSize.y; + obstacleGenerator.SetLayout(obstaclesRoot, gridSize, uw, uh); + obstacleGenerator.RefreshObstaclePixelLayout(); + } + + playerController.ApplyResponsivePlaneLayout(cartesianPlaneRect, gridSize); + } + + private void LateUpdate() + { + if (graphCalculatorMode) + return; + if (cartesianPlaneRect == null || gridRenderer == null || obstacleGenerator == null || playerController == null) + return; + + FitCartesianPlaneForGameplay(); + + Vector2 sz = cartesianPlaneRect.rect.size; + if ((sz - _lastSyncedCartesianRectSize).sqrMagnitude < 0.01f) + return; + + _lastSyncedCartesianRectSize = sz; + SyncGameplayLayoutToCartesianPlane(); } /// @@ -369,7 +467,8 @@ private void EnterGraphCalculatorMode() functionPlotter.SetEquationExtraSuffix(""); functionPlotter.SetCustomExpression("x^2"); functionPlotter.autoScaleVertical = false; - functionPlotter.autoScaleHorizontal = false; + // Stretch [xStart,xEnd] across the grid so pinch / Scale update _autoMidX/_autoScaleX; axis ticks track (LabelManager). + functionPlotter.autoScaleHorizontal = true; if (curveRenderer != null) { @@ -816,6 +915,11 @@ private void CreateMathConceptsButtonIfNeeded(Canvas canvas, TextMeshProUGUI equ var tmp = textGo.AddComponent(); tmp.text = LocalizationManager.Get("ui.math_concepts", "Math concepts"); tmp.fontSize = UiTypography.Scale(tablet ? 30 : 27); + tmp.enableAutoSizing = true; + tmp.fontSizeMin = UiTypography.Scale(17); + tmp.fontSizeMax = UiTypography.Scale(tablet ? 30 : 27); + tmp.textWrappingMode = TextWrappingModes.Normal; + tmp.overflowMode = TextOverflowModes.Truncate; tmp.fontStyle = FontStyles.Bold; tmp.alignment = TextAlignmentOptions.Center; tmp.color = new Color(0.92f, 0.97f, 1f, 1f); @@ -2199,8 +2303,8 @@ private void BuildSampleLevels() power: 1, baseN: 2, story: - "True finale — Lorenz butterfly — the horizontal axis is a long stretch of simulation time; height tracks the classic Lorenz x(t) with σ=10, ρ=28, β=8/3.\n\n" + - "Watch how the attractor keeps retuning: the same law, sensitive dependence, a path that never quite repeats — the butterfly effect made legible as motion.\n\n" + + "True finale — Chaos Theory — the horizontal axis is a long stretch of simulation time; height tracks the classic Lorenz x(t) with σ=10, ρ=28, β=8/3.\n\n" + + "Watch how the attractor keeps retuning: the same law, sensitive dependence, a path that never quite repeats — chaos theory made legible as motion.\n\n" + "Normalized after burn-in so the wings fill your grid; the curve scrolls through phase so the stage feels alive.", derivativePopTriggerCountOverride: 4, applyGridTheming: true, @@ -2212,6 +2316,31 @@ private void BuildSampleLevels() levelXEnd: lorenzBossX1 )); + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[50], + FunctionType.PhysicsGravityWellInverseSqrt, + curveColor: new Color(0.55f, 0.72f, 1f, 1f), + derivativeColor: new Color(1f, 0.45f, 0.35f, 1f), + transA: 4.2f, + transK: 0.82f, + transC: 1.35f, + transD: 0.38f, + power: 1, + baseN: 2, + story: + "BOSS: Black hole — gravity well — the curve is a softened 1/r slice: depth spikes toward the center, then relaxes into a gentle far-field shoulder.\n\n" + + "It is a teaching stand-in for how gravitational potential tightens near mass — not a full GR embedding, but the right “falling in” intuition on a 1D graph.\n\n" + + "ε from D keeps the well finite so the derivative game stays fair; ride the rim, respect the steep core.", + derivativePopTriggerCountOverride: 4, + applyGridTheming: true, + gridCenter: new Color(0.06f, 0.08f, 0.22f, 0.48f), + gridOutside: new Color(0.04f, 0.06f, 0.14f, 0.14f), + storyPauseSecondsOverride: 3f, + graphStep: 0.1f, + levelXStart: -12f, + levelXEnd: 12f + )); + var springMassColors = new[] { new Color(0.42f, 0.95f, 0.68f, 1f), @@ -2220,7 +2349,7 @@ private void BuildSampleLevels() }; levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[50], + GameLevelCatalog.DisplayNames[51], FunctionType.SpringMassUndamped, curveColor: new Color(0.38f, 0.92f, 0.74f, 1f), derivativeColor: new Color(1f, 0.48f, 0.52f, 1f), @@ -2244,6 +2373,167 @@ private void BuildSampleLevels() levelXStart: -14f, levelXEnd: 14f )); + + // --- Big O notation (algorithms): u = k(x−D) plays the role of input size n on the graph --- + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[52], + FunctionType.Power, + curveColor: new Color(0.65f, 0.85f, 1f, 1f), + derivativeColor: new Color(1f, 0.78f, 0.45f, 1f), + transA: 1.85f, + transK: 0.12f, + transC: -0.35f, + transD: 0f, + power: 0, + baseN: 2, + story: + "Big O: O(1) — constant time: the work doesn’t grow with input size. Here u⁰ = 1, so height stays flat as u (our stand-in for n) marches.\n\n" + + "Hash lookups and array indexing are classic O(1) when the model fits — the graph is the calm horizontal proof.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.11f, + levelXStart: -12f, + levelXEnd: 12f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[53], + FunctionType.NaturalLog, + curveColor: new Color(0.5f, 0.92f, 0.78f, 1f), + derivativeColor: new Color(0.98f, 0.55f, 0.82f, 1f), + transA: 1.05f, + transK: 0.38f, + transC: -2.35f, + transD: 0f, + power: 1, + baseN: 2, + story: + "Big O: O(log n) — each step shrinks the problem by a constant factor (binary search, balanced trees). ln u climbs gently forever.\n\n" + + "Domain needs u > 0 — we sample away from zero so the law stays finite on the grid.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.1f, + levelXStart: 0.45f, + levelXEnd: 16f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[54], + FunctionType.SquareRoot, + curveColor: new Color(0.72f, 0.78f, 1f, 1f), + derivativeColor: new Color(1f, 0.62f, 0.48f, 1f), + transA: 1.15f, + transK: 0.36f, + transC: -2.05f, + transD: 0f, + power: 1, + baseN: 2, + story: + "Big O: O(√n) — sublinear growth: think nested loops that only walk up to √n, or some number-theory sieves. √u bends upward but bows to log in the long run.\n\n" + + "We keep u ≥ 0 so the square root stays real.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.095f, + levelXStart: 0f, + levelXEnd: 15f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[55], + FunctionType.Power, + curveColor: new Color(0.55f, 0.9f, 1f, 1f), + derivativeColor: new Color(1f, 0.5f, 0.65f, 1f), + transA: 0.34f, + transK: 0.5f, + transC: -2.12f, + transD: 0f, + power: 1, + baseN: 2, + story: + "Big O: O(n) — scan the input once: summing a list, finding a max, a single loop. u¹ is the straight-ahead ramp.\n\n" + + "Slope (derivative) stays in the same growth class — still linear in this stylized picture.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.1f, + levelXStart: -9f, + levelXEnd: 9f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[56], + FunctionType.BigONLogN, + curveColor: new Color(0.48f, 0.82f, 1f, 1f), + derivativeColor: new Color(1f, 0.58f, 0.78f, 1f), + transA: 0.22f, + transK: 0.48f, + transC: -2.45f, + transD: 0f, + power: 1, + baseN: 2, + story: + "Big O: O(n log n) — the sweet spot for sorting lower bounds (comparison sorts) and many divide steps. u ln u pulls away from linear but loses to n².\n\n" + + "We clamp the small‑u end so ln doesn’t sing on zero — same idea as “n big enough” in proofs.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.095f, + levelXStart: 0.5f, + levelXEnd: 14f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[57], + FunctionType.Power, + curveColor: new Color(0.6f, 0.72f, 1f, 1f), + derivativeColor: new Color(1f, 0.52f, 0.42f, 1f), + transA: 0.042f, + transK: 0.46f, + transC: -2f, + transD: 0f, + power: 2, + baseN: 2, + story: + "Big O: O(n²) — nested loops, many pairwise checks, naive matrix setups. u² accelerates — the derivative warns you early.\n\n" + + "When you see the parabola in complexity class, look for a double walk over data.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.09f, + levelXStart: -7.5f, + levelXEnd: 7.5f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[58], + FunctionType.Power, + curveColor: new Color(0.52f, 0.68f, 0.98f, 1f), + derivativeColor: new Color(1f, 0.48f, 0.55f, 1f), + transA: 0.0055f, + transK: 0.34f, + transC: -1.55f, + transD: 0f, + power: 3, + baseN: 2, + story: + "Big O: O(n³) — triple loops, naive Floyd–Warshall mood, dense cubic work. u³ rockets faster than n² — small constants don’t save you forever.\n\n" + + "Good algorithms often avoid this exponent; the graph shows why.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.085f, + levelXStart: -6f, + levelXEnd: 6f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[59], + FunctionType.Exponential, + curveColor: new Color(0.58f, 0.95f, 0.72f, 1f), + derivativeColor: new Color(1f, 0.45f, 0.88f, 1f), + transA: 0.075f, + transK: 0.42f, + transC: -1.15f, + transD: 0f, + power: 1, + baseN: 2, + story: + "Big O: O(2ⁿ) — exhaustive subsets, brute-force SAT-ish nightmares. 2ᵘ explodes; we keep the window modest so the grid survives.\n\n" + + "Memoization, pruning, and smarter structure exist precisely because this curve leaves polite bounds.", + derivativePopTriggerCountOverride: 3, + graphStep: 0.11f, + levelXStart: -5.5f, + levelXEnd: 3.5f + )); } /// @@ -2498,12 +2788,18 @@ private IEnumerator LoadLevelFullRoutine(LevelDefinition def) if (showIntro) yield return RunEnumerated(RunStageIntroCoroutine(def)); + if (DeviceLayout.PreferOnScreenGameControls && runSpawnSpotlight && playerController != null) + yield return RunEnumerated(RunMobileControlGuideRoutine()); + if (runSpawnSpotlight && playerController != null) yield return RunEnumerated(RunSpawnSpotlightRoutine()); // Match original behaviour: player can move while the top story banner fades. if (playerController != null) + { + MobileInputBridge.ClearTouchRouting(); playerController.SetInputLocked(false); + } if (storyText != null) { @@ -2524,6 +2820,63 @@ private static IEnumerator RunEnumerated(IEnumerator inner) yield return inner.Current; } + /// + /// Mobile: full-screen instruction card before spawn spotlight (input still locked). + /// + private IEnumerator RunMobileControlGuideRoutine() + { + var canvas = FindAnyObjectByType(); + if (canvas == null) + yield break; + + var safe = MobileUiRoots.GetSafeContentParent(canvas.transform) as RectTransform; + Transform parent = safe != null ? safe.transform : canvas.transform; + + var go = new GameObject("MobileControlGuideOverlay", typeof(RectTransform)); + var rt = go.GetComponent(); + rt.SetParent(parent, false); + rt.SetAsLastSibling(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + + var dim = go.AddComponent(); + dim.color = new Color(0.04f, 0.05f, 0.12f, 0.92f); + dim.raycastTarget = true; + + var textGo = new GameObject("GuideText", typeof(RectTransform)); + var trt = textGo.GetComponent(); + trt.SetParent(go.transform, false); + trt.anchorMin = new Vector2(0.06f, 0.12f); + trt.anchorMax = new Vector2(0.94f, 0.88f); + trt.offsetMin = Vector2.zero; + trt.offsetMax = Vector2.zero; + + var tmp = textGo.AddComponent(); + tmp.richText = true; + tmp.textWrappingMode = TextWrappingModes.Normal; + tmp.overflowMode = TextOverflowModes.Overflow; + tmp.alignment = TextAlignmentOptions.Midline; + tmp.fontSize = UiTypography.Scale(DeviceLayout.IsTabletLike() ? 30 : 26); + tmp.lineSpacing = 6f; + tmp.color = new Color(0.94f, 0.95f, 0.98f, 1f); + tmp.text = TmpLatex.Process(LocalizationManager.Get("controls.guide_overlay", + "Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nSwipe up anywhere — jump\n\nKeyboard: Arrow keys move · Space jumps")); + LocalizationManager.ApplyTextDirection(tmp); + ApplyPrimaryUiTypography(tmp, FindPrimaryEquationTmp(), outlineWidth: 0.1f, outlineAlpha: 0.42f); + + float dur = Mathf.Max(0.2f, mobileControlGuideSeconds); + float t = 0f; + while (t < dur) + { + t += Time.unscaledDeltaTime; + yield return null; + } + + Destroy(go); + } + /// /// Fullscreen dim with a soft hole on the player — runs while input is still locked (after optional roleplay card). /// @@ -2840,6 +3193,8 @@ private IEnumerator LoadWorldAfterThemeChange(LevelDefinition def, bool grantStr if (obstacleGenerator == null || playerController == null) yield break; + FitCartesianPlaneForGameplay(); + var gridSize = gridRenderer.gridSize; var unitWidth = cartesianPlaneRect.rect.width / (float)gridSize.x; @@ -2867,8 +3222,11 @@ private IEnumerator LoadWorldAfterThemeChange(LevelDefinition def, bool grantStr else playerController.SetDeathMinYGrid(deathMinYGrid); + playerController.SetGridToPixelUnits(unitWidth, unitHeight); playerController.SetWorld(world); playerController.ResetToSpawn(world, grantStrongFirstGroundJump); + + _lastSyncedCartesianRectSize = cartesianPlaneRect.rect.size; } private IEnumerator FadeStoryTextRoutine() diff --git a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs index a900420..50b096a 100644 --- a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs +++ b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs @@ -256,21 +256,45 @@ private void Update() posGrid = nextPos; - ClampHorizontalToPlayBounds(); + ClampPositionToPlayBounds(); TickDerivativeBackgroundTint(dt); ApplyVisualPosition(); } - /// Hard horizontal limits so the avatar stays over the padded playfield (screen/safe + touch bar). - private void ClampHorizontalToPlayBounds() + /// Hard AABB limits so the avatar stays inside the padded playfield (safe area + touch bar insets). + private void ClampPositionToPlayBounds() { if (world == null || !world.hasPlayBounds) return; float halfW = playerWidthGrid * 0.5f; - posGrid.x = Mathf.Clamp(posGrid.x, world.playBounds.XMin + halfW, world.playBounds.XMax - halfW); + float halfH = playerHeightGrid * 0.5f; + var b = world.playBounds; + posGrid.x = Mathf.Clamp(posGrid.x, b.XMin + halfW, b.XMax - halfW); + posGrid.y = Mathf.Clamp(posGrid.y, b.YMin + halfH, b.YMax - halfH); + } + + /// After rotation or Cartesian plane resize: refresh pixel scale, play-bound grid inset, and clamp. + public void ApplyResponsivePlaneLayout(RectTransform plane, Vector2Int gridSize) + { + if (world == null || plane == null || gridSize.x < 1 || gridSize.y < 1) + return; + + float uw = plane.rect.width / gridSize.x; + float uh = plane.rect.height / gridSize.y; + SetGridToPixelUnits(uw, uh); + + if (world.hasPlayBounds) + { + world.playBounds = GameplayPlayBounds.Compute(plane, gridSize); + world.RefreshFinishFromPlayBounds(); + SetDeathMinYGrid(world.playBounds.YMin - 0.4f); + } + + ClampPositionToPlayBounds(); + ApplyVisualPosition(); } /// Air jump only while overlapping f′ and not already used until you leave the band. diff --git a/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs b/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs index fc53873..c44d179 100644 --- a/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs +++ b/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs @@ -110,9 +110,27 @@ public static class StageRoleplayLibrary // 48 "Fractal exile, encore. You return to Mandelbrot’s coastline for the last word—each iterate still votes on escape, and the boundary remembers every branch you dared to name.", // 49 - "Strange butterfly. Lorenz’s wings beat on a thread of time: the curve you ride is sensitive, restless, forever retuning—small shifts in the unseen become storms in the visible trace.", + "Chaos theory. Lorenz’s wings beat on a thread of time: the curve you ride is sensitive, restless, forever retuning—small shifts in the unseen become storms in the visible trace.", // 50 - "Spring cadet. Hooke’s law pulls you home to equilibrium — each crest is stored spring energy, each crossing is the quiet where velocity wins; undamped, the tune never dies, only repeats." + "Event horizon clerk. The graph pretends to be a softened well—potential diving toward a point that eats straight lines. Tread the shoulder: steep slopes mean the derivative has opinions.", + // 51 + "Spring cadet. Hooke’s law pulls you home to equilibrium — each crest is stored spring energy, each crossing is the quiet where velocity wins; undamped, the tune never dies, only repeats.", + // 52 + "Constant-time courier. O(1) is the myth that distance doesn’t matter—your path stays level while the input scrolls sideways. Enjoy the flatness; it’s rare in the wild.", + // 53 + "Binary search monk. O(log n) whispers: halve, halve, halve. The curve climbs so politely you almost trust infinite data—almost.", + // 54 + "Root scout. O(√n) is the compromise growth—faster than log, slower than linear. You’re walking a power law with a gentle exponent.", + // 55 + "Linear pilgrim. O(n) is honesty: one pass, proportional work. The ramp doesn’t cheat; it just keeps asking for more steps.", + // 56 + "Sort priest. O(n log n) is the church of merge sorts and balanced trees—more than linear, less than quadratic, forever arguing about constants in the basement.", + // 57 + "Nested-loop detective. O(n²) means someone doubled a walk. Feel the parabola: small n forgives you; large n sends invoices.", + // 58 + "Cubic alchemist. O(n³) is triple trouble—dense, blunt, expensive. The graph rockets to remind you why we invent better algorithms.", + // 59 + "Subset gambler. O(2ⁿ) is the house always winning: every extra unit doubles the shadow workload. Pray for pruning, memoization, or a smaller universe." }; /// Must match . diff --git a/First Principles/Assets/Scripts/Math/LorenzAttractorSamples.cs b/First Principles/Assets/Scripts/Math/LorenzAttractorSamples.cs index 37eb4a0..2ce1964 100644 --- a/First Principles/Assets/Scripts/Math/LorenzAttractorSamples.cs +++ b/First Principles/Assets/Scripts/Math/LorenzAttractorSamples.cs @@ -1,8 +1,9 @@ using UnityEngine; /// -/// Pre-integrated Lorenz attractor (σ=10, ρ=28, β=8/3) for the butterfly-effect boss stage. +/// Pre-integrated Lorenz attractor (σ=10, ρ=28, β=8/3) for the Chaos Theory boss stage. /// Horizontal axis in-game maps to time; height samples the x coordinate (chaotic, sensitive ICs). +/// Uses RK4 — explicit Euler with the previous dt blew up (~10²⁸ by burn-in step 50), yielding NaNs and an empty graph. /// public static class LorenzAttractorSamples { @@ -37,20 +38,50 @@ public static float TimeMax } } + private static void Deriv(float x, float y, float z, out float dx, out float dy, out float dz) + { + dx = Sigma * (y - x); + dy = x * (Rho - z) - y; + dz = x * y - Beta * z; + } + + private static void StepRk4(ref float x, ref float y, ref float z, float dt) + { + Deriv(x, y, z, out float k1x, out float k1y, out float k1z); + + float x2 = x + 0.5f * dt * k1x; + float y2 = y + 0.5f * dt * k1y; + float z2 = z + 0.5f * dt * k1z; + Deriv(x2, y2, z2, out float k2x, out float k2y, out float k2z); + + float x3 = x + 0.5f * dt * k2x; + float y3 = y + 0.5f * dt * k2y; + float z3 = z + 0.5f * dt * k2z; + Deriv(x3, y3, z3, out float k3x, out float k3y, out float k3z); + + float x4 = x + dt * k3x; + float y4 = y + dt * k3y; + float z4 = z + dt * k3z; + Deriv(x4, y4, z4, out float k4x, out float k4y, out float k4z); + + x += dt * (k1x + 2f * k2x + 2f * k3x + k4x) / 6f; + y += dt * (k1y + 2f * k2y + 2f * k3y + k4y) / 6f; + z += dt * (k1z + 2f * k2z + 2f * k3z + k4z) / 6f; + } + private static void EnsureBuilt() { if (_built) return; - _built = true; - const int burnInSteps = 900; - const int n = 3600; - const float dt = 0.028f; + const int burnInSteps = 2000; + const int n = 6000; + const float dt = 0.015f; float x = 0.2f, y = 0.15f, z = 0.1f; for (int s = 0; s < burnInSteps; s++) - StepEuler(ref x, ref y, ref z, dt); + StepRk4(ref x, ref y, ref z, dt); _xSeries = new float[n]; float xMin = x, xMax = x; @@ -58,7 +89,7 @@ private static void EnsureBuilt() for (int i = 0; i < n; i++) { - StepEuler(ref bx, ref by, ref bz, dt); + StepRk4(ref bx, ref by, ref bz, dt); _xSeries[i] = bx; if (bx < xMin) xMin = bx; if (bx > xMax) xMax = bx; @@ -70,15 +101,6 @@ private static void EnsureBuilt() _xSeries[i] = (_xSeries[i] - mid) / span * 2f; _tMax = (n - 1) * dt; - } - - private static void StepEuler(ref float x, ref float y, ref float z, float dt) - { - float dx = Sigma * (y - x); - float dy = x * (Rho - z) - y; - float dz = x * y - Beta * z; - x += dx * dt; - y += dy * dt; - z += dz * dt; + _built = true; } } diff --git a/First Principles/Assets/Scripts/UI/DeviceLayout.cs b/First Principles/Assets/Scripts/UI/DeviceLayout.cs index 91768da..9713ab2 100644 --- a/First Principles/Assets/Scripts/UI/DeviceLayout.cs +++ b/First Principles/Assets/Scripts/UI/DeviceLayout.cs @@ -6,7 +6,7 @@ /// /// Central place for **screen-dependent layout policy** used by HUD, level select, touch bar, CanvasScaler tuning. /// -/// — show touch gameplay chrome. +/// — use full-screen touch zones + guide (no virtual button strip). /// — dp-based; avoids treating phones as tablets. /// — normalized → RectTransform anchors. /// @@ -75,7 +75,16 @@ public static float RecommendedCanvasMatchWidthOrHeight() public static float TouchControlBarHeight => IsTabletLike() ? 188f : 168f; - public static float TouchHintVerticalOffset => IsTabletLike() ? 212f : 188f; + /// True in Game when we use left/right screen halves + swipe (no ◀ ▶ Jump strip). + public static bool GameplayUsesFullScreenTouchZones => PreferOnScreenGameControls; + + /// Bottom offset for the small controls hint chip (above graph; no virtual bar when zones are on). + public static float TouchHintVerticalOffset => + !PreferOnScreenGameControls + ? 22f + : GameplayUsesFullScreenTouchZones + ? (IsTabletLike() ? 118f : 96f) + : (IsTabletLike() ? 212f : 188f); // Leave vertical room for bottom “Math tips” / “How to play” band + back chip. public static Vector2 LevelSelectScrollAnchorMin => diff --git a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs new file mode 100644 index 0000000..df74194 --- /dev/null +++ b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +/// +/// Game scene: invisible full-screen touch layer (first under safe-area HUD). Hold left half → move left, +/// hold right half → move right; release with a dominant upward swipe → jump. Replaces virtual ◀ ▶ Jump buttons. +/// +public class GameplayScreenTouchZones : MonoBehaviour, + IPointerDownHandler, IPointerUpHandler, IPointerExitHandler +{ + private static GameplayScreenTouchZones _instance; + + private readonly Dictionary _pointerDownScreen = new Dictionary(); + private readonly Dictionary _pointerSide = new Dictionary(); + + public static void EnsureForGameCanvas(Transform canvasTransform) + { + if (canvasTransform == null || !DeviceLayout.PreferOnScreenGameControls) + return; + + DestroyLegacyButtonBar(canvasTransform); + + if (_instance != null) + return; + + Transform existing = canvasTransform.Find("GameplayScreenTouchZonesRoot"); + if (existing == null) + { + var safe = canvasTransform.Find(MobileUiRoots.SafeContentName); + if (safe != null) + existing = safe.Find("GameplayScreenTouchZonesRoot"); + } + + if (existing != null) + { + _instance = existing.GetComponent(); + return; + } + + var parentRt = MobileUiRoots.GetSafeContentParent(canvasTransform) ?? canvasTransform as RectTransform; + if (parentRt == null) + return; + + var go = new GameObject("GameplayScreenTouchZonesRoot", typeof(RectTransform)); + var rt = go.GetComponent(); + rt.SetParent(parentRt, false); + rt.SetAsFirstSibling(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + + var img = go.AddComponent(); + img.color = new Color(0f, 0f, 0f, 0f); + img.raycastTarget = true; + + _instance = go.AddComponent(); + } + + private static void DestroyLegacyButtonBar(Transform canvasTransform) + { + Transform t = canvasTransform.Find("MobileTouchControlsRoot"); + if (t == null) + { + var safe = canvasTransform.Find(MobileUiRoots.SafeContentName); + if (safe != null) + t = safe.Find("MobileTouchControlsRoot"); + } + + if (t != null) + UnityEngine.Object.Destroy(t.gameObject); + } + + private void OnDestroy() + { + if (_instance == this) + _instance = null; + MobileInputBridge.ClearTouchRouting(); + } + + private static float MinSwipeUpPixels() + { + float dpi = Screen.dpi > 1f ? Screen.dpi : 163f; + return Mathf.Clamp(48f * (dpi / 160f), 40f, 100f); + } + + public void OnPointerDown(PointerEventData eventData) + { + int id = eventData.pointerId; + Vector2 pos = eventData.position; + _pointerDownScreen[id] = pos; + float mid = Screen.width * 0.5f; + int side = pos.x < mid ? -1 : 1; + _pointerSide[id] = side; + if (side < 0) + MobileHoldAxis.PressLeft(); + else + MobileHoldAxis.PressRight(); + } + + public void OnPointerUp(PointerEventData eventData) => + EndPointer(eventData.pointerId, evaluateSwipeJump: true, eventData.position); + + public void OnPointerExit(PointerEventData eventData) => + EndPointer(eventData.pointerId, evaluateSwipeJump: false, eventData.position); + + private void EndPointer(int pointerId, bool evaluateSwipeJump, Vector2 releasePosition) + { + if (!_pointerSide.TryGetValue(pointerId, out int side)) + return; + + if (evaluateSwipeJump && _pointerDownScreen.TryGetValue(pointerId, out Vector2 down)) + { + Vector2 delta = releasePosition - down; + float minUp = MinSwipeUpPixels(); + if (delta.y > minUp && delta.y > Mathf.Abs(delta.x) * 0.55f) + MobileInputBridge.QueueJump(); + } + + _pointerDownScreen.Remove(pointerId); + if (side < 0) + MobileHoldAxis.ReleaseLeft(); + else + MobileHoldAxis.ReleaseRight(); + _pointerSide.Remove(pointerId); + } +} diff --git a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs.meta b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs.meta new file mode 100644 index 0000000..236fcde --- /dev/null +++ b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 537a369e35cbd4f37a39d1c8f9787937 \ No newline at end of file diff --git a/First Principles/Assets/Scripts/UI/LabelManager.cs b/First Principles/Assets/Scripts/UI/LabelManager.cs index a64533d..134eb50 100644 --- a/First Principles/Assets/Scripts/UI/LabelManager.cs +++ b/First Principles/Assets/Scripts/UI/LabelManager.cs @@ -6,7 +6,7 @@ /// Spawns TMP axis labels from extents. /// Y-axis numbers track when vertical auto-fit is on. /// X-axis numbers track and refresh when the plot window -/// (zoom / pinch), Trans (k, D), or mode changes — calculator ticks show inner u. +/// (zoom / pinch), horizontal auto-fit pivots, Trans (k, D), or mode changes — calculator ticks show inner u. /// public class LabelManager : MonoBehaviour { @@ -212,6 +212,26 @@ void RefreshXAxisLabelText() } } + /// + /// Re-read tick strings from the current mapping (e.g. after pinch / Scale in graphing calculator). + /// Syncs cached pivots so does not lag one frame. + /// + public void RefreshAllTickLabels() + { + var plotter = FindAnyObjectByType(); + if (plotter != null) + { + _lastAutoMid = plotter.VerticalAxisLabelPivot; + _lastAutoScale = plotter.VerticalAxisLabelScale; + _lastAutoMidX = plotter.HorizontalAxisLabelPivot; + _lastAutoScaleX = plotter.HorizontalAxisLabelScale; + CacheHorizontalAxisState(plotter); + } + + RefreshXAxisLabelText(); + RefreshYAxisLabelText(); + } + static string FormatXTick(FunctionPlotter plotter, float tickOffsetFromCenter) { float v = plotter != null ? plotter.AxisTickOffsetToMathX(tickOffsetFromCenter) : tickOffsetFromCenter; diff --git a/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs b/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs index 0feb489..16282f5 100644 --- a/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs +++ b/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs @@ -116,8 +116,9 @@ void Close() var scroll = scrollGo.AddComponent(); scroll.horizontal = false; scroll.vertical = true; - scroll.movementType = ScrollRect.MovementType.Clamped; - scroll.scrollSensitivity = tablet ? 40f : 25f; + scroll.movementType = ScrollRect.MovementType.Elastic; + scroll.elasticity = 0.12f; + scroll.scrollSensitivity = DeviceLayout.LevelSelectScrollSensitivity; var viewportGo = new GameObject("Viewport"); var viewportRt = viewportGo.AddComponent(); @@ -144,10 +145,6 @@ void Close() scroll.content = contentRt; - var contentSize = contentGo.AddComponent(); - contentSize.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; - contentSize.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - var tmpGo = new GameObject("ArticleText"); var tmpRt = tmpGo.AddComponent(); tmpRt.SetParent(contentRt, false); @@ -165,22 +162,17 @@ void Close() body.alignment = TextAlignmentOptions.TopLeft; body.color = new Color(0.92f, 0.93f, 0.96f, 1f); body.textWrappingMode = TextWrappingModes.Normal; + body.overflowMode = TextOverflowModes.Overflow; body.richText = true; body.margin = new Vector4(12f, 12f, 12f, 12f); CopyFont(body); ApplyArticleReadingLayout(body); - var fitter = tmpGo.AddComponent(); - fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; - fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - var le = tmpGo.AddComponent(); le.minWidth = 1f; - body.ForceMeshUpdate(true); - LayoutRebuilder.ForceRebuildLayoutImmediate(contentRt); Canvas.ForceUpdateCanvases(); - scroll.verticalNormalizedPosition = 1f; + SyncArticleScrollLayout(body, scroll); root.transform.SetAsLastSibling(); } @@ -209,11 +201,10 @@ private static void RefreshArticleBodyText() if (articleBodyTmp == null) return; articleBodyTmp.text = LearningArticleLibrary.GetLevelSelectArticleRichText(); + ApplyArticleReadingLayout(articleBodyTmp); LocalizationManager.ApplyTextDirection(articleBodyTmp); - articleBodyTmp.ForceMeshUpdate(true); - var contentRt = articleBodyTmp.rectTransform.parent as RectTransform; - if (contentRt != null) - LayoutRebuilder.ForceRebuildLayoutImmediate(contentRt); + var scroll = articleBodyTmp.GetComponentInParent(); + SyncArticleScrollLayout(articleBodyTmp, scroll); } private static void RefreshArticleBodyAndLayout(Transform overlayRoot) @@ -231,6 +222,50 @@ private static void RefreshArticleBodyAndLayout(Transform overlayRoot) scroll.verticalNormalizedPosition = 1f; } + /// + /// TMP + layout groups often under-report height; drive content height from so the can scroll long articles. + /// + private static void SyncArticleScrollLayout(TextMeshProUGUI body, ScrollRect scroll) + { + if (body == null) + return; + + body.overflowMode = TextOverflowModes.Overflow; + body.enableWordWrapping = true; + + var tmpRt = body.rectTransform; + var contentRt = tmpRt.parent as RectTransform; + var viewportRt = contentRt != null ? contentRt.parent as RectTransform : null; + if (contentRt == null || viewportRt == null) + return; + + Canvas.ForceUpdateCanvases(); + LayoutRebuilder.ForceRebuildLayoutImmediate(viewportRt); + + // Content must be at least viewport-tall so width is valid on first layout pass. + float viewportW = Mathf.Max(1f, viewportRt.rect.width); + float viewportH = Mathf.Max(1f, viewportRt.rect.height); + if (contentRt.sizeDelta.y < viewportH) + contentRt.sizeDelta = new Vector2(0f, viewportH); + + Canvas.ForceUpdateCanvases(); + float innerW = Mathf.Max(48f, contentRt.rect.width - 48f); + body.ForceMeshUpdate(true); + Vector2 pref = body.GetPreferredValues(innerW, 0f); + float textH = Mathf.Max(pref.y, 1f); + const float verticalPad = 20f; + tmpRt.sizeDelta = new Vector2(-40f, textH); + contentRt.sizeDelta = new Vector2(0f, Mathf.Max(viewportH, textH + verticalPad)); + + LayoutRebuilder.ForceRebuildLayoutImmediate(contentRt); + LayoutRebuilder.ForceRebuildLayoutImmediate(viewportRt); + if (scroll != null) + { + Canvas.ForceUpdateCanvases(); + scroll.verticalNormalizedPosition = 1f; + } + } + private static void RefreshCloseLabel() { if (closeButtonTmp == null) diff --git a/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs b/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs index dc6310b..e087821 100644 --- a/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs +++ b/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs @@ -207,8 +207,8 @@ private static string DefaultBodyEnglish() "Goal\n" + "Move along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\n" + "Controls\n" + - "• Move — arrows / WASD, or on-screen buttons.\n" + - "• Jump — Space (or mobile jump). You jump from solid platforms.\n\n" + + "• Move — arrows / WASD, or on a phone hold the left / right half of the screen.\n" + + "• Jump — Space, or swipe up on a phone. You jump from solid platforms.\n\n" + "The two curves\n" + "• Main curve — the function you walk on.\n" + "• Derivative \\(f'\\) — slope information; it’s drawn as a second line.\n\n" + diff --git a/First Principles/Assets/Scripts/UI/MobileInputBridge.cs b/First Principles/Assets/Scripts/UI/MobileInputBridge.cs index 059cb00..7a1fef8 100644 --- a/First Principles/Assets/Scripts/UI/MobileInputBridge.cs +++ b/First Principles/Assets/Scripts/UI/MobileInputBridge.cs @@ -1,7 +1,7 @@ using UnityEngine; /// -/// Tiny IPC between (UI events) and . +/// IPC between (full-screen touch) and . /// Horizontal motion uses counts; jump uses a one-shot queue consumed each Update. /// public static class MobileInputBridge @@ -19,4 +19,48 @@ public static bool ConsumeJump() JumpQueued = false; return true; } + + /// Clears swipe/jump queue and axis holds after onboarding overlays or before unlocking control. + public static void ClearTouchRouting() + { + JumpQueued = false; + MobileHoldAxis.Clear(); + } +} + +/// +/// Ref-count style axis: multiple pointers can press left/right; release decrements. Player reads aggregated -1/0/+1. +/// +public static class MobileHoldAxis +{ + private static int _left; + private static int _right; + + public static void PressLeft() => _left++; + + public static void ReleaseLeft() => _left = Mathf.Max(0, _left - 1); + + public static void PressRight() => _right++; + + public static void ReleaseRight() => _right = Mathf.Max(0, _right - 1); + + public static float Axis + { + get + { + if (_left > 0 && _right > 0) + return 0f; + if (_left > 0) + return -1f; + if (_right > 0) + return 1f; + return 0f; + } + } + + public static void Clear() + { + _left = 0; + _right = 0; + } } diff --git a/First Principles/Assets/Scripts/UI/MobileTouchControls.cs b/First Principles/Assets/Scripts/UI/MobileTouchControls.cs deleted file mode 100644 index 3afca98..0000000 --- a/First Principles/Assets/Scripts/UI/MobileTouchControls.cs +++ /dev/null @@ -1,310 +0,0 @@ -using TMPro; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -/// -/// Builds a bottom **◀ / ▶ / Jump** row parented under . -/// Phones: buttons expand to fill width. Tablets: fixed widths + flex spacers so landscape iPad -/// does not create kilometer-wide hit targets. Uses for responsive hold-to-run. -/// -/// Visuals aim for a **Minecraft PE–style** translucent strip: low-alpha panels so the graph stays readable; -/// only the three buttons use raycastTarget — the bar backdrop is non-blocking so -/// taps in any gaps/spacers pass through to content behind (HUD is laid out above ). -/// -public class MobileTouchControls : MonoBehaviour -{ - private static MobileTouchControls _instance; - - private TextMeshProUGUI jumpLabelTmp; - - // --- Minecraft-style translucency (tweak alphas here) ---------------------------------- - private static readonly Color TouchBarBackdrop = new Color(0.06f, 0.07f, 0.09f, 0.34f); - private static readonly Color MoveButtonFace = new Color(0.18f, 0.2f, 0.24f, 0.52f); - private static readonly Color JumpButtonFace = new Color(0.14f, 0.38f, 0.32f, 0.55f); - private const float TouchButtonShadowAlpha = 0.14f; - - public static void EnsureForGameCanvas(Transform canvasTransform) - { - if (canvasTransform == null || !ShouldShow()) - return; - - if (_instance != null) - return; - - Transform existing = canvasTransform.Find("MobileTouchControlsRoot"); - if (existing == null) - { - var safe = canvasTransform.Find(MobileUiRoots.SafeContentName); - if (safe != null) - existing = safe.Find("MobileTouchControlsRoot"); - } - - if (existing != null) - { - _instance = existing.GetComponent(); - return; - } - - var go = new GameObject("MobileTouchControlsRoot", typeof(RectTransform)); - var rt = go.GetComponent(); - var parent = MobileUiRoots.GetSafeContentParent(canvasTransform) ?? canvasTransform as RectTransform; - rt.SetParent(parent, false); - rt.SetAsLastSibling(); - rt.anchorMin = new Vector2(0f, 0f); - rt.anchorMax = new Vector2(1f, 0f); - rt.pivot = new Vector2(0.5f, 0f); - rt.anchoredPosition = new Vector2(0f, 10f); - rt.sizeDelta = new Vector2(0f, DeviceLayout.TouchControlBarHeight); - - _instance = go.AddComponent(); - _instance.Build(rt); - } - - private static bool ShouldShow() => DeviceLayout.PreferOnScreenGameControls; - - private void OnEnable() - { - LocalizationManager.LanguageChanged += RefreshJumpLabel; - } - - private void OnDisable() - { - LocalizationManager.LanguageChanged -= RefreshJumpLabel; - } - - private void RefreshJumpLabel() - { - if (jumpLabelTmp == null) - return; - jumpLabelTmp.text = LocalizationManager.Get("ui.jump", "Jump"); - LocalizationManager.ApplyTextDirection(jumpLabelTmp); - } - - private void OnDestroy() - { - if (_instance == this) - _instance = null; - MobileHoldAxis.Clear(); - } - - private void Build(RectTransform root) - { - bool tablet = DeviceLayout.IsTabletLike(); - float gap = tablet ? 20f : 16f; - - // Full-bar tint only; raycasts off so this never steals input from UI above or gaps between controls. - var backdropGo = new GameObject("TouchBarBackdrop", typeof(RectTransform)); - var bdRt = backdropGo.GetComponent(); - bdRt.SetParent(root, false); - bdRt.SetAsFirstSibling(); - bdRt.anchorMin = Vector2.zero; - bdRt.anchorMax = Vector2.one; - bdRt.offsetMin = Vector2.zero; - bdRt.offsetMax = Vector2.zero; - var bdImg = backdropGo.AddComponent(); - RuntimeUiPolish.UseRoundedSliced(bdImg); - bdImg.color = TouchBarBackdrop; - bdImg.raycastTarget = false; - - var row = new GameObject("Row", typeof(RectTransform)); - var rowRt = row.GetComponent(); - rowRt.SetParent(root, false); - rowRt.anchorMin = Vector2.zero; - rowRt.anchorMax = Vector2.one; - rowRt.offsetMin = new Vector2(tablet ? 20f : 12f, 10f); - rowRt.offsetMax = new Vector2(tablet ? -20f : -12f, -10f); - - var hlg = row.AddComponent(); - hlg.spacing = gap; - hlg.childAlignment = TextAnchor.MiddleCenter; - hlg.childControlHeight = true; - hlg.childControlWidth = true; - hlg.childForceExpandHeight = true; - // Phones: stretch buttons across width. Tablets: fixed widths + side spacers so bars are not huge in landscape. - hlg.childForceExpandWidth = !tablet; - - if (tablet) - AddLayoutSpacer(rowRt, flexibleWidth: 1f); - - CreateHoldButton(rowRt, "Left", -1f, tablet); - CreateHoldButton(rowRt, "Right", 1f, tablet); - CreateJumpButtonInstance(rowRt, tablet); - - if (tablet) - AddLayoutSpacer(rowRt, flexibleWidth: 1f); - } - - private static void AddLayoutSpacer(Transform parent, float flexibleWidth) - { - var go = new GameObject("Spacer", typeof(RectTransform)); - go.transform.SetParent(parent, false); - var le = go.AddComponent(); - le.flexibleWidth = flexibleWidth; - le.minWidth = 0f; - le.preferredWidth = 0f; - } - - private static void CreateHoldButton(Transform parent, string label, float dir, bool tablet) - { - var go = new GameObject($"Btn_{label}", typeof(RectTransform)); - var rt = go.GetComponent(); - rt.SetParent(parent, false); - - var le = go.AddComponent(); - le.preferredWidth = tablet ? 252f : 200f; - le.flexibleWidth = tablet ? 0f : 1f; - le.minHeight = tablet ? 132f : 120f; - if (tablet) - le.preferredHeight = 132f; - - var img = go.AddComponent(); - RuntimeUiPolish.UseRoundedSliced(img); - img.color = MoveButtonFace; - - var h = go.AddComponent(); - h.Init(dir); - RuntimeUiPolish.ApplyDropShadow(rt, new Vector2(1f, -2f), TouchButtonShadowAlpha); - - var tr = new GameObject("Text"); - var trt = tr.AddComponent(); - trt.SetParent(go.transform, false); - trt.anchorMin = Vector2.zero; - trt.anchorMax = Vector2.one; - trt.offsetMin = Vector2.zero; - trt.offsetMax = Vector2.zero; - var tmp = tr.AddComponent(); - tmp.text = label == "Left" ? "\u25C0" : "\u25B6"; - tmp.fontSize = UiTypography.Scale(tablet ? 54f : 48f); - tmp.alignment = TextAlignmentOptions.Center; - tmp.color = new Color(1f, 0.9f, 0.55f, 0.92f); - CopyTmpFont(tmp); - } - - private void CreateJumpButtonInstance(Transform parent, bool tablet) - { - var go = new GameObject("Btn_Jump", typeof(RectTransform)); - var rt = go.GetComponent(); - rt.SetParent(parent, false); - - var le = go.AddComponent(); - le.preferredWidth = tablet ? 268f : 220f; - le.flexibleWidth = tablet ? 0f : 1.2f; - le.minHeight = tablet ? 132f : 120f; - if (tablet) - le.preferredHeight = 132f; - - var img = go.AddComponent(); - RuntimeUiPolish.UseRoundedSliced(img); - img.color = JumpButtonFace; - RuntimeUiPolish.ApplyDropShadow(rt, new Vector2(1.5f, -2.5f), TouchButtonShadowAlpha); - - var tr = new GameObject("Text"); - var trt = tr.AddComponent(); - trt.SetParent(go.transform, false); - trt.anchorMin = Vector2.zero; - trt.anchorMax = Vector2.one; - trt.offsetMin = Vector2.zero; - trt.offsetMax = Vector2.zero; - jumpLabelTmp = tr.AddComponent(); - jumpLabelTmp.text = LocalizationManager.Get("ui.jump", "Jump"); - jumpLabelTmp.fontSize = UiTypography.Scale(tablet ? 34f : 30f); - jumpLabelTmp.fontStyle = FontStyles.Bold; - jumpLabelTmp.alignment = TextAlignmentOptions.Center; - jumpLabelTmp.color = new Color(0.98f, 1f, 1f, 0.94f); - CopyTmpFont(jumpLabelTmp); - LocalizationManager.ApplyTextDirection(jumpLabelTmp); - - var ev = go.AddComponent(); - } - - private static void CopyTmpFont(TextMeshProUGUI tmp) - { - var any = FindAnyObjectByType(); - if (any != null && any.font != null) - tmp.font = any.font; - else if (TMP_Settings.defaultFontAsset != null) - tmp.font = TMP_Settings.defaultFontAsset; - } - - private class MobileHoldButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler - { - private float _dir; - private bool _held; - - public void Init(float dir) => _dir = dir; - - public void OnPointerDown(PointerEventData eventData) - { - _held = true; - if (_dir < 0f) - MobileHoldAxis.PressLeft(); - else - MobileHoldAxis.PressRight(); - } - - public void OnPointerUp(PointerEventData eventData) - { - if (!_held) - return; - _held = false; - if (_dir < 0f) - MobileHoldAxis.ReleaseLeft(); - else - MobileHoldAxis.ReleaseRight(); - } - - private void OnDisable() - { - if (_held) - { - _held = false; - if (_dir < 0f) - MobileHoldAxis.ReleaseLeft(); - else - MobileHoldAxis.ReleaseRight(); - } - } - } - - /// Fires jump on pointer down (not only click) for better touch response. - private class MobileJumpTouch : MonoBehaviour, IPointerDownHandler - { - public void OnPointerDown(PointerEventData eventData) => MobileInputBridge.QueueJump(); - } -} - -/// -/// Ref-count style axis: multiple pointers could press Left; release decrements. Player reads aggregated -1/0/+1. -/// -public static class MobileHoldAxis -{ - private static int _left; - private static int _right; - - public static void PressLeft() => _left++; - public static void ReleaseLeft() => _left = Mathf.Max(0, _left - 1); - - public static void PressRight() => _right++; - public static void ReleaseRight() => _right = Mathf.Max(0, _right - 1); - - public static float Axis - { - get - { - if (_left > 0 && _right > 0) - return 0f; - if (_left > 0) - return -1f; - if (_right > 0) - return 1f; - return 0f; - } - } - - public static void Clear() - { - _left = 0; - _right = 0; - } -} diff --git a/First Principles/Assets/Scripts/UI/MobileTouchControls.cs.meta b/First Principles/Assets/Scripts/UI/MobileTouchControls.cs.meta deleted file mode 100644 index c759804..0000000 --- a/First Principles/Assets/Scripts/UI/MobileTouchControls.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a405162738495a6b7c8d9e0f1a2b3c4d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset index 6a24e10..3faafa4 100644 --- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset +++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset @@ -687,10 +687,313 @@ MonoBehaviour: m_XAdvance: 0 m_YAdvance: 0 m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 862 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 89159760 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 872 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 881 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1146060800 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 884 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 95103336 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 885 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 888 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 95072720 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 891 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 896 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 836 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -4.745117 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 3 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.8056641 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 843 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1969516365 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.8056641 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 850 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 83 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -4.9970703 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 854 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -6.3828125 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 855 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1289 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 839 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -6.3828125 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 861 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1109393408 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 55 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -4.745117 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 16 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 57 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -4.745117 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 16 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 58 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.5537109 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 16 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 60 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -7.8945312 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 16 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 855 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -7.810547 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 16 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 m_MarkToBaseAdjustmentRecords: [] m_MarkToMarkAdjustmentRecords: [] m_ShouldReimportFontFeatures: 0 - m_FallbackFontAssetTable: [] + m_FallbackFontAssetTable: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} m_FontWeightTable: - regularTypeface: {fileID: 0} italicTypeface: {fileID: 0} diff --git a/First Principles/UserSettings/Layouts/default-6000.dwlt b/First Principles/UserSettings/Layouts/default-6000.dwlt index 72ca1a4..2b0068b 100644 --- a/First Principles/UserSettings/Layouts/default-6000.dwlt +++ b/First Principles/UserSettings/Layouts/default-6000.dwlt @@ -20,11 +20,86 @@ MonoBehaviour: height: 995 m_ShowMode: 4 m_Title: Console - m_RootView: {fileID: 2} + m_RootView: {fileID: 5} m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} m_Maximized: 1 --- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.ContainerWindow + m_PixelRect: + serializedVersion: 2 + x: 163 + y: 307 + width: 725 + height: 578 + m_ShowMode: 0 + m_Title: Build Profiles + m_RootView: {fileID: 4} + m_MinSize: {x: 725, y: 426} + m_MaxSize: {x: 4000, y: 4026} + m_Maximized: 0 +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: BuildProfileWindow + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.DockArea + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 725 + height: 578 + m_MinSize: {x: 725, y: 426} + m_MaxSize: {x: 4000, y: 4026} + m_ActualView: {fileID: 15} + m_Panes: + - {fileID: 15} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.SplitView + m_Children: + - {fileID: 3} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 725 + height: 578 + m_MinSize: {x: 725, y: 426} + m_MaxSize: {x: 4000, y: 4026} + vertical: 0 + controlID: 508 + draggingID: 0 +--- !u!114 &5 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -37,9 +112,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Children: - - {fileID: 3} - - {fileID: 5} - - {fileID: 4} + - {fileID: 6} + - {fileID: 8} + - {fileID: 7} m_Position: serializedVersion: 2 x: 0 @@ -52,7 +127,7 @@ MonoBehaviour: m_TopViewHeight: 36 m_UseBottomView: 1 m_BottomViewHeight: 20 ---- !u!114 &3 +--- !u!114 &6 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -73,8 +148,8 @@ MonoBehaviour: height: 36 m_MinSize: {x: 50, y: 50} m_MaxSize: {x: 4000, y: 4000} - m_ActualView: {fileID: 12} ---- !u!114 &4 + m_ActualView: {fileID: 16} +--- !u!114 &7 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -95,7 +170,7 @@ MonoBehaviour: height: 20 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} ---- !u!114 &5 +--- !u!114 &8 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -108,8 +183,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Children: - - {fileID: 6} - - {fileID: 11} + - {fileID: 9} + - {fileID: 14} m_Position: serializedVersion: 2 x: 0 @@ -119,9 +194,9 @@ MonoBehaviour: m_MinSize: {x: 300, y: 112} m_MaxSize: {x: 24288, y: 16192} vertical: 0 - controlID: 63 + controlID: 52 draggingID: 0 ---- !u!114 &6 +--- !u!114 &9 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -134,8 +209,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Children: - - {fileID: 7} - {fileID: 10} + - {fileID: 13} m_Position: serializedVersion: 2 x: 0 @@ -145,9 +220,9 @@ MonoBehaviour: m_MinSize: {x: 200, y: 112} m_MaxSize: {x: 16192, y: 16192} vertical: 1 - controlID: 64 + controlID: 53 draggingID: 0 ---- !u!114 &7 +--- !u!114 &10 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -160,20 +235,20 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Children: - - {fileID: 8} - - {fileID: 9} + - {fileID: 11} + - {fileID: 12} m_Position: serializedVersion: 2 x: 0 y: 0 width: 962 - height: 604 + height: 605 m_MinSize: {x: 200, y: 56} m_MaxSize: {x: 16192, y: 8096} vertical: 0 - controlID: 65 + controlID: 54 draggingID: 0 ---- !u!114 &8 +--- !u!114 &11 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -191,15 +266,15 @@ MonoBehaviour: x: 0 y: 0 width: 226 - height: 604 + height: 605 m_MinSize: {x: 201, y: 226} m_MaxSize: {x: 4001, y: 4026} - m_ActualView: {fileID: 13} + m_ActualView: {fileID: 17} m_Panes: - - {fileID: 13} + - {fileID: 17} m_Selected: 0 m_LastSelected: 0 ---- !u!114 &9 +--- !u!114 &12 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -217,17 +292,17 @@ MonoBehaviour: x: 226 y: 0 width: 736 - height: 604 + height: 605 m_MinSize: {x: 202, y: 226} m_MaxSize: {x: 4002, y: 4026} - m_ActualView: {fileID: 14} + m_ActualView: {fileID: 18} m_Panes: - - {fileID: 14} - - {fileID: 15} - - {fileID: 16} + - {fileID: 18} + - {fileID: 19} + - {fileID: 20} m_Selected: 0 m_LastSelected: 1 ---- !u!114 &10 +--- !u!114 &13 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -243,18 +318,18 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 604 + y: 605 width: 962 - height: 335 + height: 334 m_MinSize: {x: 101, y: 126} m_MaxSize: {x: 4001, y: 4026} - m_ActualView: {fileID: 18} + m_ActualView: {fileID: 22} m_Panes: - - {fileID: 17} - - {fileID: 18} + - {fileID: 21} + - {fileID: 22} m_Selected: 1 m_LastSelected: 0 ---- !u!114 &11 +--- !u!114 &14 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -275,12 +350,50 @@ MonoBehaviour: height: 939 m_MinSize: {x: 276, y: 76} m_MaxSize: {x: 4001, y: 4026} - m_ActualView: {fileID: 19} + m_ActualView: {fileID: 23} m_Panes: - - {fileID: 19} + - {fileID: 23} m_Selected: 0 m_LastSelected: 0 ---- !u!114 &12 +--- !u!114 &15 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.BuildProfileModule.dll::UnityEditor.Build.Profile.BuildProfileWindow + m_MinSize: {x: 725, y: 400} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Build Profiles + m_Image: {fileID: 0} + m_Tooltip: + m_TextWithWhitespace: "Build Profiles\u200B" + m_Pos: + serializedVersion: 2 + x: 0 + y: 26 + width: 725 + height: 552 + m_SerializedDataModeController: + m_DataMode: 0 + m_PreferredDataMode: 0 + m_SupportedDataModes: + isAutomatic: 1 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_ContainerData: [] + m_DynamicPanelContainerData: [] + m_OverlaysVisible: 1 + m_DynamicPanelBehavior: 0 +--- !u!114 &16 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -546,7 +659,7 @@ MonoBehaviour: m_DynamicPanelContainerData: [] m_OverlaysVisible: 1 m_DynamicPanelBehavior: 0 ---- !u!114 &13 +--- !u!114 &17 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -570,7 +683,7 @@ MonoBehaviour: x: 0 y: 24 width: 225 - height: 578 + height: 579 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -591,21 +704,14 @@ MonoBehaviour: m_LastClickedID: m_Data: 0 m_ExpandedIDs: - - m_Data: -9474 - - m_Data: -9052 - - m_Data: -8046 - - m_Data: -7476 - - m_Data: -7464 - - m_Data: -7456 - - m_Data: -7380 - - m_Data: -7346 - - m_Data: -7224 - - m_Data: -7128 - - m_Data: -5988 - - m_Data: -5926 - - m_Data: -5440 - - m_Data: -1344 - - m_Data: 36266 + - m_Data: -62118 + - m_Data: -60778 + - m_Data: -60660 + - m_Data: -60636 + - m_Data: -60622 + - m_Data: -60586 + - m_Data: -35118 + - m_Data: -34368 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -632,7 +738,7 @@ MonoBehaviour: m_IsLocked: 0 m_CurrentSortingName: TransformSorting m_WindowGUID: 46b7a0fefa812c44ca6fda42b4d7b176 ---- !u!114 &14 +--- !u!114 &18 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -656,7 +762,7 @@ MonoBehaviour: x: 227 y: 24 width: 734 - height: 578 + height: 579 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1303,7 +1409,7 @@ MonoBehaviour: m_LastSceneViewRotation: {x: 0.31118897, y: 0.09269961, z: -0.030600414, w: 0.9453927} m_LastSceneViewOrtho: 1 m_Viewpoint: - m_SceneView: {fileID: 14} + m_SceneView: {fileID: 18} m_CameraOverscanSettings: m_Opacity: 50 m_Scale: 1 @@ -1316,7 +1422,7 @@ MonoBehaviour: name: Contributors / Receivers section: Lighting m_ViewIsLockedToObject: 0 ---- !u!114 &15 +--- !u!114 &19 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -1340,7 +1446,7 @@ MonoBehaviour: x: 226 y: 97 width: 734 - height: 578 + height: 579 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1360,7 +1466,7 @@ MonoBehaviour: m_ShowGizmos: 0 m_TargetDisplay: 0 m_ClearColor: {r: 0, g: 0, b: 0, a: 0} - m_TargetSize: {x: 2560, y: 1440} + m_TargetSize: {x: 1468, y: 1116} m_TextureFilterMode: 0 m_TextureHideFlags: 61 m_RenderIMGUI: 1 @@ -1375,10 +1481,10 @@ MonoBehaviour: m_VRangeLocked: 0 hZoomLockedByDefault: 0 vZoomLockedByDefault: 0 - m_HBaseRangeMin: -640 - m_HBaseRangeMax: 640 - m_VBaseRangeMin: -360 - m_VBaseRangeMax: 360 + m_HBaseRangeMin: -367 + m_HBaseRangeMax: 367 + m_VBaseRangeMin: -279 + m_VBaseRangeMax: 279 m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMax: 1 m_VAllowExceedBaseRangeMin: 1 @@ -1397,29 +1503,29 @@ MonoBehaviour: x: 0 y: 21 width: 734 - height: 557 - m_Scale: {x: 0.5734375, y: 0.5734375} - m_Translation: {x: 367, y: 278.5} + height: 558 + m_Scale: {x: 1, y: 1} + m_Translation: {x: 367, y: 279} m_MarginLeft: 0 m_MarginRight: 0 m_MarginTop: 0 m_MarginBottom: 0 m_LastShownAreaInsideMargins: serializedVersion: 2 - x: -640 - y: -485.66757 - width: 1280 - height: 971.33514 + x: -367 + y: -279 + width: 734 + height: 558 m_MinimalGUI: 1 - m_defaultScale: 0.5734375 - m_LastWindowPixelSize: {x: 1468, y: 1156} + m_defaultScale: 1 + m_LastWindowPixelSize: {x: 1468, y: 1158} m_ClearInEditMode: 1 m_NoCameraWarning: 1 m_LowResolutionForAspectRatios: 01000000000100000100 m_XRRenderMode: 0 m_RenderTexture: {fileID: 0} m_showToolbar: 1 ---- !u!114 &16 +--- !u!114 &20 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -1457,7 +1563,7 @@ MonoBehaviour: m_DynamicPanelContainerData: [] m_OverlaysVisible: 1 m_DynamicPanelBehavior: 0 ---- !u!114 &17 +--- !u!114 &21 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -1479,9 +1585,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 701 + y: 702 width: 961 - height: 309 + height: 308 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1506,7 +1612,7 @@ MonoBehaviour: m_SkipHidden: 0 m_SearchArea: 1 m_Folders: - - Assets/Scenes + - Assets/Scripts/Game m_Globs: [] m_ProductIds: m_AnyWithAssetOrigin: 0 @@ -1516,21 +1622,23 @@ MonoBehaviour: m_ViewMode: 1 m_StartGridSize: 16 m_LastFolders: - - Assets/Scenes + - Assets/Scripts/Game m_LastFoldersGridSize: 16 - m_LastProjectPath: /Users/johnseong/Documents/GitHub/First-Principles/First Principles + m_LastProjectPath: /Users/johnseong/Documents/GitHub2/First-Principles/First Principles m_LockTracker: m_IsLocked: 0 m_LastLocalAssetsSearchArea: 1 m_FolderTreeState: - scrollPos: {x: 0, y: 12.000122} + scrollPos: {x: 0, y: 80.00061} m_SelectedIDs: - - m_Data: 35280 + - m_Data: 40708 m_LastClickedID: - m_Data: 35280 + m_Data: 40708 m_ExpandedIDs: - m_Data: 0 - - m_Data: 34846 + - m_Data: 34560 + - m_Data: 1000000000 + - m_Data: 2147483647 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1548,7 +1656,7 @@ MonoBehaviour: m_OriginalEventType: 11 m_IsRenamingFilename: 1 m_TrimLeadingAndTrailingWhitespace: 0 - m_ClientGUIView: {fileID: 10} + m_ClientGUIView: {fileID: 13} m_SearchString: m_CreateAssetUtility: m_EndAction: {fileID: 0} @@ -1564,7 +1672,9 @@ MonoBehaviour: m_Data: 0 m_ExpandedIDs: - m_Data: 0 - - m_Data: 34846 + - m_Data: 34560 + - m_Data: 1000000000 + - m_Data: 2147483647 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1582,7 +1692,7 @@ MonoBehaviour: m_OriginalEventType: 11 m_IsRenamingFilename: 1 m_TrimLeadingAndTrailingWhitespace: 0 - m_ClientGUIView: {fileID: 10} + m_ClientGUIView: {fileID: 13} m_SearchString: m_CreateAssetUtility: m_EndAction: {fileID: 0} @@ -1592,10 +1702,9 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_ListAreaState: - m_SelectedInstanceIDs: - - m_Data: 35348 + m_SelectedInstanceIDs: [] m_LastClickedEntityId: - m_Data: 35348 + m_Data: 0 m_HadKeyboardFocusLastEvent: 1 m_ExpandedInstanceIDs: [] m_RenameOverlay: @@ -1615,7 +1724,7 @@ MonoBehaviour: m_OriginalEventType: 11 m_IsRenamingFilename: 1 m_TrimLeadingAndTrailingWhitespace: 0 - m_ClientGUIView: {fileID: 10} + m_ClientGUIView: {fileID: 13} m_CreateAssetUtility: m_EndAction: {fileID: 0} m_EntityId: @@ -1624,11 +1733,11 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_NewAssetIndexInList: -1 - m_ScrollPosition: {x: 0, y: 0} + m_ScrollPosition: {x: 0, y: 77.5} m_GridSize: 16 m_SkipHiddenPackages: 0 m_DirectoriesAreaWidth: 199 ---- !u!114 &18 +--- !u!114 &22 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} @@ -1650,9 +1759,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 628 + y: 629 width: 961 - height: 309 + height: 308 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1666,7 +1775,7 @@ MonoBehaviour: m_DynamicPanelContainerData: [] m_OverlaysVisible: 1 m_DynamicPanelBehavior: 0 ---- !u!114 &19 +--- !u!114 &23 MonoBehaviour: m_ObjectHideFlags: 52 m_CorrespondingSourceObject: {fileID: 0} diff --git a/Packages/manifest.json b/Packages/manifest.json new file mode 100644 index 0000000..be6ce35 --- /dev/null +++ b/Packages/manifest.json @@ -0,0 +1,39 @@ +{ + "dependencies": { + "com.unity.multiplayer.center": "1.0.1", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json new file mode 100644 index 0000000..6aaea1b --- /dev/null +++ b/Packages/packages-lock.json @@ -0,0 +1,287 @@ +{ + "dependencies": { + "com.unity.multiplayer.center": { + "version": "1.0.1", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.adaptiveperformance": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.subsystems": "1.0.0" + } + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0", + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vectorgraphics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..50b4625 --- /dev/null +++ b/ProjectSettings/AudioManager.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_EnableOutputSuspension: 1 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 + m_AudioFoundation: 0 + m_OutputChannelLayout: 2 + m_OutputSamplingRate: 48000 diff --git a/ProjectSettings/ClusterInputManager.asset b/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..af0927b --- /dev/null +++ b/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,45 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 23 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_DefaultMaxDepenetrationVelocity: 10 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_SimulationMode: 0 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_InvokeCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 256, y: 256, z: 256} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_ImprovedPatchFriction: 0 + m_GenerateOnTriggerStayEvents: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 + m_ScratchBufferChunkCount: 4 + m_CurrentBackendId: 4072204805 + m_FastMotionThreshold: 3.4028235e+38 + m_SceneBuffersReleaseInterval: 0 + m_ReleaseSceneBuffers: 0 + m_LogVerbosity: 3 + m_IncrementalStaticBroadphase: 1 diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..0147887 --- /dev/null +++ b/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] + m_configObjects: {} diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..092d90f --- /dev/null +++ b/ProjectSettings/EditorSettings.asset @@ -0,0 +1,52 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 15 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 1 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerCacheSize: 10 + m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp;java;cpp;c;mm;m;h + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_EnableEditorAsyncCPUTextureLoading: 0 + m_AsyncShaderCompilation: 1 + m_BlockShaders: 0 + m_UnlockBlockShaders: 0 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_InspectorUseIMGUIDefaultInspector: 0 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_ShadowmaskStitching: 1 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 + m_EnableEnlightenBakedGI: 0 + m_ReferencedClipsExactNaming: 1 + m_ForceAssetUnloadAndGCOnSceneLoad: 1 + m_HideBuildProfileClassicPlatforms: 0 diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..4b152c0 --- /dev/null +++ b/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,68 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 16 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_RenderPipelineGlobalSettingsMap: {} + m_ShaderBuildSettings: + keywordDeclarationOverrides: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_LightProbeOutsideHullStrategy: 1 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..8068b20 --- /dev/null +++ b/ProjectSettings/InputManager.asset @@ -0,0 +1,296 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + m_UsePhysicalKeys: 1 diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..517e60e --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: [] diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..c19bcd7 --- /dev/null +++ b/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_EnablePlayModeLocalDeployment: 0 + m_EnablePlayModeRemoteDeployment: 0 + m_StrippingTypes: {} diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..2e2e369 --- /dev/null +++ b/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,93 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..944120c --- /dev/null +++ b/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,42 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.PackageManager.UI.Internal.PackageManagerProjectSettings + m_EnablePreReleasePackages: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 + oneTimeWarningShown: 0 + oneTimePackageErrorsPopUpShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_ConfigSource: 0 + m_Compliance: + m_Status: 0 + m_Violations: [] + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsEntityId: + m_Data: -982 + m_OriginalEntityId: + m_Data: -984 + m_LoadAssets: 0 diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..14f419f --- /dev/null +++ b/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_BounceThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_ContactThreshold: 0 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_SimulationMode: 0 + m_SimulationLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_MaxSubStepCount: 4 + m_MinSubStepFPS: 30 + m_UseSubStepping: 0 + m_UseSubStepContacts: 0 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_GizmoOptions: 10 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_PhysicsLowLevelSettings: {fileID: 0} diff --git a/ProjectSettings/PresetManager.asset b/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..f5fc046 --- /dev/null +++ b/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,893 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 28 + productGUID: cb17d67df55ec447ebac830ac522c475 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: First-Principles + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.12156863, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidDisplayOptions: 1 + androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 1 + androidApplicationEntry: 2 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + audioSpatialExperience: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 0 + meshDeformation: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + metalUseMetalDisplayLink: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + switchGraphicsJobsSyncAfterKick: 1 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.4 + androidMinAspectRatio: 1 + applicationIdentifier: {} + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 25 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + AndroidPreferredDataLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + androidSplitApplicationBinary: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: 15.0 + tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 15.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 00000000000000000000000000000000 + templatePackageId: + templateDefaultScene: + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 2 + AndroidAllowedArchitectures: -1 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + androidAppCategory: 3 + useAndroidAppCategory: 1 + androidAppCategoryOther: + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 200 + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + - m_BuildTarget: VisionOS + m_Icons: + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 0 + m_SubKind: + m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: [] + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + VisionOS: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupHDRCubemapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 12.0 + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 1 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: ECp4dfdfR9jy4dcWcL8JnVortaXumDPN + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 + webEnableSubmoduleStrippingCompatibility: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: First-Principles + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: First-Principles + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 0 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: + apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] + androidVulkanDeviceFilterListAsset: {fileID: 0} + d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..8a87982 --- /dev/null +++ b/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.4.0f1 +m_EditorVersionWithRevision: 6000.4.0f1 (8cf496087c8f) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..64f8aba --- /dev/null +++ b/ProjectSettings/QualitySettings.asset @@ -0,0 +1,347 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 5 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 1 + globalTextureMipmapLimit: 1 + textureMipmapLimitSettings: [] + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.3 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.4 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.7 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1.5 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 255 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 2 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Android: 2 + EmbeddedLinux: 5 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Kepler: 5 + LinuxHeadlessSimulation: 5 + Nintendo Switch: 5 + Nintendo Switch 2: 5 + PS4: 5 + PS5: 5 + QNX: 5 + Server: 5 + Standalone: 5 + VisionOS: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..6abf33d --- /dev/null +++ b/ProjectSettings/TagManager.asset @@ -0,0 +1,46 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 3 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 + m_RenderingLayers: + - Default + m_MigratedRenderPipelines: [] diff --git a/ProjectSettings/TimeManager.asset b/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..2e23a1f --- /dev/null +++ b/ProjectSettings/TimeManager.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + Fixed Timestep: + m_Count: 2822399 + m_Rate: + m_Denominator: 1 + m_Numerator: 141120000 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..5ef5698 --- /dev/null +++ b/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,40 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + InsightsSettings: + m_EngineDiagnosticsEnabled: 0 + m_Enabled: 0 + CrashReportingSettings: + serializedVersion: 2 + m_EventUrl: https://perf-events.cloud.unity3d.com + m_EnableCloudDiagnosticsReporting: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/ProjectSettings/VFXManager.asset b/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..56783bb --- /dev/null +++ b/ProjectSettings/VFXManager.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_PrefixSumShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_EmptyShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 + m_MaxScrubTime: 30 + m_MaxCapacity: 100000000 + m_CompiledVersion: 0 + m_RuntimeVersion: 0 + m_RuntimeResources: {fileID: 0} + m_BatchEmptyLifetime: 300 diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..979fd8e --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_TrackPackagesOutsideProject: 0 From 09524db4bb07e15b4f2205faa890f46b8bd45d7e Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 18:34:38 -0400 Subject: [PATCH 03/14] Updated --- .../UI_BlackHoleGargantuaBackdrop.shader | 208 ++++++++++++++++++ .../UI_BlackHoleGargantuaBackdrop.shader.meta | 9 + .../Scripts/Functions/FunctionPlotter.cs | 3 +- .../Scripts/UI/BlackHoleGargantuaBackdrop.cs | 142 ++++++++++++ .../UI/BlackHoleGargantuaBackdrop.cs.meta | 2 + 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader create mode 100644 First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta create mode 100644 First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs create mode 100644 First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs.meta diff --git a/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader new file mode 100644 index 0000000..0a6dbbc --- /dev/null +++ b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader @@ -0,0 +1,208 @@ +// GPU backdrop for the gravity-well boss: Schwarzschild equatorial null geodesics. +// Math: photon Binet equation d²u/dφ² + u = 3 M u² with u = 1/r (G = c = 1). +// First integral (conserved b = L/E): (du/dφ)² = (1−2Mu)²/b² − u² + 2M u³. +// Ray is stepped in φ; emission samples a thin equatorial accretion disk (multiple passes = lensed images). +// Not full Kerr (Gargantua is rotating); Schwarzschild is the documented GR core here. +Shader "UI/BlackHoleGargantuaBackdrop" +{ + Properties + { + [PerRendererData] _MainTex ("Dummy", 2D) = "white" {} + _Color ("Multiply", Color) = (1, 1, 1, 0.78) + _Mass ("M (geometric units, Rs=2M)", Float) = 1 + _CamDist ("Observer Schwarzschild r", Float) = 16 + _BMin ("Impact param b min", Float) = 3.3 + _BMax ("Impact param b max", Float) = 14 + _DiskIn ("Disk inner r / M", Float) = 3.35 + _DiskOut ("Disk outer r / M", Float) = 9 + _DiskSpin ("Disk phase speed", Float) = 0.35 + _DiskBright ("Disk emissivity", Float) = 2.4 + _PhotonRing ("Photon ring boost", Float) = 1.15 + _Dphi ("φ step (radians)", Float) = 0.045 + _Steps ("Integration steps", Int) = 88 + _Aspect ("UV width / height", Float) = 1.7 + _TimeLive ("Time (set from C#)", Float) = 0 + _StarField ("Star field strength", Float) = 0.085 + } + + SubShader + { + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + ZWrite Off + ZTest Always + Blend SrcAlpha OneMinusSrcAlpha + Cull Off + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + #include "UnityCG.cginc" + + sampler2D _MainTex; + float4 _MainTex_ST; + float4 _Color; + float _Mass; + float _CamDist; + float _BMin; + float _BMax; + float _DiskIn; + float _DiskOut; + float _DiskSpin; + float _DiskBright; + float _PhotonRing; + float _Dphi; + int _Steps; + float _Aspect; + float _TimeLive; + float _StarField; + + struct appdata + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float4 color : COLOR; + float2 uv : TEXCOORD0; + }; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.color = v.color; + o.uv = v.texcoord; + return o; + } + + // Cheap hash for star speckle (not physical, background only). + float n2(float2 p) + { + return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); + } + + void rk4Step(inout float u, inout float v, inout float phi, float M, float h) + { + float h2 = h * 0.5; + float k1u = v; + float k1v = 3.0 * M * u * u - u; + float u2 = u + h2 * k1u; + float v2 = v + h2 * k1v; + float k2u = v2; + float k2v = 3.0 * M * u2 * u2 - u2; + u2 = u + h2 * k2u; + v2 = v + h2 * k2v; + float k3u = v2; + float k3v = 3.0 * M * u2 * u2 - u2; + u2 = u + h * k3u; + v2 = v + h * k3v; + float k4u = v2; + float k4v = 3.0 * M * u2 * u2 - u2; + u += h * (k1u + 2.0 * k2u + 2.0 * k3u + k4u) / 6.0; + v += h * (k1v + 2.0 * k2v + 2.0 * k3v + k4v) / 6.0; + phi += h; + } + + fixed4 frag(v2f i) : SV_Target + { + float2 uv = i.uv; + float M = max(_Mass, 0.05); + float Rs = 2.0 * M; + float rObs = max(_CamDist, Rs * 1.5); + float u = 1.0 / rObs; + float b = lerp(_BMin, _BMax, uv.x); + b = max(b, Rs * 1.01); + float fMu = 1.0 - 2.0 * M * u; + if (fMu <= 0.001) + return fixed4(0, 0, 0, _Color.a * i.color.a); + + float disc = (1.0 / (b * b)) * fMu * fMu - u * u + 2.0 * M * u * u * u; + if (disc < 0.0) + disc = 0.0; + float v = sqrt(disc); + float vy = (uv.y - 0.5) * 2.2; + v *= 1.0 + vy * 0.18; + + float phi = 0.0; + int steps = clamp(_Steps, 24, 128); + float h = max(_Dphi, 0.012); + + float3 acc = float3(0, 0, 0); + float dIn = _DiskIn * M; + float dOut = _DiskOut * M; + float rPhIn = 2.95 * M; + float rPhOut = 3.15 * M; + + for (int k = 0; k < 128; k++) + { + if (k >= steps) + break; + + float r = 1.0 / max(u, 1e-5); + if (r < Rs + 0.015) + { + acc += float3(0, 0, 0.015); + break; + } + + float x = r * cos(phi); + float z = r * sin(phi); + float rho = sqrt(x * x + z * z); + + if (rho > dIn && rho < dOut) + { + float t = saturate((rho - dIn) / max(dOut - dIn, 1e-3)); + float band = smoothstep(0.0, 0.08, t) * smoothstep(1.0, 0.92, t); + float spin = phi + _TimeLive * _DiskSpin; + float dop = 1.0 + 0.42 * sin(spin + uv.x * 6.28318); + dop *= 1.0 - 0.22 * sin(spin * 0.5 + vy * 3.14); + float3 hot = lerp(float3(1.0, 0.18, 0.02), float3(1.0, 0.55, 0.2), t); + hot = lerp(hot, float3(1.0, 0.85, 0.55), pow(t, 2.2)); + acc += hot * band * dop * _DiskBright * h * 2.8; + } + + if (rho > rPhIn && rho < rPhOut) + { + float pr = smoothstep(rPhIn, rPhIn + 0.04 * M, rho) * smoothstep(rPhOut, rPhOut - 0.04 * M, rho); + acc += float3(1.0, 0.95, 0.78) * pr * _PhotonRing * h * 0.45; + } + + rk4Step(u, v, phi, M, h); + + if (u < 0.0 || u > 200.0) + break; + + if (u > 1.0 / max(Rs * 0.98, 1e-4)) + break; + } + + float2 suv = uv * float2(_Aspect * 120.0, 120.0); + float stars = pow(n2(floor(suv)), 12.0) * _StarField; + acc += float3(0.55, 0.62, 1.0) * stars; + + float lum = max(max(acc.x, acc.y), acc.z); + acc = acc / (lum + 0.85); + fixed4 outc = fixed4(acc, _Color.a * i.color.a); + outc.rgb *= _Color.rgb * i.color.rgb; + return outc; + } + ENDCG + } + } + FallBack Off +} diff --git a/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta new file mode 100644 index 0000000..10331f2 --- /dev/null +++ b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6fa2973b396514f74aff0c0946fabcf4 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs index 5508128..f8606d0 100644 --- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs +++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs @@ -393,11 +393,12 @@ private void PlotFunction(FunctionType type) } } - // Boss: show classic Mandelbrot set in c-plane behind the grid (1D slice curve on top). + // Boss backdrops: Mandelbrot c-plane; Schwarzschild-style black hole (GPU shader). if (lineRenderer != null) { var gridRt = lineRenderer.transform.parent as RectTransform; MandelbrotFractalBackdrop.Sync(gridRt, this); + BlackHoleGargantuaBackdrop.Sync(gridRt, this); PushGraphRevealToRenderers(); } } diff --git a/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs new file mode 100644 index 0000000..b919953 --- /dev/null +++ b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs @@ -0,0 +1,142 @@ +using UnityEngine; +using UnityEngine.UI; + +// ----------------------------------------------------------------------------- +// BlackHoleGargantuaBackdrop — Schwarzschild photon paths on the GPU (boss stage) +// ----------------------------------------------------------------------------- +// Fragment shader integrates u'' + u = 3 M u² (equatorial null geodesics) with +// conserved impact parameter b; procedural accretion disk + photon ring for a +// Gargantua-like mood. Sync hides the layer off-stage to avoid cost. +// ----------------------------------------------------------------------------- + +/// +/// Runtime child under the graph ; toggled from . +/// +[DisallowMultipleComponent] +[RequireComponent(typeof(RawImage))] +public sealed class BlackHoleGargantuaBackdrop : MonoBehaviour +{ + public const string ChildName = "_BlackHoleGargantuaBackdrop"; + + static readonly int IdTimeLive = Shader.PropertyToID("_TimeLive"); + static readonly int IdAspect = Shader.PropertyToID("_Aspect"); + + RawImage _raw; + Material _mat; + int _paramHash = int.MinValue; + + void Awake() + { + _raw = GetComponent(); + _raw.raycastTarget = false; + } + + void OnDestroy() + { + if (_mat != null) + Destroy(_mat); + } + + void Update() + { + if (_mat == null || !_raw.gameObject.activeInHierarchy) + return; + _mat.SetFloat(IdTimeLive, Time.time); + } + + /// Creates / hides the child on ; drives shader params when visible. + public static void Sync(RectTransform gridPanel, FunctionPlotter fp) + { + if (gridPanel == null || fp == null) + return; + + Transform existing = gridPanel.Find(ChildName); + if (fp.functionType != FunctionType.PhysicsGravityWellInverseSqrt) + { + if (existing != null) + existing.gameObject.SetActive(false); + return; + } + + GameObject go; + if (existing == null) + { + go = new GameObject(ChildName, typeof(RectTransform), typeof(CanvasRenderer), typeof(RawImage), typeof(BlackHoleGargantuaBackdrop)); + go.transform.SetParent(gridPanel, false); + var rt = go.GetComponent(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + var raw = go.GetComponent(); + raw.raycastTarget = false; + raw.texture = Texture2D.whiteTexture; + raw.color = Color.white; + } + else + go = existing.gameObject; + + go.SetActive(true); + go.transform.SetAsFirstSibling(); + + var backdrop = go.GetComponent(); + if (backdrop == null) + backdrop = go.AddComponent(); + backdrop.Drive(fp); + } + + void EnsureMaterial() + { + if (_mat != null) + return; + + Shader sh = Resources.Load("UI_BlackHoleGargantuaBackdrop"); + if (sh == null) + sh = Shader.Find("UI/BlackHoleGargantuaBackdrop"); + if (sh == null) + { + Debug.LogWarning("BlackHoleGargantuaBackdrop: shader UI_BlackHoleGargantuaBackdrop not found (place under Resources)."); + return; + } + + _mat = new Material(sh); + _raw.material = _mat; + } + + public void Drive(FunctionPlotter fp) + { + EnsureMaterial(); + if (_mat == null) + return; + + Rect r = ((RectTransform)transform).rect; + float aspect = r.height > 1e-3f ? Mathf.Max(0.2f, r.width / r.height) : 1.7f; + + // Map level softening |D| → shader mass scale (gameplay uses softened 1/r well). + float mass = Mathf.Lerp(0.75f, 1.35f, Mathf.Clamp01(Mathf.Abs(fp.transD) / 0.5f)); + float bMin = 3.1f * mass; + float bMax = 13.5f * mass + Mathf.Abs(fp.transA) * 0.08f; + + int h; + unchecked + { + h = 17; + h = h * 31 + fp.transA.GetHashCode(); + h = h * 31 + fp.transD.GetHashCode(); + h = h * 31 + aspect.GetHashCode(); + h = h * 31 + mass.GetHashCode(); + } + + _mat.SetFloat(IdAspect, aspect); + _mat.SetFloat("_Mass", mass); + _mat.SetFloat("_BMin", bMin); + _mat.SetFloat("_BMax", bMax); + _mat.SetFloat("_CamDist", 14f + Mathf.Clamp(fp.transA, 0f, 8f) * 0.12f); + + if (h != _paramHash) + { + _paramHash = h; + _mat.SetFloat("_DiskBright", 2.2f + Mathf.Clamp01(fp.transK - 0.5f) * 0.6f); + } + } +} diff --git a/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs.meta b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs.meta new file mode 100644 index 0000000..8e615f3 --- /dev/null +++ b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2ec844ef3fff648cca5b935138632da5 \ No newline at end of file From d669f04f66d12077cd2505e9c246c94052bc9f79 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 18:46:17 -0400 Subject: [PATCH 04/14] Added golden ratio stage and black hole --- .../Assets/Resources/Localization/ar.txt | 51 +++-- .../Assets/Resources/Localization/cs.txt | 53 +++-- .../Assets/Resources/Localization/de.txt | 51 +++-- .../Assets/Resources/Localization/en.txt | 55 +++-- .../Assets/Resources/Localization/es.txt | 51 +++-- .../Assets/Resources/Localization/fr.txt | 51 +++-- .../Assets/Resources/Localization/hi.txt | 51 +++-- .../Assets/Resources/Localization/it.txt | 53 +++-- .../Assets/Resources/Localization/ja.txt | 51 +++-- .../Assets/Resources/Localization/ko.txt | 53 +++-- .../Assets/Resources/Localization/pl.txt | 53 +++-- .../Assets/Resources/Localization/ru.txt | 53 +++-- .../Assets/Resources/Localization/ur.txt | 51 +++-- .../Assets/Resources/Localization/zh.txt | 51 +++-- .../Resources/UI_GoldenSpiralBackdrop.shader | 121 +++++++++++ .../UI_GoldenSpiralBackdrop.shader.meta | 9 + .../Resources/UI_WindTunnelBackdrop.shader | 156 ++++++++++++++ .../UI_WindTunnelBackdrop.shader.meta | 9 + .../Scripts/Functions/FunctionPlotter.cs | 7 +- .../Assets/Scripts/Game/GameLevelCatalog.cs | 23 +- .../Assets/Scripts/Game/LevelDefinition.cs | 3 + .../Assets/Scripts/Game/LevelManager.cs | 203 ++++++++---------- .../Scripts/Game/StageRoleplayLibrary.cs | 50 +++-- .../Scripts/UI/BlackHoleGargantuaBackdrop.cs | 11 +- .../Assets/Scripts/UI/GoldenSpiralBackdrop.cs | 122 +++++++++++ .../Scripts/UI/GoldenSpiralBackdrop.cs.meta | 11 + .../Assets/Scripts/UI/WindTunnelBackdrop.cs | 119 ++++++++++ .../Scripts/UI/WindTunnelBackdrop.cs.meta | 2 + 28 files changed, 1055 insertions(+), 519 deletions(-) create mode 100644 First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader create mode 100644 First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta create mode 100644 First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader create mode 100644 First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta create mode 100644 First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs create mode 100644 First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs.meta create mode 100644 First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs create mode 100644 First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs.meta diff --git a/First Principles/Assets/Resources/Localization/ar.txt b/First Principles/Assets/Resources/Localization/ar.txt index b23ec65..2b10076 100644 --- a/First Principles/Assets/Resources/Localization/ar.txt +++ b/First Principles/Assets/Resources/Localization/ar.txt @@ -64,29 +64,28 @@ level.30=BC: طور وحركة توافقية بسيطة (طاقة) level.31=BC: تكعيب ونقطة انعطاف (رسم) level.32=BC: b^x و d/dx b^x level.33=دائرة: (x−h)² + (y−k)² = R² -level.34=طيران: رفع C_L(α) خطي + انفصال -level.35=طيران: قطب السحب (طفيلي، مُستحثّ، إجمالي) -level.36=طيران: جو متساوي الحرارة ρ(h) -level.37=طيران: حركة مجنحة / اهتزاز مُخمَّد -level.38=طيران: نيوتوني Cp ~ sin²α -level.39=طيران: Strouhal / نبرة انبعاث دوامات -level.40=طيران: غلاف دخول غلاف جوي (تسخين ρV) -level.41=اقتصاد: فقاعة الدوت كوم والانهيار (مؤشر توضيحي) -level.42=اقتصاد: أزمة 2008 والتعافي (مؤشر توضيحي) -level.43=الزعيم: شريحة هروب ماندلبروت (كسيري) -level.44=فيزياء C: الديناميكا الحرارية (P–V أديباتي، γ من N) -level.45=زعيم: لولب النسبة الذهبية (قطبي لوغاريتمي) -level.46=تحويلات: فورييه — طيف sinc -level.47=تحويلات: لابلاس — تضاؤل أسي -level.48=زعيم: ماندلبروت — الختام (شريحة هروب كسيرية) -level.49=زعيم: جاذب لورينز — نظرية الفوضى (جذاب غريب) -level.50=زعيم: ثقب أسود — بئر جاذبية (مقطع 1/r) -level.51=فيزياء C: نابض–كتلة حركة توافقية (قانون هوك، بلا تخميد) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=فيزياء C: الديناميكا الحرارية (P–V أديباتي، γ من N) +level.35=طيران: رفع C_L(α) خطي + انفصال +level.36=طيران: قطب السحب (طفيلي، مُستحثّ، إجمالي) +level.37=طيران: جو متساوي الحرارة ρ(h) +level.38=طيران: حركة مجنحة / اهتزاز مُخمَّد +level.39=طيران: نيوتوني Cp ~ sin²α +level.40=طيران: Strouhal / نبرة انبعاث دوامات +level.41=طيران: غلاف دخول غلاف جوي (تسخين ρV) +level.42=اقتصاد: فقاعة الدوت كوم والانهيار (مؤشر توضيحي) +level.43=اقتصاد: أزمة 2008 والتعافي (مؤشر توضيحي) +level.44=تحويلات: فورييه — طيف sinc +level.45=تحويلات: لابلاس — تضاؤل أسي +level.46=زعيم: لولب النسبة الذهبية (قطبي لوغاريتمي) +level.47=زعيم: ماندلبروت — الختام (شريحة هروب كسيرية) +level.48=زعيم: جاذب لورينز — نظرية الفوضى (جذاب غريب) +level.49=زعيم: ثقب أسود — بئر جاذبية (مقطع 1/r) +level.50=فيزياء C: نابض–كتلة حركة توافقية (قانون هوك، بلا تخميد) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/cs.txt b/First Principles/Assets/Resources/Localization/cs.txt index 1178c7b..8562d61 100644 --- a/First Principles/Assets/Resources/Localization/cs.txt +++ b/First Principles/Assets/Resources/Localization/cs.txt @@ -7,7 +7,7 @@ level_select.cat.integration=Mult proměnné a integrály level_select.cat.engineering=Inženýrství level_select.cat.ap_bc=AP Calculus BC a fyzika C level_select.cat.aerospace=Letectví a kosmonautika -level_select.cat.finale=Pokročilé a boss +level_select.cat.economics=Ekonomie level_select.cat.transforms=Transformace level_select.cat.final_boss=Finální boss level_select.cat.spring_physics=Pružina a SHM @@ -85,29 +85,28 @@ level.30=BC: fáze a SHM (výměna energie) level.31=BC: kubická a inflexe (náčrt) level.32=BC: b^x a d/dx b^x level.33=Kružnice: (x−h)² + (y−k)² = R² -level.34=Aerospace: vztlak C_L(α) lineární + vývrt -level.35=Aerospace: polára odporu (parazitní, indukovaná, celková) -level.36=Aerospace: isotermická atmosféra ρ(h) -level.37=Aerospace: fugoid / tlumený režim výška–klopení -level.38=Aerospace: Newtonovské Cp ~ sin²α -level.39=Aerospace: Strouhal / tón von Kármána -level.40=Aerospace: obal útlumu při vstupu (ρV teplo) -level.41=Ekonomika: bublina dot-com a pád (stylizovaný index) -level.42=Ekonomika: krize 2008 a oživení (stylizovaný index) -level.43=BOSS: řez úniku Mandelbrota (fraktálová nálada) -level.44=Fyzika C: termodynamika (adiabatické P–V, γ z N) -level.45=BOSS: zlatá spirála (logaritmická polární) -level.46=Transformace: Fourier — sinc (spektrum) -level.47=Transformace: Laplace — exponenciální pokles -level.48=BOSS: Mandelbrot — finále (fraktálový únikový řez) -level.49=BOSS: Lorenzův atraktor — teorie chaosu (podivný atraktor) -level.50=BOSS: černá díra — gravitační jáma (řez ∝ 1/r) -level.51=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) \ No newline at end of file +level.34=Fyzika C: termodynamika (adiabatické P–V, γ z N) +level.35=Aerospace: vztlak C_L(α) lineární + vývrt +level.36=Aerospace: polára odporu (parazitní, indukovaná, celková) +level.37=Aerospace: isotermická atmosféra ρ(h) +level.38=Aerospace: fugoid / tlumený režim výška–klopení +level.39=Aerospace: Newtonovské Cp ~ sin²α +level.40=Aerospace: Strouhal / tón von Kármána +level.41=Aerospace: obal útlumu při vstupu (ρV teplo) +level.42=Ekonomika: bublina dot-com a pád (stylizovaný index) +level.43=Ekonomika: krize 2008 a oživení (stylizovaný index) +level.44=Transformace: Fourier — sinc (spektrum) +level.45=Transformace: Laplace — exponenciální pokles +level.46=BOSS: zlatá spirála (logaritmická polární) +level.47=BOSS: Mandelbrot — finále (fraktálový únikový řez) +level.48=BOSS: Lorenzův atraktor — teorie chaosu (podivný atraktor) +level.49=BOSS: černá díra — gravitační jáma (řez ∝ 1/r) +level.50=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) \ No newline at end of file diff --git a/First Principles/Assets/Resources/Localization/de.txt b/First Principles/Assets/Resources/Localization/de.txt index a694657..44e52d4 100644 --- a/First Principles/Assets/Resources/Localization/de.txt +++ b/First Principles/Assets/Resources/Localization/de.txt @@ -64,29 +64,28 @@ level.30=BC: Phase & SHM (Energie) level.31=BC: Kubik & Wendepunkt (Skizze) level.32=BC: b^x & d/dx b^x level.33=Kreis: (x−h)² + (y−k)² = R² -level.34=Luftfahrt: Auftrieb C_L(α) linear + Strömungsabriss -level.35=Luftfahrt: Widerstandspolare (profil-, induziert, gesamt) -level.36=Luftfahrt: isotherme Atmosphäre ρ(h) -level.37=Luftfahrt: Phugoid / gedämpfte Nick-Hubbewegung -level.38=Luftfahrt: newtonsch Cp ~ sin²α -level.39=Luftfahrt: Strouhal / Wirbelabwurf-Ton -level.40=Luftfahrt: Wiedereintritts-Hülle (ρV Erwärmung) -level.41=Wirtschaft: Dotcom-Blase & Crash (stilisierter Index) -level.42=Wirtschaft: Krise 2008 & Erholung (stilisierter Index) -level.43=BOSS: Mandelbrot-Escapeschnitt (Fraktal) -level.44=Physik C: Thermodynamik (adiabater P–V-Verlauf, γ aus N) -level.45=BOSS: Goldener-Spiralen-Logarithmus (Polar) -level.46=Transformationen: Fourier — sinc-Spektrum -level.47=Transformationen: Laplace — exponentieller Abfall -level.48=BOSS: Mandelbrot — Finale (Fraktal-Escape-Schnitt) -level.49=BOSS: Lorenz-Attraktor — Chaos-Theorie (seltsamer Attraktor) -level.50=BOSS: Schwarzes Loch — Gravitationsbrunnen (1/r-Schnitt) -level.51=Physik C: Feder–Masse SHM (Hooke, ungedämpft) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Physik C: Thermodynamik (adiabater P–V-Verlauf, γ aus N) +level.35=Luftfahrt: Auftrieb C_L(α) linear + Strömungsabriss +level.36=Luftfahrt: Widerstandspolare (profil-, induziert, gesamt) +level.37=Luftfahrt: isotherme Atmosphäre ρ(h) +level.38=Luftfahrt: Phugoid / gedämpfte Nick-Hubbewegung +level.39=Luftfahrt: newtonsch Cp ~ sin²α +level.40=Luftfahrt: Strouhal / Wirbelabwurf-Ton +level.41=Luftfahrt: Wiedereintritts-Hülle (ρV Erwärmung) +level.42=Wirtschaft: Dotcom-Blase & Crash (stilisierter Index) +level.43=Wirtschaft: Krise 2008 & Erholung (stilisierter Index) +level.44=Transformationen: Fourier — sinc-Spektrum +level.45=Transformationen: Laplace — exponentieller Abfall +level.46=BOSS: Goldener-Spiralen-Logarithmus (Polar) +level.47=BOSS: Mandelbrot — Finale (Fraktal-Escape-Schnitt) +level.48=BOSS: Lorenz-Attraktor — Chaos-Theorie (seltsamer Attraktor) +level.49=BOSS: Schwarzes Loch — Gravitationsbrunnen (1/r-Schnitt) +level.50=Physik C: Feder–Masse SHM (Hooke, ungedämpft) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index 373e3f3..6255da8 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -8,7 +8,7 @@ level_select.cat.integration=Multivar & integration level_select.cat.engineering=Engineering level_select.cat.ap_bc=AP Calculus BC & Physics C level_select.cat.aerospace=Aerospace -level_select.cat.finale=Advanced & boss +level_select.cat.economics=Economics level_select.cat.transforms=Transforms level_select.cat.final_boss=Final boss level_select.cat.spring_physics=Spring & SHM @@ -53,7 +53,7 @@ graph.polar.param_c=C (r shift) graph.polar.param_d=D (θ phase / axis shift) graph.polar.line4=A={0}  k={1}  C={2}  D={3}   θ∈[{4},{5}] graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale & pinch zoom the window. -# Prepended to story text for every Aerospace stage (indices 34–40). +# Prepended to story text for every Aerospace stage (indices 35–41). aerospace.story_drag_polar_preamble=Drag polar refresher (every Aerospace stage)\nParasitic (zero-lift) drag — skin friction, form drag, interference lumped as CD0 in the parabolic model (roughly not the part that grows with lift).\nInduced drag — the cost of making lift: trailing vortices add ~ K CL² (higher CL / tighter turns → more induced).\nOverall drag polarCD = CD0 + K CL²: an upward-opening parabola in CL; min-drag CL sits between “too slow / high α” and “too fast / low α” for real missions. menu.tutorial_button=How to play menu.tutorial_title=How to play @@ -99,29 +99,28 @@ level.30=BC: phase & SHM (energy swaps) level.31=BC: cubic & inflection (sketching) level.32=BC: b^x & d/dx b^x level.33=Circle: (x−h)² + (y−k)² = R² -level.34=Aerospace: lift C_L(α) linear + stall -level.35=Aerospace: drag polar (parasitic, induced, total) -level.36=Aerospace: isothermal atmosphere ρ(h) -level.37=Aerospace: phugoid / damped pitch–heave mood -level.38=Aerospace: Newtonian Cp ~ sin²α -level.39=Aerospace: Strouhal / vortex shedding tone -level.40=Aerospace: re-entry decay envelope (ρV heating mood) -level.41=Economics: dot-com bubble & crash (stylized index) -level.42=Economics: 2008 crisis & recovery (stylized index) -level.43=BOSS: Mandelbrot escape slice (fractal boundary mood) -level.44=Physics C: thermodynamics (adiabatic P–V, γ from N) -level.45=BOSS: golden ratio spiral (logarithmic polar) -level.46=Transforms: Fourier — sinc spectrum (rect ↔ sinc) -level.47=Transforms: Laplace — causal exponential decay -level.48=BOSS: Mandelbrot — finale (fractal escape slice) -level.49=BOSS: Lorenz attractor — Chaos Theory (strange attractor) -level.50=BOSS: Black hole — gravity well (1/r slice) -level.51=Physics C: spring–mass SHM (Hooke's law, undamped) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Physics C: thermodynamics (adiabatic P–V, γ from N) +level.35=Aerospace: lift C_L(α) linear + stall +level.36=Aerospace: drag polar (parasitic, induced, total) +level.37=Aerospace: isothermal atmosphere ρ(h) +level.38=Aerospace: phugoid / damped pitch–heave mood +level.39=Aerospace: Newtonian Cp ~ sin²α +level.40=Aerospace: Strouhal / vortex shedding tone +level.41=Aerospace: re-entry decay envelope (ρV heating mood) +level.42=Economics: dot-com bubble & crash (stylized index) +level.43=Economics: 2008 crisis & recovery (stylized index) +level.44=Transforms: Fourier — sinc spectrum (rect ↔ sinc) +level.45=Transforms: Laplace — causal exponential decay +level.46=BOSS: golden ratio spiral (logarithmic polar) +level.47=BOSS: Mandelbrot — finale (fractal escape slice) +level.48=BOSS: Lorenz attractor — Chaos Theory (strange attractor) +level.49=BOSS: Black hole — gravity well (1/r slice) +level.50=Physics C: spring–mass SHM (Hooke's law, undamped) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/es.txt b/First Principles/Assets/Resources/Localization/es.txt index 99375f2..5596395 100644 --- a/First Principles/Assets/Resources/Localization/es.txt +++ b/First Principles/Assets/Resources/Localization/es.txt @@ -64,29 +64,28 @@ level.30=BC: fase y MAS (energía) level.31=BC: cúbica e inflexión (boceto) level.32=BC: b^x y d/dx b^x level.33=Círculo: (x−h)² + (y−k)² = R² -level.34=Aero: sustentación C_L(α) lineal + pérdida -level.35=Aero: polar de arrastre (parásita, inducida, total) -level.36=Aero: atmósfera isoterma ρ(h) -level.37=Aero: fugoide / cabeceo–heave amortiguado -level.38=Aero: newtoniano Cp ~ sin²α -level.39=Aero: Strouhal / tono de vórtices -level.40=Aero: envolvente de reentrada (calor ρV) -level.41=Economía: burbuja dotcom y crash (índice estilizado) -level.42=Economía: crisis 2008 y recuperación (índice estilizado) -level.43=JEFE: corte de escape Mandelbrot (fractal) -level.44=Física C: termodinámica (P–V adiabático, γ desde N) -level.45=JEFE: espiral áurea (polar logarítmica) -level.46=Transformadas: Fourier — sinc (espectro) -level.47=Transformadas: Laplace — decaimiento exponencial -level.48=JEFE: Mandelbrot — final (corte de escape fractal) -level.49=JEFE: atractor de Lorenz — teoría del caos (atractor extraño) -level.50=JEFE: agujero negro — pozo gravitatorio (corte 1/r) -level.51=Física C: resorte–masa SHM (ley de Hooke, sin amortiguación) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Física C: termodinámica (P–V adiabático, γ desde N) +level.35=Aero: sustentación C_L(α) lineal + pérdida +level.36=Aero: polar de arrastre (parásita, inducida, total) +level.37=Aero: atmósfera isoterma ρ(h) +level.38=Aero: fugoide / cabeceo–heave amortiguado +level.39=Aero: newtoniano Cp ~ sin²α +level.40=Aero: Strouhal / tono de vórtices +level.41=Aero: envolvente de reentrada (calor ρV) +level.42=Economía: burbuja dotcom y crash (índice estilizado) +level.43=Economía: crisis 2008 y recuperación (índice estilizado) +level.44=Transformadas: Fourier — sinc (espectro) +level.45=Transformadas: Laplace — decaimiento exponencial +level.46=JEFE: espiral áurea (polar logarítmica) +level.47=JEFE: Mandelbrot — final (corte de escape fractal) +level.48=JEFE: atractor de Lorenz — teoría del caos (atractor extraño) +level.49=JEFE: agujero negro — pozo gravitatorio (corte 1/r) +level.50=Física C: resorte–masa SHM (ley de Hooke, sin amortiguación) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/fr.txt b/First Principles/Assets/Resources/Localization/fr.txt index 1ef83a4..db0a8cd 100644 --- a/First Principles/Assets/Resources/Localization/fr.txt +++ b/First Principles/Assets/Resources/Localization/fr.txt @@ -64,29 +64,28 @@ level.30=BC : phase & MHS (échanges d’énergie) level.31=BC : cubique & inflexion (esquisse) level.32=BC : b^x & d/dx b^x level.33=Cercle : (x−h)² + (y−k)² = R² -level.34=Aéro : portance C_L(α) linéaire + décrochage -level.35=Aéro : polaire (traînée de profil, induite, totale) -level.36=Aéro : atmosphère isotherme ρ(h) -level.37=Aéro : phugoïde / oscillation amortie tangage–pilonnement -level.38=Aéro : newtonien Cp ~ sin²α -level.39=Aéro : Strouhal / tonalité tourbillonnaire -level.40=Aéro : enveloppe rentrée (échauffement ρV) -level.41=Éco : bulle internet & krach (indice stylisé) -level.42=Éco : crise 2008 & reprise (indice stylisé) -level.43=BOSS : tranche d’échappement Mandelbrot (fractale) -level.44=Physique C : thermodynamique (adiabatique P–V, γ depuis N) -level.45=BOSS : spirale d’or (polaire logarithmique) -level.46=Transformations : Fourier — sinc (spectre) -level.47=Transformations : Laplace — décroissance exponentielle -level.48=BOSS : Mandelbrot — finale (tranche d’échappement fractale) -level.49=BOSS : attracteur de Lorenz — théorie du chaos (attracteur étrange) -level.50=BOSS : trou noir — puits de gravité (tranche 1/r) -level.51=Physique C : ressort–masse SHM (loi de Hooke, non amorti) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Physique C : thermodynamique (adiabatique P–V, γ depuis N) +level.35=Aéro : portance C_L(α) linéaire + décrochage +level.36=Aéro : polaire (traînée de profil, induite, totale) +level.37=Aéro : atmosphère isotherme ρ(h) +level.38=Aéro : phugoïde / oscillation amortie tangage–pilonnement +level.39=Aéro : newtonien Cp ~ sin²α +level.40=Aéro : Strouhal / tonalité tourbillonnaire +level.41=Aéro : enveloppe rentrée (échauffement ρV) +level.42=Éco : bulle internet & krach (indice stylisé) +level.43=Éco : crise 2008 & reprise (indice stylisé) +level.44=Transformations : Fourier — sinc (spectre) +level.45=Transformations : Laplace — décroissance exponentielle +level.46=BOSS : spirale d’or (polaire logarithmique) +level.47=BOSS : Mandelbrot — finale (tranche d’échappement fractale) +level.48=BOSS : attracteur de Lorenz — théorie du chaos (attracteur étrange) +level.49=BOSS : trou noir — puits de gravité (tranche 1/r) +level.50=Physique C : ressort–masse SHM (loi de Hooke, non amorti) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/hi.txt b/First Principles/Assets/Resources/Localization/hi.txt index 160f050..5d54566 100644 --- a/First Principles/Assets/Resources/Localization/hi.txt +++ b/First Principles/Assets/Resources/Localization/hi.txt @@ -66,29 +66,28 @@ level.30=BC: कला व सरल हार्मोनिक गति level.31=BC: घन व प्रगाढ़ता (रेखाचित्र) level.32=BC: b^x व d/dx b^x level.33=वृत्त: (x−h)² + (y−k)² = R² -level.34=एयरोस्पेस: लिफ़्ट C_L(α) रैखिक + स्टॉल -level.35=एयरोस्पेस: ड्रैग पोलर (पैरासिटिक, प्रेरित, कुल) -level.36=एयरोस्पेस: समतापमान वायुमंडल ρ(h) -level.37=एयरोस्पेस: फ्यूगॉइड / डैम्प्ड पिच-हीव -level.38=एयरोस्पेस: न्यूटोनियन Cp ~ sin²α -level.39=एयरोस्पेस: स्ट्रौहल / वॉर्टेक्स शेडिंग -level.40=एयरोस्पेस: पुनः प्रवेश क्षय लिफ़ाफ़ा (ρV ताप मूड) -level.41=अर्थव्यवस्था: डॉट-कॉम बुलबुला व पतन (नमूना सूचकांक) -level.42=अर्थव्यवस्था: 2008 संकट व रिकवरी (नमूना सूचकांक) -level.43=BOSS: मैंडेलब्रॉट एस्केप स्लाइस (फ्रैक्टल) -level.44=भौतिकी C: ऊष्मागतिकी (एडियाबैटिक P–V, γ का मान N से) -level.45=BOSS: स्वर्ण अनुपात सर्पिल (लघुगणकीय ध्रुवीय) -level.46=रूपांतरण: फूरियर — सिंक स्पेक्ट्रम -level.47=रूपांतरण: लाप्लास — घातांकी क्षय -level.48=BOSS: मैंडेलब्रॉट — अंतिम (फ्रैक्टल एस्केप स्लाइस) -level.49=BOSS: लोरेंज आकर्षक — अराजकता सिद्धांत (विलक्षण आकर्षक) -level.50=BOSS: ब्लैक होल — गुरुत्वाकर्षण कुआँ (1/r स्लाइस) -level.51=फिजिक्स C: स्प्रिंग–द्रव्यमान SHM (हूक का नियम, अवमंदन रहित) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=भौतिकी C: ऊष्मागतिकी (एडियाबैटिक P–V, γ का मान N से) +level.35=एयरोस्पेस: लिफ़्ट C_L(α) रैखिक + स्टॉल +level.36=एयरोस्पेस: ड्रैग पोलर (पैरासिटिक, प्रेरित, कुल) +level.37=एयरोस्पेस: समतापमान वायुमंडल ρ(h) +level.38=एयरोस्पेस: फ्यूगॉइड / डैम्प्ड पिच-हीव +level.39=एयरोस्पेस: न्यूटोनियन Cp ~ sin²α +level.40=एयरोस्पेस: स्ट्रौहल / वॉर्टेक्स शेडिंग +level.41=एयरोस्पेस: पुनः प्रवेश क्षय लिफ़ाफ़ा (ρV ताप मूड) +level.42=अर्थव्यवस्था: डॉट-कॉम बुलबुला व पतन (नमूना सूचकांक) +level.43=अर्थव्यवस्था: 2008 संकट व रिकवरी (नमूना सूचकांक) +level.44=रूपांतरण: फूरियर — सिंक स्पेक्ट्रम +level.45=रूपांतरण: लाप्लास — घातांकी क्षय +level.46=BOSS: स्वर्ण अनुपात सर्पिल (लघुगणकीय ध्रुवीय) +level.47=BOSS: मैंडेलब्रॉट — अंतिम (फ्रैक्टल एस्केप स्लाइस) +level.48=BOSS: लोरेंज आकर्षक — अराजकता सिद्धांत (विलक्षण आकर्षक) +level.49=BOSS: ब्लैक होल — गुरुत्वाकर्षण कुआँ (1/r स्लाइस) +level.50=फिजिक्स C: स्प्रिंग–द्रव्यमान SHM (हूक का नियम, अवमंदन रहित) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/it.txt b/First Principles/Assets/Resources/Localization/it.txt index 5f28fa9..e4b78ea 100644 --- a/First Principles/Assets/Resources/Localization/it.txt +++ b/First Principles/Assets/Resources/Localization/it.txt @@ -7,7 +7,7 @@ level_select.cat.integration=Multivariabile e integrazione level_select.cat.engineering=Ingegneria level_select.cat.ap_bc=AP Calculus BC e Fisica C level_select.cat.aerospace=Aerospaziale -level_select.cat.finale=Avanzati e boss +level_select.cat.economics=Economia level_select.cat.transforms=Trasformate level_select.cat.final_boss=Boss finale level_select.cat.spring_physics=Molla e SHM @@ -85,29 +85,28 @@ level.30=BC: fase e moto armonico (scambio energia) level.31=BC: cubica e flesso (schizzo) level.32=BC: b^x e d/dx b^x level.33=Cerchio: (x−h)² + (y−k)² = R² -level.34=Aerospaziale: portanza C_L(α) lineare + stallo -level.35=Aerospaziale: polare di resistenza (parassita, indotta, totale) -level.36=Aerospaziale: atmosfera isoterma ρ(h) -level.37=Aerospaziale: fugoide / modo smorzato beccheggio‑altitudine -level.38=Aerospaziale: newtoniano Cp ~ sin²α -level.39=Aerospaziale: Strouhal / tono di scia vorticosa -level.40=Aerospaziale: inviluppo decadimento rientro (mood riscaldamento ρV) -level.41=Economia: bolla dot-com e crollo (indice stilizzato) -level.42=Economia: crisi 2008 e ripresa (indice stilizzato) -level.43=BOSS: sezione escape Mandelbrot (mood frattale) -level.44=Fisica C: termodinamica (P–V adiabatico, γ da N) -level.45=BOSS: spirale aurea (polare logaritmica) -level.46=Trasformate: Fourier — sinc (spettro) -level.47=Trasformate: Laplace — decadimento esponenziale -level.48=BOSS: Mandelbrot — finale (sezione escape frattale) -level.49=BOSS: attrattore di Lorenz — teoria del caos (attrattore strano) -level.50=BOSS: buco nero — pozzo gravitazionale (sezione 1/r) -level.51=Fisica C: molla–massa SHM (legge di Hooke, non smorzato) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Fisica C: termodinamica (P–V adiabatico, γ da N) +level.35=Aerospaziale: portanza C_L(α) lineare + stallo +level.36=Aerospaziale: polare di resistenza (parassita, indotta, totale) +level.37=Aerospaziale: atmosfera isoterma ρ(h) +level.38=Aerospaziale: fugoide / modo smorzato beccheggio‑altitudine +level.39=Aerospaziale: newtoniano Cp ~ sin²α +level.40=Aerospaziale: Strouhal / tono di scia vorticosa +level.41=Aerospaziale: inviluppo decadimento rientro (mood riscaldamento ρV) +level.42=Economia: bolla dot-com e crollo (indice stilizzato) +level.43=Economia: crisi 2008 e ripresa (indice stilizzato) +level.44=Trasformate: Fourier — sinc (spettro) +level.45=Trasformate: Laplace — decadimento esponenziale +level.46=BOSS: spirale aurea (polare logaritmica) +level.47=BOSS: Mandelbrot — finale (sezione escape frattale) +level.48=BOSS: attrattore di Lorenz — teoria del caos (attrattore strano) +level.49=BOSS: buco nero — pozzo gravitazionale (sezione 1/r) +level.50=Fisica C: molla–massa SHM (legge di Hooke, non smorzato) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ja.txt b/First Principles/Assets/Resources/Localization/ja.txt index f1d219c..734ddd9 100644 --- a/First Principles/Assets/Resources/Localization/ja.txt +++ b/First Principles/Assets/Resources/Localization/ja.txt @@ -64,29 +64,28 @@ level.30=BC:位相と単振動(エネルギー) level.31=BC:三次関数と変曲点(スケッチ) level.32=BC:b^x と d/dx b^x level.33=円:(x−h)² + (y−k)² = R² -level.34=航空:揚力C_L(α) 線形+失速 -level.35=航空:抗力極曲線(プロファイル·誘導·合計) -level.36=航空:等温大気 ρ(h) -level.37=航空:フゴイド/減衰ピッチ・上下動 -level.38=航空:ニュートン流 Cp ~ sin²α -level.39=航空:ストルーハル/渦放出音 -level.40=航空:再突入減衰包絡線(ρV加熱) -level.41=経済:ドットコムバブルと暴落(模式化インデックス) -level.42=経済:2008年危機と回復(模式化インデックス) -level.43=BOSS:マンデルブロ脱出断面(フラクタル) -level.44=物理C:熱力学(断熱P–V、γはNから) -level.45=BOSS:黄金螺旋(対数・極座標) -level.46=変換:フーリエ — sincスペクトラム -level.47=変換:ラプラス — 指数減衰 -level.48=BOSS:マンデルブロ — フィナーレ(フラクタル脱出断面) -level.49=BOSS:ローレンツアトラクター — カオス理論(ストレンジアトラクター) -level.50=BOSS:ブラックホール — 重力の井戸(1/r 断面) -level.51=物理C:ばね–質点の単振動(フックの法則、減衰なし) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=物理C:熱力学(断熱P–V、γはNから) +level.35=航空:揚力C_L(α) 線形+失速 +level.36=航空:抗力極曲線(プロファイル·誘導·合計) +level.37=航空:等温大気 ρ(h) +level.38=航空:フゴイド/減衰ピッチ・上下動 +level.39=航空:ニュートン流 Cp ~ sin²α +level.40=航空:ストルーハル/渦放出音 +level.41=航空:再突入減衰包絡線(ρV加熱) +level.42=経済:ドットコムバブルと暴落(模式化インデックス) +level.43=経済:2008年危機と回復(模式化インデックス) +level.44=変換:フーリエ — sincスペクトラム +level.45=変換:ラプラス — 指数減衰 +level.46=BOSS:黄金螺旋(対数・極座標) +level.47=BOSS:マンデルブロ — フィナーレ(フラクタル脱出断面) +level.48=BOSS:ローレンツアトラクター — カオス理論(ストレンジアトラクター) +level.49=BOSS:ブラックホール — 重力の井戸(1/r 断面) +level.50=物理C:ばね–質点の単振動(フックの法則、減衰なし) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ko.txt b/First Principles/Assets/Resources/Localization/ko.txt index ae8ee1b..fb1d3f4 100644 --- a/First Principles/Assets/Resources/Localization/ko.txt +++ b/First Principles/Assets/Resources/Localization/ko.txt @@ -13,7 +13,7 @@ level_select.cat.integration=다변수 & 적분 level_select.cat.engineering=공학 level_select.cat.ap_bc=AP 미적분 BC · 물리 C level_select.cat.aerospace=항공우주 -level_select.cat.finale=심화 & 보스 +level_select.cat.economics=경제 level_select.cat.transforms=변환 level_select.cat.final_boss=최종 보스 level_select.cat.spring_physics=스프링·단진동 @@ -83,29 +83,28 @@ level.30=BC: 위상과 단진동 (에너지) level.31=BC: 삼차함수와 변곡점 (스케치) level.32=BC: b^x와 d/dx b^x level.33=원: (x−h)² + (y−k)² = R² -level.34=항공: 양력 C_L(α) 선형 및 실속 -level.35=항공: 항력 극곡선 (패러사이틱·유도·합) -level.36=항공: 등온 대기 ρ(h) -level.37=항공: 퓨고이드 / 감쇠 피치-헤이브 -level.38=항공: 뉴턴 Cp ~ sin²α -level.39=항공: 스트루할 / 와류 방출 음 -level.40=항공: 재진입 감쇠 포락선 (ρV 가열) -level.41=경제: 닷컴 버블·붕괴 (스타일화 지수) -level.42=경제: 2008 위기·회복 (스타일화 지수) -level.43=보스: 만델브로 탈출 단면 (프랙탈) -level.44=물리 C: 열역학 (단열 P–V, γ는 N에서) -level.45=보스: 황금비 나선 (로그 극좌표) -level.46=변환: 푸리에 — sinc 스펙트럼 -level.47=변환: 라플라스 — 지수 감쇠 -level.48=보스: 만델브로 — 피날레 (프랙탈 탈출 단면) -level.49=보스: 로렌츠 어트랙터 — 카오스 이론 (이상한 끌개) -level.50=보스: 블랙홀 — 중력 우물 (1/r 단면) -level.51=물리 C: 스프링–질점 SHM (훅의 법칙, 비감쇠) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=물리 C: 열역학 (단열 P–V, γ는 N에서) +level.35=항공: 양력 C_L(α) 선형 및 실속 +level.36=항공: 항력 극곡선 (패러사이틱·유도·합) +level.37=항공: 등온 대기 ρ(h) +level.38=항공: 퓨고이드 / 감쇠 피치-헤이브 +level.39=항공: 뉴턴 Cp ~ sin²α +level.40=항공: 스트루할 / 와류 방출 음 +level.41=항공: 재진입 감쇠 포락선 (ρV 가열) +level.42=경제: 닷컴 버블·붕괴 (스타일화 지수) +level.43=경제: 2008 위기·회복 (스타일화 지수) +level.44=변환: 푸리에 — sinc 스펙트럼 +level.45=변환: 라플라스 — 지수 감쇠 +level.46=보스: 황금비 나선 (로그 극좌표) +level.47=보스: 만델브로 — 피날레 (프랙탈 탈출 단면) +level.48=보스: 로렌츠 어트랙터 — 카오스 이론 (이상한 끌개) +level.49=보스: 블랙홀 — 중력 우물 (1/r 단면) +level.50=물리 C: 스프링–질점 SHM (훅의 법칙, 비감쇠) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/pl.txt b/First Principles/Assets/Resources/Localization/pl.txt index 9f9def5..ce6396f 100644 --- a/First Principles/Assets/Resources/Localization/pl.txt +++ b/First Principles/Assets/Resources/Localization/pl.txt @@ -7,7 +7,7 @@ level_select.cat.integration=Zmienne wielowymiarowe i całki level_select.cat.engineering=Inżynieria level_select.cat.ap_bc=AP Calculus BC i Fizyka C level_select.cat.aerospace=Lotnictwo i kosmonautyka -level_select.cat.finale=Zaawansowane i boss +level_select.cat.economics=Ekonomia level_select.cat.transforms=Transformaty level_select.cat.final_boss=Finałowy boss level_select.cat.spring_physics=Sprężyna i SHM @@ -85,29 +85,28 @@ level.30=BC: faza i drgania harmoniczne (wymiana energii) level.31=BC: sześcienny i punkt przegięcia level.32=BC: b^x i d/dx b^x level.33=Okrąg: (x−h)² + (y−k)² = R² -level.34=Aerospace: siła nośna C_L(α) liniowa + przeciągnięcie -level.35=Aerospace: polara oporu (pasożytniczy, indukowany, całkowity) -level.36=Aerospace: atmosfera izotermiczna ρ(h) -level.37=Aerospace: fugoide / stłumiony tryb przechylenia -level.38=Aerospace: newtonowskie Cp ~ sin²α -level.39=Aerospace: Strouhal / ton wirów -level.40=Aerospace: obwiednia zaniku przy wejściu (ρV ciepło) -level.41=Ekonomia: bańka dot-com i krach (stylizowany indeks) -level.42=Ekonomia: kryzys 2008 i odbicie (stylizowany indeks) -level.43=BOSS: przekrój ucieczki Mandelbrota (nastrój fraktalny) -level.44=Fizyka C: termodynamika (adiabatyczny P–V, γ z N) -level.45=BOSS: spirala złotego podziału (logarytmiczna, biegunowa) -level.46=Transformaty: Fourier — sinc (widmo) -level.47=Transformaty: Laplace — wykładniczy zanik -level.48=BOSS: Mandelbrot — finał (fraktalny przekrój ucieczki) -level.49=BOSS: atraktor Lorenza — teoria chaosu (dziwny atraktor) -level.50=BOSS: czarna dziura — studnia grawitacji (przekrój 1/r) -level.51=Fizyka C: sprężyna–masa SHM (prawo Hooka, nietłumione) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Fizyka C: termodynamika (adiabatyczny P–V, γ z N) +level.35=Aerospace: siła nośna C_L(α) liniowa + przeciągnięcie +level.36=Aerospace: polara oporu (pasożytniczy, indukowany, całkowity) +level.37=Aerospace: atmosfera izotermiczna ρ(h) +level.38=Aerospace: fugoide / stłumiony tryb przechylenia +level.39=Aerospace: newtonowskie Cp ~ sin²α +level.40=Aerospace: Strouhal / ton wirów +level.41=Aerospace: obwiednia zaniku przy wejściu (ρV ciepło) +level.42=Ekonomia: bańka dot-com i krach (stylizowany indeks) +level.43=Ekonomia: kryzys 2008 i odbicie (stylizowany indeks) +level.44=Transformaty: Fourier — sinc (widmo) +level.45=Transformaty: Laplace — wykładniczy zanik +level.46=BOSS: spirala złotego podziału (logarytmiczna, biegunowa) +level.47=BOSS: Mandelbrot — finał (fraktalny przekrój ucieczki) +level.48=BOSS: atraktor Lorenza — teoria chaosu (dziwny atraktor) +level.49=BOSS: czarna dziura — studnia grawitacji (przekrój 1/r) +level.50=Fizyka C: sprężyna–masa SHM (prawo Hooka, nietłumione) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ru.txt b/First Principles/Assets/Resources/Localization/ru.txt index 0201b7b..a04cf9e 100644 --- a/First Principles/Assets/Resources/Localization/ru.txt +++ b/First Principles/Assets/Resources/Localization/ru.txt @@ -7,7 +7,7 @@ level_select.cat.integration=Многие переменные и интегра level_select.cat.engineering=Инженерия level_select.cat.ap_bc=AP Calculus BC и физика C level_select.cat.aerospace=Аэрокосмос -level_select.cat.finale=Сложные и босс +level_select.cat.economics=Экономика level_select.cat.transforms=Преобразования level_select.cat.final_boss=Финальный босс level_select.cat.spring_physics=Пружина и ГС @@ -85,29 +85,28 @@ level.30=BC: фаза и гармонические колебания level.31=BC: кубическая и точка перегиба level.32=BC: b^x и d/dx b^x level.33=Окружность: (x−h)² + (y−k)² = R² -level.34=Aerospace: подъёмная сила C_L(α) линейно + срыв -level.35=Aerospace: поляра сопротивления (паразит., индукт., суммарн.) -level.36=Aerospace: изотерм. атмосфера ρ(h) -level.37=Aerospace: фюгоид / затух. тангаж-высота -level.38=Aerospace: ньютоновское Cp ~ sin²α -level.39=Aerospace: Струхал / тон вихревой дорожки -level.40=Aerospace: оболочка затухания при входе (ρV тепло) -level.41=Экономика: пузырь dot-com и крах (стилиз. индекс) -level.42=Экономика: кризис 2008 и восстановление (стилиз. индекс) -level.43=БОСС: сечение убегания Мандельброта (фрактал) -level.44=Физика C: термодинамика (адиабата P–V, γ из N) -level.45=БОСС: золотая спираль (логарифмическая, полярная) -level.46=Преобразования: Фурье — sinc-спектр -level.47=Преобразования: Лаплас — затухание -level.48=БОСС: Мандельброт — финал (фрактальный срез побега) -level.49=БОСС: аттрактор Лоренца — теория хаоса (странный аттрактор) -level.50=БОСС: чёрная дыра — гравитационная яма (сечение 1/r) -level.51=Физика C: пружина–масса ГС (закон Гука, без затухания) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=Физика C: термодинамика (адиабата P–V, γ из N) +level.35=Aerospace: подъёмная сила C_L(α) линейно + срыв +level.36=Aerospace: поляра сопротивления (паразит., индукт., суммарн.) +level.37=Aerospace: изотерм. атмосфера ρ(h) +level.38=Aerospace: фюгоид / затух. тангаж-высота +level.39=Aerospace: ньютоновское Cp ~ sin²α +level.40=Aerospace: Струхал / тон вихревой дорожки +level.41=Aerospace: оболочка затухания при входе (ρV тепло) +level.42=Экономика: пузырь dot-com и крах (стилиз. индекс) +level.43=Экономика: кризис 2008 и восстановление (стилиз. индекс) +level.44=Преобразования: Фурье — sinc-спектр +level.45=Преобразования: Лаплас — затухание +level.46=БОСС: золотая спираль (логарифмическая, полярная) +level.47=БОСС: Мандельброт — финал (фрактальный срез побега) +level.48=БОСС: аттрактор Лоренца — теория хаоса (странный аттрактор) +level.49=БОСС: чёрная дыра — гравитационная яма (сечение 1/r) +level.50=Физика C: пружина–масса ГС (закон Гука, без затухания) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/ur.txt b/First Principles/Assets/Resources/Localization/ur.txt index f7651c9..a884411 100644 --- a/First Principles/Assets/Resources/Localization/ur.txt +++ b/First Principles/Assets/Resources/Localization/ur.txt @@ -66,29 +66,28 @@ level.30=BC: مرحلہ اور SHM level.31=BC: مکعب اور انفلیکشن level.32=BC: b^x و d/dx b^x level.33=دائرہ: (x−h)² + (y−k)² = R² -level.34=ایرواسپیس: لفٹ C_L(α) + اسٹال -level.35=ایرواسپیس: ڈریگ پولر (پیراسٹک، انڈیوسڈ، کل) -level.36=ایرواسپیس: ہمحرارتی فضا ρ(h) -level.37=ایرواسپیس: فیگوئڈ / ڈیمپڈ موڈ -level.38=ایرواسپیس: نیوٹنی Cp ~ sin²α -level.39=ایرواسپیس: اسٹروہل / وورٹیکس شیڈنگ -level.40=ایرواسپیس: دوبارہ دخول زوال -level.41=معیشت: ڈاٹ کام ببل اور حادثہ (اسٹائل شدہ انڈیکس) -level.42=معیشت: 2008 بحران اور بحالی (اسٹائل شدہ انڈیکس) -level.43=بوس: مینڈلبرو فرکٹل سلائس -level.44=فزکس C: تھرموڈائنانمکس (ایڈیابیٹک P–V، γ از N) -level.45=بوس: سنہری تناسب سنئلی (لوگ قطبی) -level.46=تبدیل: فوریے — سینک سپیکٹرم -level.47=تبدیل: لاپلاس — نماتی زوال -level.48=بوس: مینڈلبرو — اختتام (فرکٹل فرار سلائس) -level.49=بوس: لورینز اٹریکٹر — کیس تھیوری (عجیب اٹریکٹر) -level.50=باس: بلیک ہول — کشش ثقل کنواں (1/r سلائس) -level.51=فزکس C: سپرنگ–عنصر جرم SHM (ہوک کا قانون، ڈیمپنگ کے بغیر) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=فزکس C: تھرموڈائنانمکس (ایڈیابیٹک P–V، γ از N) +level.35=ایرواسپیس: لفٹ C_L(α) + اسٹال +level.36=ایرواسپیس: ڈریگ پولر (پیراسٹک، انڈیوسڈ، کل) +level.37=ایرواسپیس: ہمحرارتی فضا ρ(h) +level.38=ایرواسپیس: فیگوئڈ / ڈیمپڈ موڈ +level.39=ایرواسپیس: نیوٹنی Cp ~ sin²α +level.40=ایرواسپیس: اسٹروہل / وورٹیکس شیڈنگ +level.41=ایرواسپیس: دوبارہ دخول زوال +level.42=معیشت: ڈاٹ کام ببل اور حادثہ (اسٹائل شدہ انڈیکس) +level.43=معیشت: 2008 بحران اور بحالی (اسٹائل شدہ انڈیکس) +level.44=تبدیل: فوریے — سینک سپیکٹرم +level.45=تبدیل: لاپلاس — نماتی زوال +level.46=بوس: سنہری تناسب سنئلی (لوگ قطبی) +level.47=بوس: مینڈلبرو — اختتام (فرکٹل فرار سلائس) +level.48=بوس: لورینز اٹریکٹر — کیس تھیوری (عجیب اٹریکٹر) +level.49=باس: بلیک ہول — کشش ثقل کنواں (1/r سلائس) +level.50=فزکس C: سپرنگ–عنصر جرم SHM (ہوک کا قانون، ڈیمپنگ کے بغیر) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/Localization/zh.txt b/First Principles/Assets/Resources/Localization/zh.txt index 08e3fbf..c3a7bce 100644 --- a/First Principles/Assets/Resources/Localization/zh.txt +++ b/First Principles/Assets/Resources/Localization/zh.txt @@ -64,29 +64,28 @@ level.30=BC:相位与简谐振动(能量) level.31=BC:三次与拐点(作图) level.32=BC:b^x 与 d/dx b^x level.33=圆:(x−h)² + (y−k)² = R² -level.34=航空:升力 C_L(α) 线性+失速 -level.35=航空:阻力极曲线(型阻·诱导·总阻) -level.36=航空:等温大气 ρ(h) -level.37=航空:起伏运动 / 阻尼俯仰-沉浮 -level.38=航空:牛顿流 Cp ~ sin²α -level.39=航空:斯特劳哈尔 / 涡脱落音 -level.40=航空:再入衰减包络(ρV 加热) -level.41=经济:互联网泡沫与崩盘(示意指数曲线) -level.42=经济:2008 危机与复苏(示意指数曲线) -level.43=BOSS:曼德博逃逸截面(分形) -level.44=物理C:热力学(绝热P–V,γ由N给出) -level.45=BOSS:黄金比例螺旋(对数极坐标) -level.46=变换:傅里叶 — sinc 频谱 -level.47=变换:拉普拉斯 — 指数衰减 -level.48=BOSS:曼德博 — 终章(分形逃逸截面) -level.49=BOSS:洛伦兹吸引子 — 混沌理论(奇异吸引子) -level.50=BOSS:黑洞 — 引力势阱(1/r 切片) -level.51=物理C:弹簧–质点简谐振动(胡克定律,无阻尼) -level.52=Big O: O(1) — constant time -level.53=Big O: O(log n) — logarithmic growth -level.54=Big O: O(√n) — sublinear root growth -level.55=Big O: O(n) — linear growth -level.56=Big O: O(n log n) — n log n growth -level.57=Big O: O(n²) — quadratic growth -level.58=Big O: O(n³) — cubic growth -level.59=Big O: O(2ⁿ) — exponential (base 2) +level.34=物理C:热力学(绝热P–V,γ由N给出) +level.35=航空:升力 C_L(α) 线性+失速 +level.36=航空:阻力极曲线(型阻·诱导·总阻) +level.37=航空:等温大气 ρ(h) +level.38=航空:起伏运动 / 阻尼俯仰-沉浮 +level.39=航空:牛顿流 Cp ~ sin²α +level.40=航空:斯特劳哈尔 / 涡脱落音 +level.41=航空:再入衰减包络(ρV 加热) +level.42=经济:互联网泡沫与崩盘(示意指数曲线) +level.43=经济:2008 危机与复苏(示意指数曲线) +level.44=变换:傅里叶 — sinc 频谱 +level.45=变换:拉普拉斯 — 指数衰减 +level.46=BOSS:黄金比例螺旋(对数极坐标) +level.47=BOSS:曼德博 — 终章(分形逃逸截面) +level.48=BOSS:洛伦兹吸引子 — 混沌理论(奇异吸引子) +level.49=BOSS:黑洞 — 引力势阱(1/r 切片) +level.50=物理C:弹簧–质点简谐振动(胡克定律,无阻尼) +level.51=Big O: O(1) — constant time +level.52=Big O: O(log n) — logarithmic growth +level.53=Big O: O(√n) — sublinear root growth +level.54=Big O: O(n) — linear growth +level.55=Big O: O(n log n) — n log n growth +level.56=Big O: O(n²) — quadratic growth +level.57=Big O: O(n³) — cubic growth +level.58=Big O: O(2ⁿ) — exponential (base 2) diff --git a/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader new file mode 100644 index 0000000..0639d9f --- /dev/null +++ b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader @@ -0,0 +1,121 @@ +// Procedural logarithmic spiral mood (golden ratio boss): φ-growth arms in polar view, +// warm gold on deep field — matches r ∝ φ^{kθ} teaching language on the stage. +Shader "UI/GoldenSpiralBackdrop" +{ + Properties + { + [PerRendererData] _MainTex ("Dummy", 2D) = "white" {} + _Color ("Tint & alpha", Color) = (1, 0.85, 0.45, 0.48) + _Aspect ("UV width / height", Float) = 1.7 + _TimeLive ("Time", Float) = 0 + } + + SubShader + { + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + ZWrite Off + ZTest Always + Blend SrcAlpha OneMinusSrcAlpha + Cull Off + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + sampler2D _MainTex; + float4 _MainTex_ST; + float4 _Color; + float _Aspect; + float _TimeLive; + + struct appdata + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float4 color : COLOR; + float2 uv : TEXCOORD0; + }; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.color = v.color; + o.uv = v.texcoord; + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + float2 uv = i.uv; + float asp = max(_Aspect, 0.25); + float2 p = (uv - 0.5) * 2.0; + p.x *= asp; + + float r = length(p); + float ang = atan2(p.y, p.x); + + // Golden ratio φ; log-spiral with one arm per 2π matches r ∝ φ^{θ/(2π)}. + float phi = 1.618033988749; + float twoPi = 6.28318530718; + float b = log(phi) / twoPi; + + float t = _TimeLive * 0.22; + + float phase1 = log(r + 0.07) - b * ang; + float spiral1 = abs(frac(phase1 * 2.15 + t * 0.045) - 0.5); + + float phase2 = log(r + 0.09) - b * (ang + 2.399963); // ~ golden angle + float spiral2 = abs(frac(phase2 * 2.15 - t * 0.032) - 0.5); + + float phase3 = log(r + 0.05) - b * (-ang + 0.73); + float spiral3 = abs(frac(phase3 * 1.85 + t * 0.028) - 0.5); + + float arms = + smoothstep(0.13, 0.0, spiral1) + + smoothstep(0.13, 0.0, spiral2) * 0.72 + + smoothstep(0.11, 0.0, spiral3) * 0.45; + + float radPhase = log(r + 0.04) / log(phi) * 2.8 + t * 0.06; + float rings = smoothstep(0.09, 0.0, abs(frac(radPhase) - 0.5)) * 0.35; + + float vign = smoothstep(1.55, 0.28, r); + float core = smoothstep(0.02, 0.14, r); + + float3 bgDeep = float3(0.05, 0.04, 0.1); + float3 bgWarm = float3(0.12, 0.07, 0.04); + float3 baseCol = lerp(bgDeep, bgWarm, saturate(r * 0.35 + uv.y * 0.25)); + + float3 goldHi = float3(1.0, 0.9, 0.42); + float3 goldMid = float3(0.92, 0.62, 0.22); + float3 glow = lerp(goldMid, goldHi, arms * 0.65 + rings * 0.4); + + float intensity = (arms * 0.62 + rings * 0.28) * vign * (0.35 + 0.65 * core); + float3 col = baseCol + glow * intensity; + + col = saturate(col); + float a = _Color.a * i.color.a; + return fixed4(col * _Color.rgb * i.color.rgb, a); + } + ENDCG + } + } + FallBack Off +} diff --git a/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta new file mode 100644 index 0000000..b39048b --- /dev/null +++ b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a8e3c91d4f2b4069b7c5d8e1f3a2940b +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader new file mode 100644 index 0000000..70dd08c --- /dev/null +++ b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader @@ -0,0 +1,156 @@ +// Procedural wind-tunnel mood (aerospace stages): left→right freestream, +// smoke/schlieren streaks, faint test-section grid, subtle symmetric airfoil silhouette. +Shader "UI/WindTunnelBackdrop" +{ + Properties + { + [PerRendererData] _MainTex ("Dummy", 2D) = "white" {} + _Color ("Tint & alpha", Color) = (0.9, 0.96, 1, 0.54) + _FlowSpeed ("Flow speed", Float) = 0.55 + _StreakScale ("Streak scale", Float) = 9 + _Aspect ("UV width / height", Float) = 1.7 + } + + SubShader + { + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + ZWrite Off + ZTest Always + Blend SrcAlpha OneMinusSrcAlpha + Cull Off + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + sampler2D _MainTex; + float4 _MainTex_ST; + float4 _Color; + float _FlowSpeed; + float _StreakScale; + float _Aspect; + + struct appdata + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float4 color : COLOR; + float2 uv : TEXCOORD0; + }; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.color = v.color; + o.uv = v.texcoord; + return o; + } + + float hash21(float2 p) + { + float h = dot(p, float2(127.1, 311.7)); + return frac(sin(h) * 43758.5453123); + } + + float noise2(float2 p) + { + float2 i = floor(p); + float2 f = frac(p); + f = f * f * (3.0 - 2.0 * f); + float a = hash21(i); + float b = hash21(i + float2(1, 0)); + float c = hash21(i + float2(0, 1)); + float d = hash21(i + float2(1, 1)); + return lerp(lerp(a, b, f.x), lerp(c, d, f.x), f.y); + } + + float fbm(float2 p) + { + float s = 0.0; + float a = 0.5; + for (int k = 0; k < 5; k++) + { + s += a * noise2(p); + p *= 2.02; + a *= 0.5; + } + return s; + } + + // Thin symmetric airfoil thickness (teaching shape): y_t(x) ~ semi-ellipse chord. + float airfoilThickness(float xNorm) + { + xNorm = abs(xNorm); + if (xNorm >= 1.0) + return 0.0; + return 0.18 * sqrt(1.0 - xNorm * xNorm); + } + + fixed4 frag(v2f i) : SV_Target + { + float2 uv = i.uv; + float t = _Time.y * _FlowSpeed; + float asp = max(_Aspect, 0.25); + + float2 p = (uv - 0.5) * 2.0; + p.x *= asp; + + // Freestream along +x (wind enters from left of screen). + float2 flow = float2(uv.x * asp * _StreakScale * 0.35 + t * 0.9, uv.y * _StreakScale * 0.55); + float sm = fbm(flow); + float sm2 = fbm(flow * 1.6 + float2(3.1, -t * 0.4)); + + // Streaks: elongated along x. + float streak = pow(sm * sm2, 1.4); + streak *= smoothstep(0.15, 0.55, streak); + + // Wake wobble behind nominal chord (x in p space ~ -0.2 to 0.5). + float chordX = p.x / 0.62; + float yt = airfoilThickness(chordX); + float distWing = abs(p.y) - yt; + float wingMask = 1.0 - smoothstep(-0.02, 0.06, distWing); + float wake = smoothstep(0.05, 0.45, p.x) * exp(-abs(p.y) * 2.2) * (1.0 - smoothstep(-0.35, 0.55, p.x)); + + float turbWake = fbm(float2(p.x * 4.0 - t * 1.2, p.y * 8.0 + sin(p.x * 6.0 + t))) * wake * 0.55; + + // Test-section vertical rails (window frames). + float rail = smoothstep(0.02, 0.0, abs(uv.x - 0.08)) + smoothstep(0.02, 0.0, abs(uv.x - 0.92)); + rail *= 0.15; + + // Cool tunnel base gradient (floor darker) — slightly lifted for readability. + float3 baseCol = lerp(float3(0.06, 0.1, 0.15), float3(0.13, 0.18, 0.26), uv.y); + baseCol += float3(0.08, 0.12, 0.17) * (1.0 - uv.y) * rail; + + float3 mist = float3(0.58, 0.76, 0.98) * streak * 0.72; + mist += float3(0.5, 0.66, 0.92) * turbWake * 1.12; + mist += float3(0.32, 0.42, 0.58) * wingMask * 0.16; + + float3 col = baseCol + mist; + col = saturate(col); + + float a = _Color.a * i.color.a; + return fixed4(col * _Color.rgb * i.color.rgb, a); + } + ENDCG + } + } + FallBack Off +} diff --git a/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta new file mode 100644 index 0000000..2fb8240 --- /dev/null +++ b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6426e7063d26b4ffbb3950a79360b1cc +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs index f8606d0..a239003 100644 --- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs +++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs @@ -47,6 +47,9 @@ public class FunctionPlotter : MonoBehaviour public bool differentiate = false; + [Tooltip("Level mode: wind-tunnel GPU backdrop (set from LevelDefinition for aerospace stages).")] + public bool showWindTunnelBackdrop = false; + [Tooltip("Level mode: vertically scale f and f′ so the band fits the grid (flat curves read clearly).")] public bool autoScaleVertical = true; @@ -393,12 +396,14 @@ private void PlotFunction(FunctionType type) } } - // Boss backdrops: Mandelbrot c-plane; Schwarzschild-style black hole (GPU shader). + // Stage backdrops: Mandelbrot; black hole; golden φ-spiral; wind tunnel (aerospace). if (lineRenderer != null) { var gridRt = lineRenderer.transform.parent as RectTransform; MandelbrotFractalBackdrop.Sync(gridRt, this); BlackHoleGargantuaBackdrop.Sync(gridRt, this); + GoldenSpiralBackdrop.Sync(gridRt, this); + WindTunnelBackdrop.Sync(gridRt, this); PushGraphRevealToRenderers(); } } diff --git a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs index 06784b2..2364c05 100644 --- a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs +++ b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs @@ -69,6 +69,7 @@ public static class GameLevelCatalog "BC: cubic & inflection (sketching)", "BC: b^x & d/dx b^x", "Circle: (x−h)² + (y−k)² = R²", + "Physics C: thermodynamics (adiabatic P–V, γ from N)", // --- Aerospace engineering & aerodynamics (order must match LevelManager.BuildSampleLevels) --- "Aerospace: lift C_L(α) linear + stall", "Aerospace: drag polar (parasitic, induced, total)", @@ -79,11 +80,9 @@ public static class GameLevelCatalog "Aerospace: re-entry decay envelope (ρV heating mood)", "Economics: dot-com bubble & crash (stylized index)", "Economics: 2008 crisis & recovery (stylized index)", - "BOSS: Mandelbrot escape slice (fractal boundary mood)", - "Physics C: thermodynamics (adiabatic P–V, γ from N)", - "BOSS: golden ratio spiral (logarithmic polar)", "Transforms: Fourier — sinc spectrum (rect ↔ sinc)", "Transforms: Laplace — causal exponential decay", + "BOSS: golden ratio spiral (logarithmic polar)", "BOSS: Mandelbrot — finale (fractal escape slice)", "BOSS: Lorenz attractor — Chaos Theory (strange attractor)", "BOSS: Black hole — gravity well (1/r slice)", @@ -108,20 +107,20 @@ public static class GameLevelCatalog new LevelSelectCategory("level_select.cat.core", "Core & series", 0, 8), new LevelSelectCategory("level_select.cat.integration", "Multivar & integration", 9, 13), new LevelSelectCategory("level_select.cat.engineering", "Engineering", 14, 16), - new LevelSelectCategory("level_select.cat.ap_bc", "AP Calculus BC & Physics C", 17, 33), - new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 34, 40), - new LevelSelectCategory("level_select.cat.finale", "Advanced & boss", 41, 45), - new LevelSelectCategory("level_select.cat.transforms", "Transforms", 46, 47), - new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 51, 51), - new LevelSelectCategory("level_select.cat.big_o", "Big O notation", 52, 59), - new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 48, 50), + new LevelSelectCategory("level_select.cat.ap_bc", "AP Calculus BC & Physics C", 17, 34), + new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 35, 41), + new LevelSelectCategory("level_select.cat.economics", "Economics", 42, 43), + new LevelSelectCategory("level_select.cat.transforms", "Transforms", 44, 45), + new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 50, 50), + new LevelSelectCategory("level_select.cat.big_o", "Big O notation", 51, 58), + new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 46, 49), }; /// First index of the contiguous Aerospace: block (must match sample levels). - public const int AerospaceLevelsBeginIndex = 34; + public const int AerospaceLevelsBeginIndex = 35; /// Inclusive last index of the Aerospace block (re-entry stage). - public const int AerospaceLevelsEndIndex = 40; + public const int AerospaceLevelsEndIndex = 41; /// True for levels whose titles start with Aerospace: in the catalog. public static bool IsAerospaceLevel(int index) => diff --git a/First Principles/Assets/Scripts/Game/LevelDefinition.cs b/First Principles/Assets/Scripts/Game/LevelDefinition.cs index aeef65f..398c104 100644 --- a/First Principles/Assets/Scripts/Game/LevelDefinition.cs +++ b/First Principles/Assets/Scripts/Game/LevelDefinition.cs @@ -88,6 +88,9 @@ public class LevelDefinition : ScriptableObject [Tooltip("Tint the background grid to match this level’s mood.")] public bool applyGridTheming = false; + [Tooltip("GPU wind-tunnel / schlieren backdrop (aerospace category).")] + public bool showWindTunnelBackdrop = false; + public Color gridCenterLineTheming = new Color(1f, 1f, 1f, 0.39f); public Color gridOutsideLineTheming = new Color(1f, 1f, 1f, 0.14f); diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 6cb9045..04627a8 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -469,6 +469,7 @@ private void EnterGraphCalculatorMode() functionPlotter.autoScaleVertical = false; // Stretch [xStart,xEnd] across the grid so pinch / Scale update _autoMidX/_autoScaleX; axis ticks track (LabelManager). functionPlotter.autoScaleHorizontal = true; + functionPlotter.showWindTunnelBackdrop = false; if (curveRenderer != null) { @@ -1919,10 +1920,35 @@ private void BuildSampleLevels() storyPauseSecondsOverride: 2.65f )); - // ---- Aerospace engineering & aerodynamics (indices 34–40) ----------------------------- - levels.Add(MakeLevel( GameLevelCatalog.DisplayNames[34], + FunctionType.ThermoAdiabaticPV, + curveColor: new Color(0.98f, 0.52f, 0.28f, 1f), + derivativeColor: new Color(0.45f, 0.82f, 0.98f, 1f), + transA: 9.5f, + transK: 0.38f, + transC: -2.35f, + transD: -16f, + power: 2, + baseN: 140, + story: + "Thermodynamics — reversible adiabatic path — for an ideal gas, quasi-static adiabats obey PVγ = constant (no heat exchange, work comes only from internal energy bookkeeping).\n\n" + + "Here the horizontal walk is a scaled “volume-like” coordinate; height tracks pressure mood as P ∝ V−γ. We set N = 140 so γ ≈ 1.40 — a familiar air/diatomic story problem vibe, not a lab instrument.\n\n" + + "Teaching sketch only: real pistons have losses, gradients, and non-equilibrium corners — but the slope story you feel underfoot is still γ.", + derivativePopTriggerCountOverride: 4, + applyGridTheming: true, + gridCenter: new Color(0.38f, 0.18f, 0.1f, 0.36f), + gridOutside: new Color(0.22f, 0.1f, 0.06f, 0.1f), + storyPauseSecondsOverride: 2.85f, + graphStep: 0.11f, + levelXStart: -14f, + levelXEnd: 14f + )); + + // ---- Aerospace engineering & aerodynamics (indices 35–41) ----------------------------- + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[35], FunctionType.AeroLiftVsAlpha, curveColor: new Color(0.35f, 0.72f, 1f, 1f), derivativeColor: new Color(1f, 0.58f, 0.3f, 1f), @@ -1940,7 +1966,8 @@ private void BuildSampleLevels() applyGridTheming: true, gridCenter: new Color(0.16f, 0.32f, 0.48f, 0.37f), gridOutside: new Color(0.12f, 0.22f, 0.34f, 0.11f), - storyPauseSecondsOverride: 2.65f + storyPauseSecondsOverride: 2.65f, + showWindTunnelBackdrop: true )); var dragPolarOverlays = new[] @@ -1950,7 +1977,7 @@ private void BuildSampleLevels() }; levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[35], + GameLevelCatalog.DisplayNames[36], FunctionType.AeroDragPolarTriple, curveColor: new Color(0.75f, 0.55f, 1f, 1f), derivativeColor: new Color(1f, 0.72f, 0.35f, 1f), @@ -1969,11 +1996,12 @@ private void BuildSampleLevels() gridCenter: new Color(0.35f, 0.25f, 0.5f, 0.36f), gridOutside: new Color(0.25f, 0.18f, 0.36f, 0.1f), storyPauseSecondsOverride: 2.65f, - dragPolarOverlayColors: dragPolarOverlays + dragPolarOverlayColors: dragPolarOverlays, + showWindTunnelBackdrop: true )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[36], + GameLevelCatalog.DisplayNames[37], FunctionType.AeroIsothermalDensity, curveColor: new Color(0.45f, 0.88f, 0.72f, 1f), derivativeColor: new Color(0.95f, 0.45f, 0.5f, 1f), @@ -1991,7 +2019,8 @@ private void BuildSampleLevels() applyGridTheming: true, gridCenter: new Color(0.18f, 0.42f, 0.34f, 0.36f), gridOutside: new Color(0.13f, 0.3f, 0.24f, 0.1f), - storyPauseSecondsOverride: 2.6f + storyPauseSecondsOverride: 2.6f, + showWindTunnelBackdrop: true )); var aeroPhugColors = new[] @@ -2002,7 +2031,7 @@ private void BuildSampleLevels() }; levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[37], + GameLevelCatalog.DisplayNames[38], FunctionType.DampedOscillator, curveColor: new Color(0.4f, 0.85f, 0.95f, 1f), derivativeColor: new Color(1f, 0.52f, 0.28f, 1f), @@ -2021,11 +2050,12 @@ private void BuildSampleLevels() gridCenter: new Color(0.14f, 0.35f, 0.48f, 0.36f), gridOutside: new Color(0.1f, 0.25f, 0.34f, 0.1f), levelStageColors: aeroPhugColors, - storyPauseSecondsOverride: 2.75f + storyPauseSecondsOverride: 2.75f, + showWindTunnelBackdrop: true )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[38], + GameLevelCatalog.DisplayNames[39], FunctionType.AeroNewtonianSinSquared, curveColor: new Color(1f, 0.45f, 0.42f, 1f), derivativeColor: new Color(0.5f, 0.82f, 1f, 1f), @@ -2043,11 +2073,12 @@ private void BuildSampleLevels() applyGridTheming: true, gridCenter: new Color(0.48f, 0.22f, 0.2f, 0.35f), gridOutside: new Color(0.34f, 0.15f, 0.14f, 0.1f), - storyPauseSecondsOverride: 2.55f + storyPauseSecondsOverride: 2.55f, + showWindTunnelBackdrop: true )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[39], + GameLevelCatalog.DisplayNames[40], FunctionType.Sine, curveColor: new Color(0.55f, 0.65f, 1f, 1f), derivativeColor: new Color(1f, 0.48f, 0.72f, 1f), @@ -2065,11 +2096,12 @@ private void BuildSampleLevels() applyGridTheming: true, gridCenter: new Color(0.22f, 0.28f, 0.52f, 0.36f), gridOutside: new Color(0.16f, 0.2f, 0.38f, 0.1f), - storyPauseSecondsOverride: 2.45f + storyPauseSecondsOverride: 2.45f, + showWindTunnelBackdrop: true )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[40], + GameLevelCatalog.DisplayNames[41], FunctionType.ExponentialDecay, curveColor: new Color(1f, 0.72f, 0.38f, 1f), derivativeColor: new Color(0.45f, 0.78f, 1f, 1f), @@ -2087,12 +2119,13 @@ private void BuildSampleLevels() applyGridTheming: true, gridCenter: new Color(0.42f, 0.3f, 0.18f, 0.35f), gridOutside: new Color(0.3f, 0.22f, 0.12f, 0.1f), - storyPauseSecondsOverride: 2.65f + storyPauseSecondsOverride: 2.65f, + showWindTunnelBackdrop: true )); - // Economics (41–42) + Mandelbrot (43) + thermo (44) + golden spiral (45); Transforms (46–47); Mandelbrot encore finale (48). + // Economics (42–43); Transforms (44–45); boss block (46–49); spring (50); Big O (51–58). levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[41], + GameLevelCatalog.DisplayNames[42], FunctionType.EconomyDotcomBubbleStylized, curveColor: new Color(0.14f, 0.58f, 0.34f, 1f), derivativeColor: new Color(0.98f, 0.72f, 0.28f, 1f), @@ -2115,7 +2148,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[42], + GameLevelCatalog.DisplayNames[43], FunctionType.EconomySubprime2008Stylized, curveColor: new Color(0.72f, 0.22f, 0.2f, 1f), derivativeColor: new Color(0.52f, 0.78f, 0.95f, 1f), @@ -2137,83 +2170,8 @@ private void BuildSampleLevels() graphStep: 0.09f )); - levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[43], - FunctionType.MandelbrotEscapeImSlice, - curveColor: new Color(0.25f, 0.98f, 0.62f, 1f), - derivativeColor: new Color(0.98f, 0.38f, 0.82f, 1f), - transA: -0.743643887f, - transK: 0.088f, - transC: -2.18f, - transD: 0f, - power: 80, - baseN: 26, - story: - "Final stage — Mandelbrot set — the backdrop is the classic c-plane (Re horizontal, Im vertical) colored by smooth escape time; the bright line marks your fixed Re(c). The green curve is the same slice as before: height vs Im(c).\n\n" + - "The cardioid and bulbs are the boundary where Julia sets disconnect; zooming that coastline reveals endless filaments (true deep zoom needs a different engine, but the map is real Mandelbrot math).\n\n" + - "Slice iteration uses |Im(c)| (conjugate symmetry). Curve uses fractional escape counts so steps look less “flat” than raw integers.", - derivativePopTriggerCountOverride: 4, - applyGridTheming: true, - gridCenter: new Color(0.12f, 0.32f, 0.48f, 0.4f), - gridOutside: new Color(0.08f, 0.18f, 0.28f, 0.12f), - storyPauseSecondsOverride: 2.9f, - graphStep: 0.14f, - levelXStart: -16f, - levelXEnd: 16f - )); - levels.Add(MakeLevel( GameLevelCatalog.DisplayNames[44], - FunctionType.ThermoAdiabaticPV, - curveColor: new Color(0.98f, 0.52f, 0.28f, 1f), - derivativeColor: new Color(0.45f, 0.82f, 0.98f, 1f), - transA: 9.5f, - transK: 0.38f, - transC: -2.35f, - transD: -16f, - power: 2, - baseN: 140, - story: - "Thermodynamics — reversible adiabatic path — for an ideal gas, quasi-static adiabats obey PVγ = constant (no heat exchange, work comes only from internal energy bookkeeping).\n\n" + - "Here the horizontal walk is a scaled “volume-like” coordinate; height tracks pressure mood as P ∝ V−γ. We set N = 140 so γ ≈ 1.40 — a familiar air/diatomic story problem vibe, not a lab instrument.\n\n" + - "Teaching sketch only: real pistons have losses, gradients, and non-equilibrium corners — but the slope story you feel underfoot is still γ.", - derivativePopTriggerCountOverride: 4, - applyGridTheming: true, - gridCenter: new Color(0.38f, 0.18f, 0.1f, 0.36f), - gridOutside: new Color(0.22f, 0.1f, 0.06f, 0.1f), - storyPauseSecondsOverride: 2.85f, - graphStep: 0.11f, - levelXStart: -14f, - levelXEnd: 14f - )); - - levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[45], - FunctionType.PolarGoldenLogSpiral, - curveColor: new Color(0.99f, 0.86f, 0.38f, 1f), - derivativeColor: new Color(0.62f, 0.42f, 0.98f, 1f), - transA: 2.15f, - transK: 1f, - transC: -3.08f, - transD: 0f, - power: 1, - baseN: 105, - story: - "Secret boss — golden spiral — nature’s favorite growth curve is a logarithmic spiral: each time angle θ advances steadily, radius scales by a fixed factor tied to the golden ratio φ = (1+√5)/2.\n\n" + - "Fibonacci rectangles, nautilus moods, and phyllotaxis in sunflowers all whisper the same proportion — here you walk the graph as r(θ) ∝ φ^{kθ} on a polar-style readout (horizontal = θ, vertical = r).\n\n" + - "Exact classical spirals use arc-length subtleties; this stage is the clean calculus headline: exponential growth in φ as you turn.", - derivativePopTriggerCountOverride: 4, - applyGridTheming: true, - gridCenter: new Color(0.42f, 0.34f, 0.14f, 0.38f), - gridOutside: new Color(0.22f, 0.17f, 0.08f, 0.12f), - storyPauseSecondsOverride: 2.95f, - graphStep: 0.075f, - levelXStart: -11.5f, - levelXEnd: 13.5f - )); - - levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[46], FunctionType.TransformFourierSinc, curveColor: new Color(0.42f, 0.78f, 1f, 1f), derivativeColor: new Color(1f, 0.55f, 0.85f, 1f), @@ -2238,7 +2196,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[47], + GameLevelCatalog.DisplayNames[45], FunctionType.TransformLaplaceCausalDecay, curveColor: new Color(0.55f, 0.95f, 0.65f, 1f), derivativeColor: new Color(0.98f, 0.72f, 0.38f, 1f), @@ -2263,7 +2221,32 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[48], + GameLevelCatalog.DisplayNames[46], + FunctionType.PolarGoldenLogSpiral, + curveColor: new Color(0.99f, 0.86f, 0.38f, 1f), + derivativeColor: new Color(0.62f, 0.42f, 0.98f, 1f), + transA: 2.15f, + transK: 1f, + transC: -3.08f, + transD: 0f, + power: 1, + baseN: 105, + story: + "Secret boss — golden spiral — nature’s favorite growth curve is a logarithmic spiral: each time angle θ advances steadily, radius scales by a fixed factor tied to the golden ratio φ = (1+√5)/2.\n\n" + + "Fibonacci rectangles, nautilus moods, and phyllotaxis in sunflowers all whisper the same proportion — here you walk the graph as r(θ) ∝ φ^{kθ} on a polar-style readout (horizontal = θ, vertical = r).\n\n" + + "Exact classical spirals use arc-length subtleties; this stage is the clean calculus headline: exponential growth in φ as you turn.", + derivativePopTriggerCountOverride: 4, + applyGridTheming: true, + gridCenter: new Color(0.42f, 0.34f, 0.14f, 0.38f), + gridOutside: new Color(0.22f, 0.17f, 0.08f, 0.12f), + storyPauseSecondsOverride: 2.95f, + graphStep: 0.075f, + levelXStart: -11.5f, + levelXEnd: 13.5f + )); + + levels.Add(MakeLevel( + GameLevelCatalog.DisplayNames[47], FunctionType.MandelbrotEscapeImSlice, curveColor: new Color(0.25f, 0.98f, 0.62f, 1f), derivativeColor: new Color(0.98f, 0.38f, 0.82f, 1f), @@ -2276,7 +2259,7 @@ private void BuildSampleLevels() story: "True finale — Mandelbrot encore — the backdrop is again the classic c-plane (Re horizontal, Im vertical) colored by smooth escape time; your path follows the same slice: height vs Im(c) at fixed Re(c).\n\n" + "This is the final boss gate: every step still reads Julia–Mandelbrot folklore — bulbs, filaments, and the cardioid where behavior flips.\n\n" + - "Same slice recipe as the mid-finale: fractional escape counts + |Im| symmetry. Welcome back to the boundary.", + "Fractional escape counts + |Im| symmetry on this slice — the Mandelbrot coastline in one graph.", derivativePopTriggerCountOverride: 4, applyGridTheming: true, gridCenter: new Color(0.12f, 0.32f, 0.48f, 0.4f), @@ -2292,7 +2275,7 @@ private void BuildSampleLevels() float lorenzBossK = LorenzAttractorSamples.TimeMax / Mathf.Max(lorenzBossX1 - lorenzBossX0, 0.01f); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[49], + GameLevelCatalog.DisplayNames[48], FunctionType.ChaosLorenzButterflyX, curveColor: new Color(0.42f, 0.86f, 1f, 1f), derivativeColor: new Color(1f, 0.52f, 0.88f, 1f), @@ -2317,7 +2300,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[50], + GameLevelCatalog.DisplayNames[49], FunctionType.PhysicsGravityWellInverseSqrt, curveColor: new Color(0.55f, 0.72f, 1f, 1f), derivativeColor: new Color(1f, 0.45f, 0.35f, 1f), @@ -2349,7 +2332,7 @@ private void BuildSampleLevels() }; levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[51], + GameLevelCatalog.DisplayNames[50], FunctionType.SpringMassUndamped, curveColor: new Color(0.38f, 0.92f, 0.74f, 1f), derivativeColor: new Color(1f, 0.48f, 0.52f, 1f), @@ -2376,7 +2359,7 @@ private void BuildSampleLevels() // --- Big O notation (algorithms): u = k(x−D) plays the role of input size n on the graph --- levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[52], + GameLevelCatalog.DisplayNames[51], FunctionType.Power, curveColor: new Color(0.65f, 0.85f, 1f, 1f), derivativeColor: new Color(1f, 0.78f, 0.45f, 1f), @@ -2396,7 +2379,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[53], + GameLevelCatalog.DisplayNames[52], FunctionType.NaturalLog, curveColor: new Color(0.5f, 0.92f, 0.78f, 1f), derivativeColor: new Color(0.98f, 0.55f, 0.82f, 1f), @@ -2416,7 +2399,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[54], + GameLevelCatalog.DisplayNames[53], FunctionType.SquareRoot, curveColor: new Color(0.72f, 0.78f, 1f, 1f), derivativeColor: new Color(1f, 0.62f, 0.48f, 1f), @@ -2436,7 +2419,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[55], + GameLevelCatalog.DisplayNames[54], FunctionType.Power, curveColor: new Color(0.55f, 0.9f, 1f, 1f), derivativeColor: new Color(1f, 0.5f, 0.65f, 1f), @@ -2456,7 +2439,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[56], + GameLevelCatalog.DisplayNames[55], FunctionType.BigONLogN, curveColor: new Color(0.48f, 0.82f, 1f, 1f), derivativeColor: new Color(1f, 0.58f, 0.78f, 1f), @@ -2476,7 +2459,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[57], + GameLevelCatalog.DisplayNames[56], FunctionType.Power, curveColor: new Color(0.6f, 0.72f, 1f, 1f), derivativeColor: new Color(1f, 0.52f, 0.42f, 1f), @@ -2496,7 +2479,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[58], + GameLevelCatalog.DisplayNames[57], FunctionType.Power, curveColor: new Color(0.52f, 0.68f, 0.98f, 1f), derivativeColor: new Color(1f, 0.48f, 0.55f, 1f), @@ -2516,7 +2499,7 @@ private void BuildSampleLevels() )); levels.Add(MakeLevel( - GameLevelCatalog.DisplayNames[59], + GameLevelCatalog.DisplayNames[58], FunctionType.Exponential, curveColor: new Color(0.58f, 0.95f, 0.72f, 1f), derivativeColor: new Color(1f, 0.45f, 0.88f, 1f), @@ -2567,7 +2550,8 @@ private LevelDefinition MakeLevel( float? levelXStart = null, float? levelXEnd = null, Color[] dragPolarOverlayColors = null, - float? riemannPlatformCoverage = null) + float? riemannPlatformCoverage = null, + bool showWindTunnelBackdrop = false) { var def = ScriptableObject.CreateInstance(); def.levelName = name; @@ -2639,6 +2623,8 @@ private LevelDefinition MakeLevel( }; } + def.showWindTunnelBackdrop = showWindTunnelBackdrop; + return def; } @@ -2685,6 +2671,7 @@ private void ApplyLevelTheme(LevelDefinition def) functionPlotter.power = def.power; functionPlotter.baseN = def.baseN; functionPlotter.differentiate = true; + functionPlotter.showWindTunnelBackdrop = def.showWindTunnelBackdrop; if (def.showRiemannVisualization) { diff --git a/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs b/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs index c44d179..8acff83 100644 --- a/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs +++ b/First Principles/Assets/Scripts/Game/StageRoleplayLibrary.cs @@ -80,56 +80,54 @@ public static class StageRoleplayLibrary // 33 "Circle lawyer. (x−h)²+(y−k)²=R² fails the vertical-line exam—so you walk the upper contract only. Semicircles still argue with implicit bias.", // 34 - "Wind-tunnel initiate. Lift coefficient whispers to angle of attack until stall throws a tantrum. Respect the breakpoint; it’s older than your clearance badge.", + "Heat engine cadet. Compression trades volume for pressure along an adiabat—no heat admitted, just workledger math. Feel the steepening as γ insists the gas fight back harder per liter squeezed.", // 35 - "Performance engineer. Drag polar plots your sins against lift: parasitic weight plus induced gossip. Min-drag C_L is the quiet table at the banquet.", + "Wind-tunnel initiate. Lift coefficient whispers to angle of attack until stall throws a tantrum. Respect the breakpoint; it’s older than your clearance badge.", // 36 - "High-altitude clerk. Isothermal density falls exponentially—scale height is the accountant. Thinner air, quieter Reynolds gossip, louder truth about thrust lapse.", + "Performance engineer. Drag polar plots your sins against lift: parasitic weight plus induced gossip. Min-drag C_L is the quiet table at the banquet.", // 37 - "Test pilot (modes). Phugoid myths trade altitude for speed slowly; short-period pitches snap faster. Damping writes apologies on every oscillation.", + "High-altitude clerk. Isothermal density falls exponentially—scale height is the accountant. Thinner air, quieter Reynolds gossip, louder truth about thrust lapse.", // 38 - "Hypersonic scribe. Newtonian sin²α scratches impact lore on blunt faces—models, not scripture. Use it to speak, not to land contracts.", + "Test pilot (modes). Phugoid myths trade altitude for speed slowly; short-period pitches snap faster. Damping writes apologies on every oscillation.", // 39 - "Wake listener. Strouhal hums a shedding song—bluff bodies gossip at f~St·U/D. Feel the sine fingerprint of organized wake jazz.", + "Hypersonic scribe. Newtonian sin²α scratches impact lore on blunt faces—models, not scripture. Use it to speak, not to land contracts.", // 40 - "Shield monk. Re-entry trades dynamic pressure against velocity cubed in campfire tales. The envelope relaxes: breathe as ρ and V forgive you.", + "Wake listener. Strouhal hums a shedding song—bluff bodies gossip at f~St·U/D. Feel the sine fingerprint of organized wake jazz.", // 41 - "Equities ghost. You ride a stylized dot-com decade—run-up, vertigo, air pocket—where every slope is a headline and second derivative feels like sentiment flipping overnight.", + "Shield monk. Re-entry trades dynamic pressure against velocity cubed in campfire tales. The envelope relaxes: breathe as ρ and V forgive you.", // 42 - "Risk officer. The 2008 arc is a cliff masquerading as a bull: crawl the crest, brace for the sheer drop, then learn that recovery is a slow integral, not a bounce.", + "Equities ghost. You ride a stylized dot-com decade—run-up, vertigo, air pocket—where every slope is a headline and second derivative feels like sentiment flipping overnight.", // 43 - "Fractal exile. Mandelbrot boundary guards escape routes—each iterate is a spell. Step wrong and infinity notices; step right and you pierce a holographic veil.", + "Risk officer. The 2008 arc is a cliff masquerading as a bull: crawl the crest, brace for the sheer drop, then learn that recovery is a slow integral, not a bounce.", // 44 - "Heat engine cadet. Compression trades volume for pressure along an adiabat—no heat admitted, just workledger math. Feel the steepening as γ insists the gas fight back harder per liter squeezed.", + "Spectrum scribe. A rectangle in one domain blooms into a sinc in the other—side lobes are the honest echo of sharp corners. You are reading the interference pattern of changing coordinates.", // 45 - "Gilded navigator. Every quarter-turn the world wants to scale itself by φ—the spiral is a compass that never forgets proportion. Follow the radius outward: each step is geometric, not arithmetic.", + "s‑plane pilgrim. The exponential after the switch-on is the seed of every pole story: decay in time becomes algebra in s. The past is zero until the kernel says go.", // 46 - "Spectrum scribe. A rectangle in one domain blooms into a sinc in the other—side lobes are the honest echo of sharp corners. You are reading the interference pattern of changing coordinates.", + "Gilded navigator. Every quarter-turn the world wants to scale itself by φ—the spiral is a compass that never forgets proportion. Follow the radius outward: each step is geometric, not arithmetic.", // 47 - "s‑plane pilgrim. The exponential after the switch-on is the seed of every pole story: decay in time becomes algebra in s. The past is zero until the kernel says go.", - // 48 "Fractal exile, encore. You return to Mandelbrot’s coastline for the last word—each iterate still votes on escape, and the boundary remembers every branch you dared to name.", - // 49 + // 48 "Chaos theory. Lorenz’s wings beat on a thread of time: the curve you ride is sensitive, restless, forever retuning—small shifts in the unseen become storms in the visible trace.", - // 50 + // 49 "Event horizon clerk. The graph pretends to be a softened well—potential diving toward a point that eats straight lines. Tread the shoulder: steep slopes mean the derivative has opinions.", - // 51 + // 50 "Spring cadet. Hooke’s law pulls you home to equilibrium — each crest is stored spring energy, each crossing is the quiet where velocity wins; undamped, the tune never dies, only repeats.", - // 52 + // 51 "Constant-time courier. O(1) is the myth that distance doesn’t matter—your path stays level while the input scrolls sideways. Enjoy the flatness; it’s rare in the wild.", - // 53 + // 52 "Binary search monk. O(log n) whispers: halve, halve, halve. The curve climbs so politely you almost trust infinite data—almost.", - // 54 + // 53 "Root scout. O(√n) is the compromise growth—faster than log, slower than linear. You’re walking a power law with a gentle exponent.", - // 55 + // 54 "Linear pilgrim. O(n) is honesty: one pass, proportional work. The ramp doesn’t cheat; it just keeps asking for more steps.", - // 56 + // 55 "Sort priest. O(n log n) is the church of merge sorts and balanced trees—more than linear, less than quadratic, forever arguing about constants in the basement.", - // 57 + // 56 "Nested-loop detective. O(n²) means someone doubled a walk. Feel the parabola: small n forgives you; large n sends invoices.", - // 58 + // 57 "Cubic alchemist. O(n³) is triple trouble—dense, blunt, expensive. The graph rockets to remind you why we invent better algorithms.", - // 59 + // 58 "Subset gambler. O(2ⁿ) is the house always winning: every extra unit doubles the shadow workload. Pray for pruning, memoization, or a smaller universe." }; diff --git a/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs index b919953..99152e4 100644 --- a/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs +++ b/First Principles/Assets/Scripts/UI/BlackHoleGargantuaBackdrop.cs @@ -109,7 +109,16 @@ public void Drive(FunctionPlotter fp) if (_mat == null) return; - Rect r = ((RectTransform)transform).rect; + var rtDrive = (RectTransform)transform; + if (rtDrive.anchorMin != Vector2.zero || rtDrive.anchorMax != Vector2.one) + { + rtDrive.anchorMin = Vector2.zero; + rtDrive.anchorMax = Vector2.one; + rtDrive.offsetMin = Vector2.zero; + rtDrive.offsetMax = Vector2.zero; + } + + Rect r = rtDrive.rect; float aspect = r.height > 1e-3f ? Mathf.Max(0.2f, r.width / r.height) : 1.7f; // Map level softening |D| → shader mass scale (gameplay uses softened 1/r well). diff --git a/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs b/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs new file mode 100644 index 0000000..dbe8a53 --- /dev/null +++ b/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs @@ -0,0 +1,122 @@ +using UnityEngine; +using UnityEngine.UI; + +// ----------------------------------------------------------------------------- +// GoldenSpiralBackdrop — logarithmic φ-spiral field behind the graph (boss stage) +// ----------------------------------------------------------------------------- +// Shown when FunctionType is PolarGoldenLogSpiral; GPU-only, matches stage theme. +// ----------------------------------------------------------------------------- + +[DisallowMultipleComponent] +[RequireComponent(typeof(RawImage))] +public sealed class GoldenSpiralBackdrop : MonoBehaviour +{ + public const string ChildName = "_GoldenSpiralBackdrop"; + + static readonly int IdTimeLive = Shader.PropertyToID("_TimeLive"); + static readonly int IdAspect = Shader.PropertyToID("_Aspect"); + static readonly int IdColor = Shader.PropertyToID("_Color"); + + static readonly Color GoldenTint = new Color(1f, 0.88f, 0.52f, 0.5f); + + RawImage _raw; + Material _mat; + + void Awake() + { + _raw = GetComponent(); + _raw.raycastTarget = false; + } + + void OnDestroy() + { + if (_mat != null) + Destroy(_mat); + } + + void Update() + { + if (_mat == null || !_raw.gameObject.activeInHierarchy) + return; + _mat.SetFloat(IdTimeLive, Time.time); + } + + public static void Sync(RectTransform gridPanel, FunctionPlotter fp) + { + if (gridPanel == null || fp == null) + return; + + Transform existing = gridPanel.Find(ChildName); + if (fp.functionType != FunctionType.PolarGoldenLogSpiral) + { + if (existing != null) + existing.gameObject.SetActive(false); + return; + } + + GameObject go; + if (existing == null) + { + go = new GameObject(ChildName, typeof(RectTransform), typeof(CanvasRenderer), typeof(RawImage), typeof(GoldenSpiralBackdrop)); + go.transform.SetParent(gridPanel, false); + var rt = go.GetComponent(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + var raw = go.GetComponent(); + raw.raycastTarget = false; + raw.texture = Texture2D.whiteTexture; + raw.color = Color.white; + } + else + go = existing.gameObject; + + go.SetActive(true); + go.transform.SetAsFirstSibling(); + + var backdrop = go.GetComponent(); + if (backdrop == null) + backdrop = go.AddComponent(); + backdrop.Drive(fp); + } + + void EnsureMaterial() + { + if (_mat != null) + return; + + Shader sh = Resources.Load("UI_GoldenSpiralBackdrop"); + if (sh == null) + sh = Shader.Find("UI/GoldenSpiralBackdrop"); + if (sh == null) + { + Debug.LogWarning("GoldenSpiralBackdrop: shader UI_GoldenSpiralBackdrop not found (place under Resources)."); + return; + } + + _mat = new Material(sh); + _raw.material = _mat; + } + + public void Drive(FunctionPlotter fp) + { + EnsureMaterial(); + if (_mat == null) + return; + + var rtDrive = (RectTransform)transform; + if (rtDrive.anchorMin != Vector2.zero || rtDrive.anchorMax != Vector2.one) + { + rtDrive.anchorMin = Vector2.zero; + rtDrive.anchorMax = Vector2.one; + rtDrive.offsetMin = Vector2.zero; + rtDrive.offsetMax = Vector2.zero; + } + + float aspect = rtDrive.rect.height > 1e-3f ? Mathf.Max(0.2f, rtDrive.rect.width / rtDrive.rect.height) : 1.7f; + _mat.SetFloat(IdAspect, aspect); + _mat.SetFloat(IdTimeLive, Time.time); + _mat.SetColor(IdColor, GoldenTint); + } +} diff --git a/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs.meta b/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs.meta new file mode 100644 index 0000000..590279e --- /dev/null +++ b/First Principles/Assets/Scripts/UI/GoldenSpiralBackdrop.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9f4d02e5a3c4170c8d6e9f2a4b3051c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs b/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs new file mode 100644 index 0000000..ae4b8fb --- /dev/null +++ b/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs @@ -0,0 +1,119 @@ +using UnityEngine; +using UnityEngine.UI; + +// ----------------------------------------------------------------------------- +// WindTunnelBackdrop — procedural wind-tunnel / schlieren mood behind the graph +// ----------------------------------------------------------------------------- +// Shown on all aerospace category stages via FunctionPlotter.showWindTunnelBackdrop. +// GPU-only; no CPU texture. +// ----------------------------------------------------------------------------- + +[DisallowMultipleComponent] +[RequireComponent(typeof(RawImage))] +public sealed class WindTunnelBackdrop : MonoBehaviour +{ + public const string ChildName = "_WindTunnelBackdrop"; + + static readonly int IdAspect = Shader.PropertyToID("_Aspect"); + static readonly int IdFlowSpeed = Shader.PropertyToID("_FlowSpeed"); + static readonly int IdStreakScale = Shader.PropertyToID("_StreakScale"); + static readonly int IdColor = Shader.PropertyToID("_Color"); + + static readonly Color WindTint = new Color(0.9f, 0.96f, 1f, 0.54f); + + RawImage _raw; + Material _mat; + + void Awake() + { + _raw = GetComponent(); + _raw.raycastTarget = false; + } + + void OnDestroy() + { + if (_mat != null) + Destroy(_mat); + } + + public static void Sync(RectTransform gridPanel, FunctionPlotter fp) + { + if (gridPanel == null || fp == null) + return; + + Transform existing = gridPanel.Find(ChildName); + if (!fp.showWindTunnelBackdrop) + { + if (existing != null) + existing.gameObject.SetActive(false); + return; + } + + GameObject go; + if (existing == null) + { + go = new GameObject(ChildName, typeof(RectTransform), typeof(CanvasRenderer), typeof(RawImage), typeof(WindTunnelBackdrop)); + go.transform.SetParent(gridPanel, false); + var rt = go.GetComponent(); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + var raw = go.GetComponent(); + raw.raycastTarget = false; + raw.texture = Texture2D.whiteTexture; + raw.color = Color.white; + } + else + go = existing.gameObject; + + go.SetActive(true); + go.transform.SetAsFirstSibling(); + + var backdrop = go.GetComponent(); + if (backdrop == null) + backdrop = go.AddComponent(); + backdrop.Drive(fp); + } + + void EnsureMaterial() + { + if (_mat != null) + return; + + Shader sh = Resources.Load("UI_WindTunnelBackdrop"); + if (sh == null) + sh = Shader.Find("UI/WindTunnelBackdrop"); + if (sh == null) + { + Debug.LogWarning("WindTunnelBackdrop: shader UI_WindTunnelBackdrop not found (place under Resources)."); + return; + } + + _mat = new Material(sh); + _mat.SetColor(IdColor, WindTint); + _raw.material = _mat; + } + + public void Drive(FunctionPlotter fp) + { + EnsureMaterial(); + if (_mat == null) + return; + + var rt = (RectTransform)transform; + if (rt.anchorMin != Vector2.zero || rt.anchorMax != Vector2.one) + { + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + } + + float aspect = rt.rect.height > 1e-3f ? Mathf.Max(0.2f, rt.rect.width / rt.rect.height) : 1.7f; + _mat.SetFloat(IdAspect, aspect); + _mat.SetFloat(IdFlowSpeed, 0.42f + Mathf.Clamp01(fp.transK) * 0.35f); + _mat.SetFloat(IdStreakScale, 7.5f + Mathf.Abs(fp.transA) * 1.2f); + _mat.SetColor(IdColor, WindTint); + } +} diff --git a/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs.meta b/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs.meta new file mode 100644 index 0000000..c15f9a1 --- /dev/null +++ b/First Principles/Assets/Scripts/UI/WindTunnelBackdrop.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5426f749a56a94bcdaafe25f3a3a4711 \ No newline at end of file From 27f6aaf8d341c815536a6dedd1540a60b35b767d Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:08:23 -0400 Subject: [PATCH 05/14] Fixed Mobile Touch Controls (still not working) --- .../Assets/Resources/Localization/en.txt | 6 +- First Principles/Assets/Scenes/Game.unity | 2 +- First Principles/Assets/Scenes/Menu.unity | 4 +- .../Assets/Scripts/Game/LevelManager.cs | 60 +++- .../Scripts/Game/PlayerControllerUI2D.cs | 8 +- .../Assets/Scripts/UI/DeviceLayout.cs | 2 +- .../Scripts/UI/GameplayScreenTouchZones.cs | 163 ++++++--- .../Assets/Scripts/UI/GridRendererUI.cs | 50 +-- .../Assets/Scripts/UI/LabelManager.cs | 23 ++ .../Assets/Scripts/UI/MenuTutorialOverlay.cs | 2 +- .../Assets/Scripts/UI/MobileInputBridge.cs | 3 +- .../LiberationSans SDF - Fallback.asset | 321 ++++++++++++++++++ 12 files changed, 567 insertions(+), 77 deletions(-) diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index 6255da8..5b88d5d 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -26,8 +26,8 @@ ui.jump=Jump ui.move=Move ui.keyboard_hint_mobile=(keyboard: arrows / Space) hud.stage=STAGE -controls.mobile=Left hold ◀ · Right hold ▶ · Swipe up jump (keyboard: arrows / Space) -controls.guide_overlay=Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nSwipe up anywhere — jump\n\nKeyboard: Arrow keys move · Space jumps +controls.mobile=Left hold ◀ · Right hold ▶ · 2nd finger jump (keyboard: arrows / Space) +controls.guide_overlay=Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nWhile holding, tap with another finger — jump\n\nKeyboard: Arrow keys move · Space jumps controls.desktop=Move · Jump Space controls.calculator=Graphing calculator Type f(u) · Deriv · · Trans · Scale · Pinch · Back graph.calc_deriv=Deriv @@ -57,7 +57,7 @@ graph.calculator_intro=Graphing calculator mode\nType almost aerospace.story_drag_polar_preamble=Drag polar refresher (every Aerospace stage)\nParasitic (zero-lift) drag — skin friction, form drag, interference lumped as CD0 in the parabolic model (roughly not the part that grows with lift).\nInduced drag — the cost of making lift: trailing vortices add ~ K CL² (higher CL / tighter turns → more induced).\nOverall drag polarCD = CD0 + K CL²: an upward-opening parabola in CL; min-drag CL sits between “too slow / high α” and “too fast / low α” for real missions. menu.tutorial_button=How to play menu.tutorial_title=How to play -menu.tutorial_body=Goal\nMove along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\nControls\n• Move — arrows / WASD, or on-screen buttons.\n• Jump — Space (or mobile jump). You jump from solid platforms.\n\nThe two curves\n• Main curve — the function you walk on.\n• Derivative f′ — slope information; it’s drawn as a second line.\n\nAir jump on the derivative\nWhile you are in the air, if your character overlaps the derivative curve, press Jump again for an extra hop.\n\nThe derivative line brightens when you touch it. You get one bonus jump each time you brush it until you leave the curve or land. On phones you may feel a short vibration when you touch f′; on PC a sound plays when vibration isn’t available.\n\nSelect level\nOn this screen, stages are grouped (Core, Engineering, AP Calculus, Aerospace …). Tap How to play at the bottom to reopen this help. Pick a group, then a level. +menu.tutorial_body=Goal\nMove along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\nControls\n• Move — arrows / WASD, or on a phone hold the left / right half of the screen.\n• Jump — Space, or on a phone tap with a second finger while holding left/right. You jump from solid platforms.\n\nThe two curves\n• Main curve — the function you walk on.\n• Derivative f′ — slope information; it’s drawn as a second line.\n\nAir jump on the derivative\nWhile you are in the air, if your character overlaps the derivative curve, press Jump again for an extra hop.\n\nThe derivative line brightens when you touch it. You get one bonus jump each time you brush it until you leave the curve or land. On phones you may feel a short vibration when you touch f′; on PC a sound plays when vibration isn’t available.\n\nSelect level\nOn this screen, stages are grouped (Core, Engineering, AP Calculus, Aerospace …). Tap How to play at the bottom to reopen this help. Pick a group, then a level. menu.player_icon_title=Player icon menu.player_icon_set=Player icon menu.player_icon_hint=Tap a symbol — it’s your avatar in levels. diff --git a/First Principles/Assets/Scenes/Game.unity b/First Principles/Assets/Scenes/Game.unity index 24e72d6..333a2c6 100644 --- a/First Principles/Assets/Scenes/Game.unity +++ b/First Principles/Assets/Scenes/Game.unity @@ -2871,7 +2871,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Material: {fileID: 0} m_Color: {r: 0.122641504, g: 0.122641504, b: 0.122641504, a: 1} - m_RaycastTarget: 1 + m_RaycastTarget: 0 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: diff --git a/First Principles/Assets/Scenes/Menu.unity b/First Principles/Assets/Scenes/Menu.unity index 12d6ced..91d53c6 100644 --- a/First Principles/Assets/Scenes/Menu.unity +++ b/First Principles/Assets/Scenes/Menu.unity @@ -436,8 +436,8 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: -392} - m_SizeDelta: {x: 964.3611, y: 118} + m_AnchoredPosition: {x: 0, y: -452} + m_SizeDelta: {x: 964.3611, y: 132} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1004057114 MonoBehaviour: diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 04627a8..c23017c 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -282,7 +282,10 @@ private void SetupReferences() ConfigureGameBackButtonDestination(); if (!graphCalculatorMode) + { FitCartesianPlaneForGameplay(); + SyncGameplayLayoutToCartesianPlane(); + } } /// @@ -304,8 +307,22 @@ private void FitCartesianPlaneForGameplay() bool mobile = DeviceLayout.PreferOnScreenGameControls; float hPad = mobile ? 8f : 14f; - float topReserve = mobile ? 172f : 138f; - float bottomReserve = mobile ? DeviceLayout.TouchHintVerticalOffset + 32f : 70f; + float aspectTall = ph / Mathf.Max(1f, pw); + float topReserve; + float bottomReserve; + if (mobile) + { + // Portrait height fraction so graph + axes scale together on tall phones (not only TMP labels). + float tallBlend = Mathf.Clamp01((aspectTall - 1.35f) / 0.82f); + topReserve = Mathf.Clamp(ph * Mathf.Lerp(0.102f, 0.086f, tallBlend), 120f, 205f); + float hintFloor = DeviceLayout.TouchHintVerticalOffset + 26f; + bottomReserve = Mathf.Clamp(ph * Mathf.Lerp(0.128f, 0.112f, tallBlend), hintFloor, 255f); + } + else + { + topReserve = 138f; + bottomReserve = 70f; + } float maxW = Mathf.Max(64f, pw - hPad * 2f); float maxH = Mathf.Max(64f, ph - topReserve - bottomReserve); @@ -315,7 +332,7 @@ private void FitCartesianPlaneForGameplay() float s = Mathf.Min(1f, maxW / baseW, maxH / baseH); Vector2 newSize = new Vector2(baseW * s, baseH * s); - float yNudge = mobile ? (bottomReserve - topReserve) * 0.2f : 0f; + float yNudge = mobile ? (bottomReserve - topReserve) * 0.18f : 0f; cartesianPlaneRect.anchorMin = new Vector2(0.5f, 0.5f); cartesianPlaneRect.anchorMax = new Vector2(0.5f, 0.5f); @@ -329,12 +346,47 @@ private void FitCartesianPlaneForGameplay() cartesianPlaneRect.anchoredPosition = new Vector2(0f, yNudge); } + /// + /// Authoring used a fixed 1820×980 grid rect; after the Cartesian plane + /// shrinks on phones — stretch grid + curve renderers to fill it so axes, graphs, and obstacle math line up. + /// + private void StretchGameplayGridStackToCartesianPlane() + { + if (gridRenderer == null || cartesianPlaneRect == null) + return; + + var gridRt = gridRenderer.rectTransform; + gridRt.anchorMin = Vector2.zero; + gridRt.anchorMax = Vector2.one; + gridRt.pivot = new Vector2(0.5f, 0.5f); + gridRt.offsetMin = Vector2.zero; + gridRt.offsetMax = Vector2.zero; + gridRt.anchoredPosition = Vector2.zero; + + for (int i = 0; i < gridRt.childCount; i++) + { + var lineRt = gridRt.GetChild(i) as RectTransform; + if (lineRt == null) + continue; + lineRt.anchorMin = Vector2.zero; + lineRt.anchorMax = Vector2.one; + lineRt.pivot = new Vector2(0f, 0f); + lineRt.offsetMin = Vector2.zero; + lineRt.offsetMax = Vector2.zero; + lineRt.anchoredPosition = Vector2.zero; + } + + gridRenderer.SetVerticesDirty(); + } + private void SyncGameplayLayoutToCartesianPlane() { if (graphCalculatorMode || cartesianPlaneRect == null || gridRenderer == null || obstacleGenerator == null || playerController == null) return; + StretchGameplayGridStackToCartesianPlane(); + Vector2 sz = cartesianPlaneRect.rect.size; var gridSize = gridRenderer.gridSize; @@ -2849,7 +2901,7 @@ private IEnumerator RunMobileControlGuideRoutine() tmp.lineSpacing = 6f; tmp.color = new Color(0.94f, 0.95f, 0.98f, 1f); tmp.text = TmpLatex.Process(LocalizationManager.Get("controls.guide_overlay", - "Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nSwipe up anywhere — jump\n\nKeyboard: Arrow keys move · Space jumps")); + "Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nWhile holding, tap with another finger — jump\n\nKeyboard: Arrow keys move · Space jumps")); LocalizationManager.ApplyTextDirection(tmp); ApplyPrimaryUiTypography(tmp, FindPrimaryEquationTmp(), outlineWidth: 0.1f, outlineAlpha: 0.42f); diff --git a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs index 50b096a..ee6764c 100644 --- a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs +++ b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs @@ -18,8 +18,8 @@ public class PlayerControllerUI2D : MonoBehaviour { [Header("Movement (Grid Units)")] [SerializeField] private float moveSpeedGridPerSec = 7f; - [SerializeField] private float gravityGridPerSec2 = 20f; - [SerializeField] private float jumpVelocityGridPerSec = 9f; + [SerializeField] private float gravityGridPerSec2 = 15.5f; + [SerializeField] private float jumpVelocityGridPerSec = 11.2f; [Header("f′ line — air jump")] [Tooltip("Grid-space proximity to f′ (player center vs polyline). Wider = easier to register a 'hit'.")] @@ -69,7 +69,7 @@ public class PlayerControllerUI2D : MonoBehaviour private bool touchingDerivativeNow; /// After using f′ air jump, stay true until you leave the band or land (prevents spam while sliding on the line). private bool derivativeAirJumpConsumedThisBand; - /// Fresh level entry: first grounded jump uses ×1.5 once. + /// Fresh level entry: first grounded jump uses a small boost once (~12% over base). private bool strongFirstGroundJumpPending; private float derivativeHighlightSmoothed; private AudioSource derivativeHitAudio; @@ -209,7 +209,7 @@ private void Update() float jv = jumpVelocityGridPerSec; if (strongFirstGroundJumpPending) { - jv *= 1.5f; + jv *= 1.12f; strongFirstGroundJumpPending = false; } velGrid.y = jv; diff --git a/First Principles/Assets/Scripts/UI/DeviceLayout.cs b/First Principles/Assets/Scripts/UI/DeviceLayout.cs index 9713ab2..7f584c7 100644 --- a/First Principles/Assets/Scripts/UI/DeviceLayout.cs +++ b/First Principles/Assets/Scripts/UI/DeviceLayout.cs @@ -75,7 +75,7 @@ public static float RecommendedCanvasMatchWidthOrHeight() public static float TouchControlBarHeight => IsTabletLike() ? 188f : 168f; - /// True in Game when we use left/right screen halves + swipe (no ◀ ▶ Jump strip). + /// True in Game when we use left/right screen halves + second-finger jump (no ◀ ▶ Jump strip). public static bool GameplayUsesFullScreenTouchZones => PreferOnScreenGameControls; /// Bottom offset for the small controls hint chip (above graph; no virtual bar when zones are on). diff --git a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs index df74194..7443e08 100644 --- a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs +++ b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs @@ -4,16 +4,16 @@ using UnityEngine.UI; /// -/// Game scene: invisible full-screen touch layer (first under safe-area HUD). Hold left half → move left, -/// hold right half → move right; release with a dominant upward swipe → jump. Replaces virtual ◀ ▶ Jump buttons. +/// Game scene: invisible full-screen touch layer. Hold left half → move left, hold right half → move right. +/// While holding movement, put down a second finger anywhere → jump (one shot per touch-down). /// public class GameplayScreenTouchZones : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler { private static GameplayScreenTouchZones _instance; - private readonly Dictionary _pointerDownScreen = new Dictionary(); private readonly Dictionary _pointerSide = new Dictionary(); + private readonly HashSet _jumpOnlyPointerIds = new HashSet(); public static void EnsureForGameCanvas(Transform canvasTransform) { @@ -22,9 +22,6 @@ public static void EnsureForGameCanvas(Transform canvasTransform) DestroyLegacyButtonBar(canvasTransform); - if (_instance != null) - return; - Transform existing = canvasTransform.Find("GameplayScreenTouchZonesRoot"); if (existing == null) { @@ -33,30 +30,113 @@ public static void EnsureForGameCanvas(Transform canvasTransform) existing = safe.Find("GameplayScreenTouchZonesRoot"); } + RectTransform rt; if (existing != null) { + rt = existing as RectTransform; _instance = existing.GetComponent(); - return; + if (_instance == null) + _instance = existing.gameObject.AddComponent(); + } + else + { + var parentRt = MobileUiRoots.GetSafeContentParent(canvasTransform) ?? canvasTransform as RectTransform; + if (parentRt == null) + return; + + var go = new GameObject("GameplayScreenTouchZonesRoot", typeof(RectTransform)); + rt = go.GetComponent(); + rt.SetParent(parentRt, false); + rt.anchorMin = Vector2.zero; + rt.anchorMax = Vector2.one; + rt.offsetMin = Vector2.zero; + rt.offsetMax = Vector2.zero; + + var img = go.AddComponent(); + img.color = new Color(0f, 0f, 0f, 0f); + img.raycastTarget = true; + + _instance = go.AddComponent(); } - var parentRt = MobileUiRoots.GetSafeContentParent(canvasTransform) ?? canvasTransform as RectTransform; - if (parentRt == null) + // Must sit above the full-screen graph stack (GraphicRaycaster hits top-first). Under _SafeContent + // as first sibling put this layer *behind* GraphContainer — touches never reached gameplay. + ReparentTouchLayerAboveGraph(canvasTransform, rt); + } + + /// + /// Inserts the touch catcher just above Graph inside GraphContainer so Footer/HUD stays on top. + /// + static void ReparentTouchLayerAboveGraph(Transform canvasTransform, RectTransform touchRt) + { + if (touchRt == null || canvasTransform == null) + return; + + var graphContainer = FindDeepChildByName(canvasTransform, "GraphContainer") as RectTransform; + if (graphContainer == null) + { + var fallback = MobileUiRoots.GetSafeContentParent(canvasTransform) ?? canvasTransform as RectTransform; + if (fallback == null) + return; + touchRt.SetParent(fallback, false); + touchRt.anchorMin = Vector2.zero; + touchRt.anchorMax = Vector2.one; + touchRt.offsetMin = Vector2.zero; + touchRt.offsetMax = Vector2.zero; + int gc = -1; + for (int i = 0; i < fallback.childCount; i++) + { + if (fallback.GetChild(i).name == "GraphContainer") + { + gc = i; + break; + } + } + + if (gc >= 0) + { + int fallbackMaxSibling = Mathf.Max(0, fallback.childCount - 1); + touchRt.SetSiblingIndex(Mathf.Clamp(gc + 1, 0, fallbackMaxSibling)); + } + else + touchRt.SetAsLastSibling(); return; + } - var go = new GameObject("GameplayScreenTouchZonesRoot", typeof(RectTransform)); - var rt = go.GetComponent(); - rt.SetParent(parentRt, false); - rt.SetAsFirstSibling(); - rt.anchorMin = Vector2.zero; - rt.anchorMax = Vector2.one; - rt.offsetMin = Vector2.zero; - rt.offsetMax = Vector2.zero; + touchRt.SetParent(graphContainer, false); + touchRt.anchorMin = Vector2.zero; + touchRt.anchorMax = Vector2.one; + touchRt.offsetMin = Vector2.zero; + touchRt.offsetMax = Vector2.zero; - var img = go.AddComponent(); - img.color = new Color(0f, 0f, 0f, 0f); - img.raycastTarget = true; + int graphIdx = 0; + for (int i = 0; i < graphContainer.childCount; i++) + { + if (graphContainer.GetChild(i).name == "Graph") + { + graphIdx = i; + break; + } + } - _instance = go.AddComponent(); + int graphMaxSibling = Mathf.Max(0, graphContainer.childCount - 1); + touchRt.SetSiblingIndex(Mathf.Clamp(graphIdx + 1, 0, graphMaxSibling)); + } + + static Transform FindDeepChildByName(Transform root, string name) + { + if (root == null) + return null; + if (root.name == name) + return root; + for (int i = 0; i < root.childCount; i++) + { + var c = FindDeepChildByName(root.GetChild(i), name); + if (c != null) + return c; + } + + return null; } private static void DestroyLegacyButtonBar(Transform canvasTransform) @@ -80,17 +160,19 @@ private void OnDestroy() MobileInputBridge.ClearTouchRouting(); } - private static float MinSwipeUpPixels() - { - float dpi = Screen.dpi > 1f ? Screen.dpi : 163f; - return Mathf.Clamp(48f * (dpi / 160f), 40f, 100f); - } - public void OnPointerDown(PointerEventData eventData) { int id = eventData.pointerId; + + // Second finger while already steering: jump (do not stack another left/right hold). + if (_pointerSide.Count >= 1) + { + MobileInputBridge.QueueJump(); + _jumpOnlyPointerIds.Add(id); + return; + } + Vector2 pos = eventData.position; - _pointerDownScreen[id] = pos; float mid = Screen.width * 0.5f; int side = pos.x < mid ? -1 : 1; _pointerSide[id] = side; @@ -101,29 +183,30 @@ public void OnPointerDown(PointerEventData eventData) } public void OnPointerUp(PointerEventData eventData) => - EndPointer(eventData.pointerId, evaluateSwipeJump: true, eventData.position); + EndPointer(eventData.pointerId); public void OnPointerExit(PointerEventData eventData) => - EndPointer(eventData.pointerId, evaluateSwipeJump: false, eventData.position); + EndPointer(eventData.pointerId); - private void EndPointer(int pointerId, bool evaluateSwipeJump, Vector2 releasePosition) + private void EndPointer(int pointerId) { - if (!_pointerSide.TryGetValue(pointerId, out int side)) + if (_jumpOnlyPointerIds.Remove(pointerId)) return; - if (evaluateSwipeJump && _pointerDownScreen.TryGetValue(pointerId, out Vector2 down)) - { - Vector2 delta = releasePosition - down; - float minUp = MinSwipeUpPixels(); - if (delta.y > minUp && delta.y > Mathf.Abs(delta.x) * 0.55f) - MobileInputBridge.QueueJump(); - } + if (!_pointerSide.TryGetValue(pointerId, out int side)) + return; - _pointerDownScreen.Remove(pointerId); if (side < 0) MobileHoldAxis.ReleaseLeft(); else MobileHoldAxis.ReleaseRight(); _pointerSide.Remove(pointerId); } + + /// Clears jump-only pointer bookkeeping when runs. + internal static void ClearAuxiliaryPointerState() + { + if (_instance != null) + _instance._jumpOnlyPointerIds.Clear(); + } } diff --git a/First Principles/Assets/Scripts/UI/GridRendererUI.cs b/First Principles/Assets/Scripts/UI/GridRendererUI.cs index 3037ca6..586a656 100644 --- a/First Principles/Assets/Scripts/UI/GridRendererUI.cs +++ b/First Principles/Assets/Scripts/UI/GridRendererUI.cs @@ -20,6 +20,8 @@ public class GridRendererUI : Graphic private float height; private float cellWidth; private float cellHeight; + private float _meshXMin; + private float _meshYMin; private LabelManager labelManager; @@ -50,8 +52,12 @@ protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); - width = rectTransform.rect.width; - height = rectTransform.rect.height; + Rect r = rectTransform.rect; + width = r.width; + height = r.height; + // Vertices were authored for bottom-left origin; centered/stretched pivots shift rect.xMin/yMin — offset so grid matches curve/labels. + _meshXMin = r.xMin; + _meshYMin = r.yMin; cellWidth = width / (float)gridSize.x; cellHeight = height / (float)gridSize.y; @@ -78,32 +84,34 @@ private void DrawCell(int x, int y, int index, VertexHelper vh) UIVertex vertex = UIVertex.simpleVert; vertex.color = outsideLine; - vertex.position = new Vector3(xPos, yPos); + float bx = _meshXMin + xPos; + float by = _meshYMin + yPos; + vertex.position = new Vector3(bx, by); vh.AddVert(vertex); - vertex.position = new Vector3(xPos, yPos + cellHeight); + vertex.position = new Vector3(bx, by + cellHeight); vh.AddVert(vertex); - vertex.position = new Vector3(xPos + cellWidth, yPos + cellHeight); + vertex.position = new Vector3(bx + cellWidth, by + cellHeight); vh.AddVert(vertex); - vertex.position = new Vector3(xPos + cellWidth, yPos); + vertex.position = new Vector3(bx + cellWidth, by); vh.AddVert(vertex); float widthSqr = Mathf.Pow(thickness, 2); float distanceSqr = widthSqr / 2; float distance = Mathf.Sqrt(distanceSqr); - vertex.position = new Vector3(xPos + distance, yPos + distance); + vertex.position = new Vector3(bx + distance, by + distance); vh.AddVert(vertex); - vertex.position = new Vector3(xPos + distance, yPos + (cellHeight - distance)); + vertex.position = new Vector3(bx + distance, by + (cellHeight - distance)); vh.AddVert(vertex); - vertex.position = new Vector3(xPos + (cellWidth - distance), yPos + (cellHeight - distance)); + vertex.position = new Vector3(bx + (cellWidth - distance), by + (cellHeight - distance)); vh.AddVert(vertex); - vertex.position = new Vector3(xPos + (cellWidth - distance), yPos + distance); + vertex.position = new Vector3(bx + (cellWidth - distance), by + distance); vh.AddVert(vertex); int offset = index * 8; @@ -127,25 +135,26 @@ private void DrawCell(int x, int y, int index, VertexHelper vh) private void DrawCenterLine(int index, VertexHelper vh) { - float width = rectTransform.rect.width; - float height = rectTransform.rect.height; + float cx = _meshXMin; + float cy = _meshYMin; float centerLineOffset = centerLineThickness / 2; UIVertex vertex = UIVertex.simpleVert; vertex.color = centerLine; + float midY = cy + height * 0.5f; //Horizontal Line - vertex.position = new Vector3(0, (height / 2) - centerLineOffset); + vertex.position = new Vector3(cx, midY - centerLineOffset); vh.AddVert(vertex); - vertex.position = new Vector3(0, (height / 2) + centerLineOffset); + vertex.position = new Vector3(cx, midY + centerLineOffset); vh.AddVert(vertex); - vertex.position = new Vector3(width, (height / 2) + centerLineOffset); + vertex.position = new Vector3(cx + width, midY + centerLineOffset); vh.AddVert(vertex); - vertex.position = new Vector3(width, (height / 2) - centerLineOffset); + vertex.position = new Vector3(cx + width, midY - centerLineOffset); vh.AddVert(vertex); int offset = index * 8; @@ -153,17 +162,18 @@ private void DrawCenterLine(int index, VertexHelper vh) vh.AddTriangle(offset + 0, offset + 1, offset + 2); vh.AddTriangle(offset + 2, offset + 3, offset + 0); + float midX = cx + width * 0.5f; //Vertical Line - vertex.position = new Vector3((width / 2) - centerLineOffset, 0); + vertex.position = new Vector3(midX - centerLineOffset, cy); vh.AddVert(vertex); - vertex.position = new Vector3((width / 2) - centerLineOffset, height); + vertex.position = new Vector3(midX - centerLineOffset, cy + height); vh.AddVert(vertex); - vertex.position = new Vector3((width / 2) + centerLineOffset, height); + vertex.position = new Vector3(midX + centerLineOffset, cy + height); vh.AddVert(vertex); - vertex.position = new Vector3((width / 2) + centerLineOffset, 0); + vertex.position = new Vector3(midX + centerLineOffset, cy); vh.AddVert(vertex); vh.AddTriangle(offset + 4, offset + 5, offset + 6); diff --git a/First Principles/Assets/Scripts/UI/LabelManager.cs b/First Principles/Assets/Scripts/UI/LabelManager.cs index 134eb50..a8619f6 100644 --- a/First Principles/Assets/Scripts/UI/LabelManager.cs +++ b/First Principles/Assets/Scripts/UI/LabelManager.cs @@ -40,6 +40,8 @@ public class LabelManager : MonoBehaviour private float _lastTransD = float.NaN; private FunctionType _lastFunctionTypeForXAxis = (FunctionType)(-1); + private Vector2 _lastGridPixelSize = Vector2.zero; + private void Awake() { gridRenderer = FindAnyObjectByType(); @@ -48,6 +50,16 @@ private void Awake() private void Start() { GenerateLabels(); + if (gridRenderer != null) + _lastGridPixelSize = RectSize(gridRenderer.rectTransform); + } + + private static Vector2 RectSize(RectTransform rt) + { + if (rt == null) + return Vector2.zero; + var r = rt.rect; + return new Vector2(r.width, r.height); } private void LateUpdate() @@ -56,6 +68,17 @@ private void LateUpdate() if (plotter == null) return; + if (gridRenderer != null) + { + Vector2 gridPx = RectSize(gridRenderer.rectTransform); + if (gridPx.x > 16f && gridPx.y > 16f && + (gridPx - _lastGridPixelSize).sqrMagnitude > 36f) + { + _lastGridPixelSize = gridPx; + GenerateLabels(); + } + } + float mid = plotter.VerticalAxisLabelPivot; float sc = plotter.VerticalAxisLabelScale; diff --git a/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs b/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs index e087821..3103dbb 100644 --- a/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs +++ b/First Principles/Assets/Scripts/UI/MenuTutorialOverlay.cs @@ -208,7 +208,7 @@ private static string DefaultBodyEnglish() "Move along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\n" + "Controls\n" + "• Move — arrows / WASD, or on a phone hold the left / right half of the screen.\n" + - "• Jump — Space, or swipe up on a phone. You jump from solid platforms.\n\n" + + "• Jump — Space, or on a phone tap with a second finger while holding left/right. You jump from solid platforms.\n\n" + "The two curves\n" + "• Main curve — the function you walk on.\n" + "• Derivative \\(f'\\) — slope information; it’s drawn as a second line.\n\n" + diff --git a/First Principles/Assets/Scripts/UI/MobileInputBridge.cs b/First Principles/Assets/Scripts/UI/MobileInputBridge.cs index 7a1fef8..68f5eb5 100644 --- a/First Principles/Assets/Scripts/UI/MobileInputBridge.cs +++ b/First Principles/Assets/Scripts/UI/MobileInputBridge.cs @@ -20,11 +20,12 @@ public static bool ConsumeJump() return true; } - /// Clears swipe/jump queue and axis holds after onboarding overlays or before unlocking control. + /// Clears jump queue, axis holds, and auxiliary touch ids after overlays or before unlocking control. public static void ClearTouchRouting() { JumpQueued = false; MobileHoldAxis.Clear(); + GameplayScreenTouchZones.ClearAuxiliaryPointerState(); } } diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset index 3faafa4..fe264f6 100644 --- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset +++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset @@ -972,6 +972,201 @@ MonoBehaviour: m_XAdvance: 0 m_YAdvance: 0 m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 854 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -9.448242 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 871 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 827 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.5537109 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 869 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 836 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.5537109 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 869 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 854 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -7.4746094 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 869 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 855 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -4.1152344 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 869 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 872 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -3.6113281 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 869 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 888 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.6376953 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 877 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 888 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 882 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 65966 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 888 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -1.2177734 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 886 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 0 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 888 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -2.3095703 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 889 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1133903872 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 856 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -2.477539 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 836 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 2003134806 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 856 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -2.7714844 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 855 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 1141604352 + - m_FirstAdjustmentRecord: + m_GlyphIndex: 856 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: -2.7714844 + m_YAdvance: 0 + m_SecondAdjustmentRecord: + m_GlyphIndex: 861 + m_GlyphValueRecord: + m_XPlacement: 0 + m_YPlacement: 0 + m_XAdvance: 0 + m_YAdvance: 0 + m_FeatureLookupFlags: 67 m_MarkToBaseAdjustmentRecords: [] m_MarkToMarkAdjustmentRecords: [] m_ShouldReimportFontFeatures: 0 @@ -994,6 +1189,132 @@ MonoBehaviour: - {fileID: 0} - {fileID: 0} - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} m_FontWeightTable: - regularTypeface: {fileID: 0} italicTypeface: {fileID: 0} From 8650104bfc0542df3ebbdefd62c590cf33b4a925 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:11:33 -0400 Subject: [PATCH 06/14] Fixed Mobile Controls --- .../Resources/PerformanceTestRunInfo.json | 1 + .../PerformanceTestRunInfo.json.meta | 7 +++++ .../Resources/PerformanceTestRunSettings.json | 1 + .../PerformanceTestRunSettings.json.meta | 7 +++++ .../Scripts/Functions/FunctionPlotter.cs | 12 ++++++- .../Assets/Scripts/Game/LevelManager.cs | 3 ++ .../Scripts/UI/GameplayScreenTouchZones.cs | 31 +++++++++++++++++-- .../LiberationSans SDF - Fallback.asset | 9 ++++++ 8 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 First Principles/Assets/Resources/PerformanceTestRunInfo.json create mode 100644 First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta create mode 100644 First Principles/Assets/Resources/PerformanceTestRunSettings.json create mode 100644 First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json b/First Principles/Assets/Resources/PerformanceTestRunInfo.json new file mode 100644 index 0000000..0ea17c0 --- /dev/null +++ b/First Principles/Assets/Resources/PerformanceTestRunInfo.json @@ -0,0 +1 @@ +{"TestSuite":"","Date":0,"Player":{"Development":false,"ScreenWidth":0,"ScreenHeight":0,"ScreenRefreshRate":0,"Fullscreen":false,"Vsync":0,"AntiAliasing":0,"Batchmode":false,"RenderThreadingMode":"MultiThreaded","MtRendering":false,"GraphicsJobs":false,"GpuSkinning":false,"Platform":"","ColorSpace":"","AnisotropicFiltering":"","BlendWeights":"","GraphicsApi":"","ScriptingBackend":"IL2CPP","AndroidTargetSdkVersion":"AndroidApiLevelAuto","AndroidBuildSystem":"Gradle","BuildTarget":"iOS","StereoRenderingPath":"MultiPass"},"Hardware":{"OperatingSystem":"","DeviceModel":"","DeviceName":"","ProcessorType":"","ProcessorCount":0,"GraphicsDeviceName":"","SystemMemorySizeMB":0},"Editor":{"Version":"6000.4.0f1","Branch":"6000.4/staging","Changeset":"8cf496087c8f","Date":1773430047},"Dependencies":["com.unity.2d.animation@14.0.3","com.unity.2d.pixel-perfect@5.1.1","com.unity.2d.psdimporter@13.0.2","com.unity.2d.sprite@1.0.0","com.unity.2d.spriteshape@14.0.1","com.unity.2d.tilemap@1.0.0","com.unity.ai.navigation@2.0.11","com.unity.collab-proxy@2.11.4","com.unity.ide.rider@3.0.39","com.unity.ide.visualstudio@2.0.27","com.unity.ide.vscode@1.2.4","com.unity.inputsystem@1.16.0","com.unity.multiplayer.center@1.0.1","com.unity.test-framework@1.6.0","com.unity.timeline@1.8.11","com.unity.ugui@2.0.0","com.unity.modules.accessibility@1.0.0","com.unity.modules.adaptiveperformance@1.0.0","com.unity.modules.ai@1.0.0","com.unity.modules.androidjni@1.0.0","com.unity.modules.animation@1.0.0","com.unity.modules.assetbundle@1.0.0","com.unity.modules.audio@1.0.0","com.unity.modules.cloth@1.0.0","com.unity.modules.director@1.0.0","com.unity.modules.imageconversion@1.0.0","com.unity.modules.imgui@1.0.0","com.unity.modules.jsonserialize@1.0.0","com.unity.modules.particlesystem@1.0.0","com.unity.modules.physics@1.0.0","com.unity.modules.physics2d@1.0.0","com.unity.modules.screencapture@1.0.0","com.unity.modules.terrain@1.0.0","com.unity.modules.terrainphysics@1.0.0","com.unity.modules.tilemap@1.0.0","com.unity.modules.ui@1.0.0","com.unity.modules.uielements@1.0.0","com.unity.modules.umbra@1.0.0","com.unity.modules.unityanalytics@1.0.0","com.unity.modules.unitywebrequest@1.0.0","com.unity.modules.unitywebrequestassetbundle@1.0.0","com.unity.modules.unitywebrequestaudio@1.0.0","com.unity.modules.unitywebrequesttexture@1.0.0","com.unity.modules.unitywebrequestwww@1.0.0","com.unity.modules.vectorgraphics@1.0.0","com.unity.modules.vehicles@1.0.0","com.unity.modules.video@1.0.0","com.unity.modules.vr@1.0.0","com.unity.modules.wind@1.0.0","com.unity.modules.xr@1.0.0","com.unity.modules.subsystems@1.0.0","com.unity.modules.hierarchycore@1.0.0","com.unity.ext.nunit@2.0.5","com.unity.2d.common@13.0.1","com.unity.mathematics@1.3.3","com.unity.collections@6.4.0","com.unity.burst@1.8.28","com.unity.nuget.mono-cecil@1.11.6","com.unity.test-framework.performance@3.2.0"],"Results":[]} \ No newline at end of file diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta b/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta new file mode 100644 index 0000000..d4d9733 --- /dev/null +++ b/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f02f9f9335b0a4160940f1e6540c4b60 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json b/First Principles/Assets/Resources/PerformanceTestRunSettings.json new file mode 100644 index 0000000..49438ae --- /dev/null +++ b/First Principles/Assets/Resources/PerformanceTestRunSettings.json @@ -0,0 +1 @@ +{"MeasurementCount":-1} \ No newline at end of file diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta b/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta new file mode 100644 index 0000000..bf80355 --- /dev/null +++ b/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbc686885050d46718f6c481c235bcd1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs index a239003..d4ebbb0 100644 --- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs +++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs @@ -60,6 +60,9 @@ public class FunctionPlotter : MonoBehaviour [Tooltip("Level mode: horizontally scale the domain window [xStart,xEnd] so it fills most of the grid.")] public bool autoScaleHorizontal = true; + [Tooltip("Graphing calculator: match vertical scale to horizontal zoom so one grid column and one row span the same plotter x/y units (pinch/Scale zoom x and y together). Ignored for polar plot styles.")] + public bool lockVerticalPlotScaleToHorizontalWindow = false; + [Tooltip("Fraction of half the grid width (from center) used by the fitted x-window.")] [Range(0.38f, 0.92f)] public float horizontalFillFraction = 0.74f; @@ -153,7 +156,8 @@ int ComputeGraphRevealParamsHash() { int a = HashCode.Combine(functionType, xStart, xEnd, step, transA, transK); int b = HashCode.Combine(transC, transD, power, baseN, customExpression ?? ""); - int c = HashCode.Combine(autoScaleVertical, autoScaleHorizontal, verticalFillFraction, horizontalFillFraction); + int c = HashCode.Combine(autoScaleVertical, autoScaleHorizontal, lockVerticalPlotScaleToHorizontalWindow, + verticalFillFraction, horizontalFillFraction); return HashCode.Combine(a, b, c); } @@ -428,6 +432,12 @@ public void ComputeGraph(FunctionType functionType, float transA, float transK, ComputeVerticalAutoFit(lineRenderer.gridSize.y, fLo, fHi); ComputeHorizontalAutoFit(lineRenderer.gridSize.x, xStart, xEnd); + if (lockVerticalPlotScaleToHorizontalWindow && !IsPolarPlotStyle(functionType)) + { + _autoMid = 0f; + _autoScale = _autoScaleX; + } + // --- Pass 2: build polylines with display mapping --- for (float i = xStart; i <= xEnd; i += step) { diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index c23017c..57fde17 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -521,6 +521,8 @@ private void EnterGraphCalculatorMode() functionPlotter.autoScaleVertical = false; // Stretch [xStart,xEnd] across the grid so pinch / Scale update _autoMidX/_autoScaleX; axis ticks track (LabelManager). functionPlotter.autoScaleHorizontal = true; + // Pinch / Scale: same plotter units per grid row as per column (square math window). + functionPlotter.lockVerticalPlotScaleToHorizontalWindow = true; functionPlotter.showWindTunnelBackdrop = false; if (curveRenderer != null) @@ -2714,6 +2716,7 @@ private void ApplyLevelTheme(LevelDefinition def) functionPlotter.verticalFillFraction = def.graphVerticalFillFraction; functionPlotter.autoScaleHorizontal = def.autoFitGraphHorizontal; functionPlotter.horizontalFillFraction = def.graphHorizontalFillFraction; + functionPlotter.lockVerticalPlotScaleToHorizontalWindow = false; functionPlotter.transA = def.transA; functionPlotter.transK = def.transK; diff --git a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs index 7443e08..d2b63b3 100644 --- a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs +++ b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs @@ -59,6 +59,8 @@ public static void EnsureForGameCanvas(Transform canvasTransform) _instance = go.AddComponent(); } + _instance.EnsureRaycastGraphic(); + // Must sit above the full-screen graph stack (GraphicRaycaster hits top-first). Under _SafeContent // as first sibling put this layer *behind* GraphContainer — touches never reached gameplay. ReparentTouchLayerAboveGraph(canvasTransform, rt); @@ -153,6 +155,23 @@ private static void DestroyLegacyButtonBar(Transform canvasTransform) UnityEngine.Object.Destroy(t.gameObject); } + private void Awake() + { + EnsureRaycastGraphic(); + } + + private void EnsureRaycastGraphic() + { + var img = GetComponent(); + if (img == null) + { + img = gameObject.AddComponent(); + img.color = new Color(0f, 0f, 0f, 0f); + } + + img.raycastTarget = true; + } + private void OnDestroy() { if (_instance == this) @@ -203,10 +222,16 @@ private void EndPointer(int pointerId) _pointerSide.Remove(pointerId); } - /// Clears jump-only pointer bookkeeping when runs. + /// + /// Clears pointer bookkeeping when runs. + /// Must match — otherwise _pointerSide.Count >= 1 stays true while axis is 0 + /// and every new touch is misclassified as a second-finger jump (movement appears dead). + /// internal static void ClearAuxiliaryPointerState() { - if (_instance != null) - _instance._jumpOnlyPointerIds.Clear(); + if (_instance == null) + return; + _instance._jumpOnlyPointerIds.Clear(); + _instance._pointerSide.Clear(); } } diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset index fe264f6..2ad2e8c 100644 --- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset +++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset @@ -1315,6 +1315,15 @@ MonoBehaviour: - {fileID: 0} - {fileID: 0} - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} m_FontWeightTable: - regularTypeface: {fileID: 0} italicTypeface: {fileID: 0} From 4a19b0a78d9ff3263b03979d6ae42e19face297f Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:32:34 -0400 Subject: [PATCH 07/14] Updated --- .../Assets/Resources/Localization/en.txt | 7 +- .../Resources/PerformanceTestRunInfo.json | 1 - .../PerformanceTestRunInfo.json.meta | 7 - .../Resources/PerformanceTestRunSettings.json | 1 - .../PerformanceTestRunSettings.json.meta | 7 - .../Scripts/Game/DerivativePopAnimator.cs | 41 ++- .../Assets/Scripts/Game/GameLevelCatalog.cs | 11 +- .../Game/GraphCalculatorAnalysisControls.cs | 11 + .../Game/GraphCalculatorEquationPanel.cs | 79 ++++- .../Scripts/Game/LearningArticleLibrary.cs | 4 +- .../Assets/Scripts/Game/LevelManager.cs | 283 ++++++++++++++---- .../Scripts/Game/LevelSelectController.cs | 93 ++++++ .../Scripts/Game/PlayerControllerUI2D.cs | 8 + .../Scripts/Game/StageRoleplayLibrary.cs | 4 +- .../Assets/Scripts/UI/DerivRendererUI.cs | 5 +- .../Scripts/UI/GameplayScreenTouchZones.cs | 34 ++- .../LiberationSans SDF - Fallback.asset | 9 + 17 files changed, 492 insertions(+), 113 deletions(-) delete mode 100644 First Principles/Assets/Resources/PerformanceTestRunInfo.json delete mode 100644 First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta delete mode 100644 First Principles/Assets/Resources/PerformanceTestRunSettings.json delete mode 100644 First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index 5b88d5d..e7886e7 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -8,6 +8,7 @@ level_select.cat.integration=Multivar & integration level_select.cat.engineering=Engineering level_select.cat.ap_bc=AP Calculus BC & Physics C level_select.cat.aerospace=Aerospace +level_select.cat.astrophysics=Astrophysics level_select.cat.economics=Economics level_select.cat.transforms=Transforms level_select.cat.final_boss=Final boss @@ -21,11 +22,14 @@ ui.language=Language ui.tap_change_language=Tap to change ui.stage_intro_hint=Tap anywhere to continue ui.close=Close +ui.coming_soon=Coming soon! +ui.coming_soon_tap=Tap anywhere to close ui.math_concepts=Math concepts ui.jump=Jump ui.move=Move ui.keyboard_hint_mobile=(keyboard: arrows / Space) hud.stage=STAGE +hud.points=PTS controls.mobile=Left hold ◀ · Right hold ▶ · 2nd finger jump (keyboard: arrows / Space) controls.guide_overlay=Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nWhile holding, tap with another finger — jump\n\nKeyboard: Arrow keys move · Space jumps controls.desktop=Move · Jump Space @@ -52,7 +56,7 @@ graph.polar.param_k=k (θ scale) graph.polar.param_c=C (r shift) graph.polar.param_d=D (θ phase / axis shift) graph.polar.line4=A={0}  k={1}  C={2}  D={3}   θ∈[{4},{5}] -graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale & pinch zoom the window. +graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale · pinch zoom the window. # Prepended to story text for every Aerospace stage (indices 35–41). aerospace.story_drag_polar_preamble=Drag polar refresher (every Aerospace stage)\nParasitic (zero-lift) drag — skin friction, form drag, interference lumped as CD0 in the parabolic model (roughly not the part that grows with lift).\nInduced drag — the cost of making lift: trailing vortices add ~ K CL² (higher CL / tighter turns → more induced).\nOverall drag polarCD = CD0 + K CL²: an upward-opening parabola in CL; min-drag CL sits between “too slow / high α” and “too fast / low α” for real missions. menu.tutorial_button=How to play @@ -124,3 +128,4 @@ level.55=Big O: O(n log n) — n log n growth level.56=Big O: O(n²) — quadratic growth level.57=Big O: O(n³) — cubic growth level.58=Big O: O(2ⁿ) — exponential (base 2) +level.59=Astrophysics: Hohmann transfer diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json b/First Principles/Assets/Resources/PerformanceTestRunInfo.json deleted file mode 100644 index 0ea17c0..0000000 --- a/First Principles/Assets/Resources/PerformanceTestRunInfo.json +++ /dev/null @@ -1 +0,0 @@ -{"TestSuite":"","Date":0,"Player":{"Development":false,"ScreenWidth":0,"ScreenHeight":0,"ScreenRefreshRate":0,"Fullscreen":false,"Vsync":0,"AntiAliasing":0,"Batchmode":false,"RenderThreadingMode":"MultiThreaded","MtRendering":false,"GraphicsJobs":false,"GpuSkinning":false,"Platform":"","ColorSpace":"","AnisotropicFiltering":"","BlendWeights":"","GraphicsApi":"","ScriptingBackend":"IL2CPP","AndroidTargetSdkVersion":"AndroidApiLevelAuto","AndroidBuildSystem":"Gradle","BuildTarget":"iOS","StereoRenderingPath":"MultiPass"},"Hardware":{"OperatingSystem":"","DeviceModel":"","DeviceName":"","ProcessorType":"","ProcessorCount":0,"GraphicsDeviceName":"","SystemMemorySizeMB":0},"Editor":{"Version":"6000.4.0f1","Branch":"6000.4/staging","Changeset":"8cf496087c8f","Date":1773430047},"Dependencies":["com.unity.2d.animation@14.0.3","com.unity.2d.pixel-perfect@5.1.1","com.unity.2d.psdimporter@13.0.2","com.unity.2d.sprite@1.0.0","com.unity.2d.spriteshape@14.0.1","com.unity.2d.tilemap@1.0.0","com.unity.ai.navigation@2.0.11","com.unity.collab-proxy@2.11.4","com.unity.ide.rider@3.0.39","com.unity.ide.visualstudio@2.0.27","com.unity.ide.vscode@1.2.4","com.unity.inputsystem@1.16.0","com.unity.multiplayer.center@1.0.1","com.unity.test-framework@1.6.0","com.unity.timeline@1.8.11","com.unity.ugui@2.0.0","com.unity.modules.accessibility@1.0.0","com.unity.modules.adaptiveperformance@1.0.0","com.unity.modules.ai@1.0.0","com.unity.modules.androidjni@1.0.0","com.unity.modules.animation@1.0.0","com.unity.modules.assetbundle@1.0.0","com.unity.modules.audio@1.0.0","com.unity.modules.cloth@1.0.0","com.unity.modules.director@1.0.0","com.unity.modules.imageconversion@1.0.0","com.unity.modules.imgui@1.0.0","com.unity.modules.jsonserialize@1.0.0","com.unity.modules.particlesystem@1.0.0","com.unity.modules.physics@1.0.0","com.unity.modules.physics2d@1.0.0","com.unity.modules.screencapture@1.0.0","com.unity.modules.terrain@1.0.0","com.unity.modules.terrainphysics@1.0.0","com.unity.modules.tilemap@1.0.0","com.unity.modules.ui@1.0.0","com.unity.modules.uielements@1.0.0","com.unity.modules.umbra@1.0.0","com.unity.modules.unityanalytics@1.0.0","com.unity.modules.unitywebrequest@1.0.0","com.unity.modules.unitywebrequestassetbundle@1.0.0","com.unity.modules.unitywebrequestaudio@1.0.0","com.unity.modules.unitywebrequesttexture@1.0.0","com.unity.modules.unitywebrequestwww@1.0.0","com.unity.modules.vectorgraphics@1.0.0","com.unity.modules.vehicles@1.0.0","com.unity.modules.video@1.0.0","com.unity.modules.vr@1.0.0","com.unity.modules.wind@1.0.0","com.unity.modules.xr@1.0.0","com.unity.modules.subsystems@1.0.0","com.unity.modules.hierarchycore@1.0.0","com.unity.ext.nunit@2.0.5","com.unity.2d.common@13.0.1","com.unity.mathematics@1.3.3","com.unity.collections@6.4.0","com.unity.burst@1.8.28","com.unity.nuget.mono-cecil@1.11.6","com.unity.test-framework.performance@3.2.0"],"Results":[]} \ No newline at end of file diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta b/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta deleted file mode 100644 index d4d9733..0000000 --- a/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f02f9f9335b0a4160940f1e6540c4b60 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json b/First Principles/Assets/Resources/PerformanceTestRunSettings.json deleted file mode 100644 index 49438ae..0000000 --- a/First Principles/Assets/Resources/PerformanceTestRunSettings.json +++ /dev/null @@ -1 +0,0 @@ -{"MeasurementCount":-1} \ No newline at end of file diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta b/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta deleted file mode 100644 index bf80355..0000000 --- a/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: dbc686885050d46718f6c481c235bcd1 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs b/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs index e42e80e..705b8c6 100644 --- a/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs +++ b/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs @@ -14,17 +14,23 @@ public class DerivativePopAnimator : MonoBehaviour [SerializeField] private float thicknessMultiplier = 1.8f; [SerializeField] private float popDurationSeconds = 0.25f; - private float baseThickness; - private Color baseColor; + /// + /// Baseline stroke width for f′ (not the momentary boosted value). Stopping a pop mid-animation used to leave + /// elevated; the next pop then multiplied that again — runaway “thick line”. + /// + private float _restThickness = DerivRendererUI.DefaultThicknessPixels; public void SetTarget(DerivRendererUI target) { this.target = target; - if (this.target != null) - { - baseThickness = this.target.thickness; - baseColor = this.target.color; - } + SyncRestThicknessFromTarget(); + } + + /// Call after resetting on level load / theme apply. + public void SyncRestThicknessFromTarget() + { + if (target != null) + _restThickness = Mathf.Max(0.25f, target.thickness); } public void Pop(Color popColor) @@ -33,7 +39,12 @@ public void Pop(Color popColor) return; if (popRoutine != null) + { StopCoroutine(popRoutine); + popRoutine = null; + // Interrupted mid-pulse — snap back so the next pop does not compound thickness. + target.thickness = _restThickness; + } popRoutine = StartCoroutine(PopRoutine(popColor)); } @@ -42,16 +53,16 @@ private IEnumerator PopRoutine(Color popColor) { float elapsed = 0f; - baseThickness = target.thickness; - baseColor = target.color; + Color colorBeforePop = target.color; Color c = popColor; if (c.a <= 0f) c.a = 1f; target.color = c; - float startThickness = baseThickness; - float endThickness = baseThickness * thicknessMultiplier; + float restT = _restThickness; + float startThickness = restT; + float endThickness = restT * thicknessMultiplier; while (elapsed < popDurationSeconds * 0.5f) { @@ -67,12 +78,16 @@ private IEnumerator PopRoutine(Color popColor) { settleT += Time.deltaTime; float t = Mathf.Clamp01(settleT / (popDurationSeconds * 0.5f)); - target.thickness = Mathf.Lerp(fromThickness, startThickness, t); + target.thickness = Mathf.Lerp(fromThickness, restT, t); yield return null; } + target.thickness = restT; + var restored = target.color; - restored.a = baseColor.a; + restored.a = colorBeforePop.a; target.color = restored; + + popRoutine = null; } } diff --git a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs index 2364c05..d856e7c 100644 --- a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs +++ b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs @@ -94,11 +94,19 @@ public static class GameLevelCatalog "Big O: O(n log n) — n log n growth", "Big O: O(n²) — quadratic growth", "Big O: O(n³) — cubic growth", - "Big O: O(2ⁿ) — exponential (base 2)" + "Big O: O(2ⁿ) — exponential (base 2)", + // Placeholder: listed in Level Select but not built in LevelManager yet (see IsComingSoonLevel). + "Astrophysics: Hohmann transfer" }; public static int LevelCount => DisplayNames.Length; + /// Level index reserved for a future stage; shows “coming soon” instead of loading Game. + public const int HohmannTransferComingSoonLevelIndex = 59; + + public static bool IsComingSoonLevel(int index) => + index == HohmannTransferComingSoonLevelIndex; + /// /// Grouped picker on the Level Select scene (indices must match / ). /// @@ -109,6 +117,7 @@ public static class GameLevelCatalog new LevelSelectCategory("level_select.cat.engineering", "Engineering", 14, 16), new LevelSelectCategory("level_select.cat.ap_bc", "AP Calculus BC & Physics C", 17, 34), new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 35, 41), + new LevelSelectCategory("level_select.cat.astrophysics", "Astrophysics", 59, 59), new LevelSelectCategory("level_select.cat.economics", "Economics", 42, 43), new LevelSelectCategory("level_select.cat.transforms", "Transforms", 44, 45), new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 50, 50), diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs index 5834069..4b3afae 100644 --- a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs +++ b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs @@ -340,4 +340,15 @@ void DestroyUiButtons() derivButton = null; integralButton = null; } + + /// + /// Top edge of the Deriv / ∫ row in the same bottom‑anchored space as + /// (anchoredPosition.y + button height). + /// + public static float DerivativeIntegralRowTopFromBottom(float transRowBottomY, bool tablet) + { + float h = tablet ? 108f : 100f; + float row2Bottom = transRowBottomY + h + 10f; + return row2Bottom + h * 0.92f; + } } diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs index 2e4c23b..56e4c36 100644 --- a/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs +++ b/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs @@ -8,14 +8,18 @@ /// public static class GraphCalculatorEquationPanel { - private const string RootName = "GraphicCalculatorEquationRoot"; + public const string EquationRootObjectName = "GraphicCalculatorEquationRoot"; + private const string RootName = EquationRootObjectName; private const string LegacyRootName = "FaxasEquationInputRoot"; private static TextMeshProUGUI labelTmp; private static TextMeshProUGUI placeholderTmp; private static TextMeshProUGUI statusTmp; - public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMeshProUGUI typographyReference, float bottomY, float panelHeight) + /// When is null: anchored Y from bottom of parent (legacy placement). + /// When set: panel is top-anchored directly under this banner (graphing calculator). + public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMeshProUGUI typographyReference, float bottomY, float panelHeight, + RectTransform layoutBelowStory = null, float gapBelowStory = 10f) { if (parent == null || plotter == null) return; @@ -24,6 +28,11 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes if (existing != null) { ApplyEquationPanelFontAndWeight(existing, typographyReference, plotter); + var ert = existing.GetComponent(); + if (layoutBelowStory != null) + ApplyEquationPanelLayoutBelowStory(ert, layoutBelowStory, gapBelowStory, panelHeight); + else + ApplyEquationPanelBottomLayout(ert, parent, bottomY, panelHeight); return; } @@ -32,6 +41,11 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes { legacyRoot.name = RootName; ApplyEquationPanelFontAndWeight(legacyRoot, typographyReference, plotter); + var legacyRt = legacyRoot.GetComponent(); + if (layoutBelowStory != null) + ApplyEquationPanelLayoutBelowStory(legacyRt, layoutBelowStory, gapBelowStory, panelHeight); + else + ApplyEquationPanelBottomLayout(legacyRt, parent, bottomY, panelHeight); return; } @@ -40,12 +54,17 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes var root = new GameObject(RootName); var rt = root.AddComponent(); - rt.SetParent(parent, false); - rt.anchorMin = new Vector2(0.5f, 0f); - rt.anchorMax = new Vector2(0.5f, 0f); - rt.pivot = new Vector2(0.5f, 0f); - rt.anchoredPosition = new Vector2(0f, bottomY); - rt.sizeDelta = new Vector2(w, panelHeight); + rt.SetParent(layoutBelowStory != null ? layoutBelowStory.parent : parent, false); + if (layoutBelowStory != null) + ApplyEquationPanelLayoutBelowStory(rt, layoutBelowStory, gapBelowStory, panelHeight); + else + { + rt.anchorMin = new Vector2(0.5f, 0f); + rt.anchorMax = new Vector2(0.5f, 0f); + rt.pivot = new Vector2(0.5f, 0f); + rt.anchoredPosition = new Vector2(0f, bottomY); + rt.sizeDelta = new Vector2(w, panelHeight); + } var bg = root.AddComponent(); RuntimeUiPolish.UseRoundedSliced(bg); @@ -53,13 +72,13 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes bg.raycastTarget = true; var labelGo = new GameObject("Label"); - var lrt = labelGo.AddComponent(); - lrt.SetParent(rt, false); - lrt.anchorMin = new Vector2(0f, 1f); - lrt.anchorMax = new Vector2(0f, 1f); - lrt.pivot = new Vector2(0f, 1f); - lrt.anchoredPosition = new Vector2(tablet ? 16f : 12f, -6f); - lrt.sizeDelta = new Vector2(220f, 28f); + var labelRt = labelGo.AddComponent(); + labelRt.SetParent(rt, false); + labelRt.anchorMin = new Vector2(0f, 1f); + labelRt.anchorMax = new Vector2(0f, 1f); + labelRt.pivot = new Vector2(0f, 1f); + labelRt.anchoredPosition = new Vector2(tablet ? 16f : 12f, -6f); + labelRt.sizeDelta = new Vector2(220f, 28f); var label = labelGo.AddComponent(); label.text = LocalizationManager.Get("graph.label_fu", "f(u) ="); label.fontSize = UiTypography.Scale(tablet ? 26 : 24); @@ -266,4 +285,34 @@ static void ApplyStatusHintLayoutAndSize(TextMeshProUGUI status, RectTransform s srt.sizeDelta = new Vector2(-24f, 28f); } } + + /// Top-anchored panel flush under the intro banner (same horizontal stretch as ). + static void ApplyEquationPanelLayoutBelowStory(RectTransform eqRt, RectTransform storyRt, float gap, float panelHeight) + { + if (eqRt == null || storyRt == null) + return; + + eqRt.SetParent(storyRt.parent, false); + eqRt.anchorMin = storyRt.anchorMin; + eqRt.anchorMax = storyRt.anchorMax; + eqRt.pivot = new Vector2(0.5f, 1f); + eqRt.sizeDelta = new Vector2(0f, panelHeight); + float storyH = storyRt.sizeDelta.y; + eqRt.anchoredPosition = new Vector2(storyRt.anchoredPosition.x, storyRt.anchoredPosition.y - storyH - gap); + } + + static void ApplyEquationPanelBottomLayout(RectTransform eqRt, RectTransform parent, float bottomY, float panelHeight) + { + if (eqRt == null || parent == null) + return; + + bool tablet = DeviceLayout.IsTabletLike(); + float w = tablet ? 980f : 900f; + eqRt.SetParent(parent, false); + eqRt.anchorMin = new Vector2(0.5f, 0f); + eqRt.anchorMax = new Vector2(0.5f, 0f); + eqRt.pivot = new Vector2(0.5f, 0f); + eqRt.anchoredPosition = new Vector2(0f, bottomY); + eqRt.sizeDelta = new Vector2(w, panelHeight); + } } diff --git a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs index 90b79d4..71b73d1 100644 --- a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs +++ b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs @@ -14,7 +14,9 @@ public static class LearningArticleLibrary public static string GetLevelSelectArticleRichText() { string raw = LoadRawArticleForCurrentLanguage(); - return TmpLatex.Process(raw); + string processed = TmpLatex.Process(raw); + // MathArticle/*.txt used XML-style & for "&"; TMP does not decode entities. + return processed.Replace("&", "&"); } private static string LoadRawArticleForCurrentLanguage() diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 57fde17..33e38cb 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -54,6 +54,7 @@ public class LevelManager : MonoBehaviour private TextMeshProUGUI storyText; private TextMeshProUGUI stageHudText; + private TextMeshProUGUI scoreHudText; private TextMeshProUGUI controlsHintText; private int lastStageHudKey = int.MinValue; private Sprite cachedHudPanelSprite; @@ -67,6 +68,12 @@ public class LevelManager : MonoBehaviour private readonly List levels = new List(); private int currentLevelIndex; + private const int GameplayStartingScore = 100; + private const int DerivativeTouchPenaltyPoints = 5; + + /// Touch f′ penalty score (starts at each level). + private int gameplayScore = GameplayStartingScore; + /// How many stage boundary thresholds the player has already crossed (derivative pops). private int nextStageIndex; private List stageTriggerXGrid; @@ -132,9 +139,26 @@ private void OnLocalizationChanged() RefreshStageHudLocalizedForce(); if (graphCalculatorMode) + { RefreshStoryBannerForCurrentMode(null); + TightenGraphCalculatorStoryBanner(); + var canvas = FindAnyObjectByType(); + var safe = canvas != null ? MobileUiRoots.GetSafeContentParent(canvas.transform) as RectTransform : null; + var calcParent = safe != null ? safe : canvas?.transform as RectTransform; + float bridge = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset : 22f; + float transRow = bridge + 74f; + float eqBottom = GraphCalculatorEquationPanelBottomY(transRow); + if (functionPlotter != null && calcParent != null) + GraphCalculatorEquationPanel.Ensure(calcParent, functionPlotter, FindPrimaryEquationTmp(), eqBottom, 108f); + var paramTmp = GameObject.Find("GraphicCalculatorParamHint")?.GetComponent(); + LayoutGraphCalculatorParamHintBelowStory(paramTmp, storyText != null ? storyText.rectTransform : null, + DeviceLayout.IsTabletLike() ? 144f : 132f, 10f); + } else if (levels.Count > 0 && currentLevelIndex >= 0 && currentLevelIndex < levels.Count) RefreshStoryBannerForCurrentMode(levels[currentLevelIndex]); + + if (!graphCalculatorMode) + RefreshScoreHud(); } private void RefreshControlsHintLocalized() @@ -177,6 +201,7 @@ private void RefreshStageHudLocalizedForce() { lastStageHudKey = int.MinValue; RefreshStageHud(); + RefreshScoreHud(); } private void RefreshStoryBannerForCurrentMode(LevelDefinition def) @@ -188,7 +213,7 @@ private void RefreshStoryBannerForCurrentMode(LevelDefinition def) { storyText.text = TmpLatex.Process(LocalizationManager.Get("graph.calculator_intro", "Graphing calculator mode\n" + - "Type almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale & pinch zoom the window.")); + "Type almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale · pinch zoom the window.")); LocalizationManager.ApplyTextDirection(storyText); return; } @@ -271,12 +296,18 @@ private void SetupReferences() HideLegacyGraphTuningButtons(); EnsureRiemannRenderer(); var mainCanvas = FindAnyObjectByType(); - if (mainCanvas != null && !graphCalculatorMode) + // Always create the layer on phones/tablets; disable in graphing calculator so a later level load + // (or any code that re-runs Ensure) does not depend on "first scene entry was platformer". + if (mainCanvas != null && DeviceLayout.PreferOnScreenGameControls) + { GameplayScreenTouchZones.EnsureForGameCanvas(mainCanvas.transform); + GameplayScreenTouchZones.SetActiveForGameplayMode(!graphCalculatorMode); + } // Wire callbacks. playerController.SetDeathCallback(RestartCurrentLevel); playerController.SetFinishCallback(AdvanceLevel); + playerController.SetDerivativeLineGrazeScoringCallback(OnDerivativeLineGrazePenalty); if (derivRenderer != null) playerController.BindDerivativeRenderer(derivRenderer); ConfigureGameBackButtonDestination(); @@ -501,6 +532,7 @@ private void EnterGraphCalculatorMode() RefreshStoryBannerForCurrentMode(null); storyText.color = new Color(1f, 1f, 1f, 0.94f); storyText.fontStyle = FontStyles.Bold; + TightenGraphCalculatorStoryBanner(); } if (stageHudText != null && stageHudText.transform.parent != null) @@ -547,12 +579,13 @@ private void EnterGraphCalculatorMode() var hintParent = safe != null ? safe : canvas?.transform as RectTransform; float bridgeControls = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset : 22f; float transRowBottom = bridgeControls + 74f; + float equationPanelBottomY = GraphCalculatorEquationPanelBottomY(transRowBottom); var equationStyleRef = FindPrimaryEquationTmp(); if (equationStyleRef != null) equationStyleRef.fontStyle = FontStyles.Bold; - GraphCalculatorEquationPanel.Ensure(hintParent, functionPlotter, equationStyleRef, transRowBottom + 110f, 108f); + GraphCalculatorEquationPanel.Ensure(hintParent, functionPlotter, equationStyleRef, equationPanelBottomY, 108f); var transGo = GameObject.Find("TransButton"); var scaleGo = GameObject.Find("ScaleButton"); @@ -563,24 +596,18 @@ private void EnterGraphCalculatorMode() if (legacyHint != null) legacyHint.name = "GraphicCalculatorParamHint"; + bool tabletHint = DeviceLayout.IsTabletLike(); if (hintParent != null && GameObject.Find("GraphicCalculatorParamHint") == null) { var hintGo = new GameObject("GraphicCalculatorParamHint"); var hrt = hintGo.AddComponent(); hrt.SetParent(hintParent, false); - hrt.anchorMin = new Vector2(0.5f, 0f); - hrt.anchorMax = new Vector2(0.5f, 0f); - hrt.pivot = new Vector2(0.5f, 0f); - bool tablet = DeviceLayout.IsTabletLike(); - float up = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset + 312f : 318f; - hrt.anchoredPosition = new Vector2(0f, up); - hrt.sizeDelta = new Vector2(tablet ? 1040f : 960f, tablet ? 144f : 132f); paramHint = hintGo.AddComponent(); paramHint.richText = true; paramHint.textWrappingMode = TextWrappingModes.Normal; paramHint.overflowMode = TextOverflowModes.Overflow; - paramHint.fontSize = UiTypography.Scale(tablet ? 31 : 27); + paramHint.fontSize = UiTypography.Scale(tabletHint ? 31 : 27); paramHint.alignment = TextAlignmentOptions.Top; paramHint.color = new Color(0.9f, 0.93f, 0.98f, 0.96f); ApplyPrimaryUiTypography(paramHint, FindPrimaryEquationTmp(), outlineWidth: 0.12f, outlineAlpha: 0.45f); @@ -604,6 +631,9 @@ private void EnterGraphCalculatorMode() } } + LayoutGraphCalculatorParamHintBelowStory(paramHint, storyText != null ? storyText.rectTransform : null, + tabletHint ? 144f : 132f, 10f); + ApplyGraphCalculatorControlButtonTypography(transGo); ApplyGraphCalculatorControlButtonTypography(scaleGo); @@ -649,6 +679,46 @@ private static void ApplyGraphCalculatorControlButtonTypography(GameObject butto } } + /// Shrink the tall story placeholder so the intro sits at the top; height follows TMP preferred size. + void TightenGraphCalculatorStoryBanner() + { + if (storyText == null) + return; + + storyText.alignment = TextAlignmentOptions.Top; + Canvas.ForceUpdateCanvases(); + storyText.ForceMeshUpdate(); + float w = storyText.rectTransform.rect.width; + if (w < 48f) + w = Mathf.Max(320f, Screen.safeArea.width * 0.88f); + Vector2 pv = storyText.GetPreferredValues(storyText.text, w, 0f); + float h = Mathf.Clamp(pv.y + 14f, 52f, 280f); + storyText.rectTransform.sizeDelta = new Vector2(0f, h); + } + + /// Bottom Y for the f(u) panel so it sits just above the Deriv / ∫ row (matches ). + float GraphCalculatorEquationPanelBottomY(float transRowBottomY) + { + bool tablet = DeviceLayout.IsTabletLike(); + return GraphCalculatorAnalysisControls.DerivativeIntegralRowTopFromBottom(transRowBottomY, tablet) + 12f; + } + + /// Places the Trans / Scale hint under the intro banner (calculator mode). + static void LayoutGraphCalculatorParamHintBelowStory(TextMeshProUGUI hint, RectTransform storyRt, float blockHeight, float gap) + { + if (hint == null || storyRt == null) + return; + + RectTransform hrt = hint.rectTransform; + hrt.SetParent(storyRt.parent, false); + hrt.anchorMin = storyRt.anchorMin; + hrt.anchorMax = storyRt.anchorMax; + hrt.pivot = new Vector2(0.5f, 1f); + hrt.sizeDelta = new Vector2(0f, blockHeight); + hrt.anchoredPosition = new Vector2(storyRt.anchoredPosition.x, + storyRt.anchoredPosition.y - storyRt.sizeDelta.y - gap); + } + private static void LayoutCalculatorToolButtons(GameObject transGo, GameObject scaleGo, float anchoredBottomY) { var canvas = UnityEngine.Object.FindAnyObjectByType(); @@ -828,7 +898,8 @@ private void CreateGameplayHudIfNeeded() panelRt.pivot = new Vector2(0f, 1f); float topPad = DeviceLayout.PreferOnScreenGameControls ? 12f : 20f; panelRt.anchoredPosition = new Vector2(18f, -topPad); - panelRt.sizeDelta = new Vector2(440f, 88f); + bool wideHud = DeviceLayout.IsTabletLike(); + panelRt.sizeDelta = new Vector2(wideHud ? 620f : 560f, wideHud ? 92f : 88f); RuntimeUiPolish.ApplyDropShadow(panelRt, new Vector2(2f, -3f), 0.26f); var panelBg = panelGo.AddComponent(); @@ -856,10 +927,10 @@ private void CreateGameplayHudIfNeeded() var textGo = new GameObject("StageHud"); var textRt = textGo.AddComponent(); textRt.SetParent(panelGo.transform, false); - textRt.anchorMin = Vector2.zero; - textRt.anchorMax = Vector2.one; + textRt.anchorMin = new Vector2(0f, 0f); + textRt.anchorMax = new Vector2(0.54f, 1f); textRt.offsetMin = new Vector2(18f, 12f); - textRt.offsetMax = new Vector2(-16f, -14f); + textRt.offsetMax = new Vector2(-6f, -14f); var tmp = textGo.AddComponent(); tmp.richText = true; @@ -877,54 +948,74 @@ private void CreateGameplayHudIfNeeded() tmp.text = FormatStageHudLine(1, 1); stageHudText = tmp; + + var scoreGo = new GameObject("ScoreHud"); + var scoreRt = scoreGo.AddComponent(); + scoreRt.SetParent(panelGo.transform, false); + scoreRt.anchorMin = new Vector2(0.52f, 0f); + scoreRt.anchorMax = new Vector2(1f, 1f); + scoreRt.offsetMin = new Vector2(4f, 12f); + scoreRt.offsetMax = new Vector2(-18f, -14f); + var scoreTmp = scoreGo.AddComponent(); + scoreTmp.richText = true; + scoreTmp.textWrappingMode = TextWrappingModes.Normal; + scoreTmp.overflowMode = TextOverflowModes.Overflow; + scoreTmp.fontSize = UiTypography.Scale(28); + scoreTmp.enableAutoSizing = true; + scoreTmp.fontSizeMin = UiTypography.Scale(16); + scoreTmp.fontSizeMax = UiTypography.Scale(30); + scoreTmp.alignment = TextAlignmentOptions.MidlineRight; + scoreTmp.color = new Color(0.94f, 0.95f, 0.98f, 1f); + scoreTmp.lineSpacing = -4f; + ApplyPrimaryUiTypography(scoreTmp, equationStyle, outlineWidth: 0.16f, outlineAlpha: 0.55f); + scoreHudText = scoreTmp; + RefreshScoreHud(); } CreateMathConceptsButtonIfNeeded(canvas, equationStyle); - if (!graphCalculatorMode) + // Build hint for every mode so graphing calculator → platformer does not skip creation on first HUD pass. + if (controlsHintText == null) { - if (controlsHintText == null) - { - bool tabletUi = DeviceLayout.IsTabletLike(); - var barGo = new GameObject("ControlsHintPanel"); - var barRt = barGo.AddComponent(); - var safe = MobileUiRoots.GetSafeContentParent(canvas.transform); - barRt.SetParent(safe != null ? safe : canvas.transform, false); - barRt.anchorMin = new Vector2(0.5f, 0f); - barRt.anchorMax = new Vector2(0.5f, 0f); - barRt.pivot = new Vector2(0.5f, 0f); - float up = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset : 22f; - barRt.anchoredPosition = new Vector2(0f, up); - barRt.sizeDelta = new Vector2(tabletUi ? 900f : 760f, tabletUi ? 60f : 56f); - - var barBg = barGo.AddComponent(); - barBg.sprite = panelSprite; - barBg.color = new Color(0.08f, 0.09f, 0.13f, 0.85f); - barBg.raycastTarget = false; - barBg.type = panelSprite != null && panelSprite.border.sqrMagnitude > 0.001f ? Image.Type.Sliced : Image.Type.Simple; - - var textGo = new GameObject("ControlsHint"); - var textRt = textGo.AddComponent(); - textRt.SetParent(barGo.transform, false); - textRt.anchorMin = Vector2.zero; - textRt.anchorMax = Vector2.one; - textRt.offsetMin = new Vector2(20f, 8f); - textRt.offsetMax = new Vector2(-20f, -8f); - - var tmp = textGo.AddComponent(); - tmp.richText = true; - tmp.textWrappingMode = TextWrappingModes.Normal; - tmp.overflowMode = TextOverflowModes.Overflow; - tmp.fontSize = UiTypography.Scale(24); - tmp.alignment = TextAlignmentOptions.Midline; - tmp.color = new Color(0.82f, 0.85f, 0.92f, 0.92f); - tmp.characterSpacing = 0.25f; - ApplyPrimaryUiTypography(tmp, equationStyle, outlineWidth: 0.14f, outlineAlpha: 0.5f); - controlsHintText = tmp; - } + bool tabletUi = DeviceLayout.IsTabletLike(); + var barGo = new GameObject("ControlsHintPanel"); + var barRt = barGo.AddComponent(); + var safe = MobileUiRoots.GetSafeContentParent(canvas.transform); + barRt.SetParent(safe != null ? safe : canvas.transform, false); + barRt.anchorMin = new Vector2(0.5f, 0f); + barRt.anchorMax = new Vector2(0.5f, 0f); + barRt.pivot = new Vector2(0.5f, 0f); + float up = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset : 22f; + barRt.anchoredPosition = new Vector2(0f, up); + barRt.sizeDelta = new Vector2(tabletUi ? 900f : 760f, tabletUi ? 60f : 56f); + + var barBg = barGo.AddComponent(); + barBg.sprite = panelSprite; + barBg.color = new Color(0.08f, 0.09f, 0.13f, 0.85f); + barBg.raycastTarget = false; + barBg.type = panelSprite != null && panelSprite.border.sqrMagnitude > 0.001f ? Image.Type.Sliced : Image.Type.Simple; + + var textGo = new GameObject("ControlsHint"); + var textRt = textGo.AddComponent(); + textRt.SetParent(barGo.transform, false); + textRt.anchorMin = Vector2.zero; + textRt.anchorMax = Vector2.one; + textRt.offsetMin = new Vector2(20f, 8f); + textRt.offsetMax = new Vector2(-20f, -8f); - RefreshControlsHintLocalized(); + var tmp = textGo.AddComponent(); + tmp.richText = true; + tmp.textWrappingMode = TextWrappingModes.Normal; + tmp.overflowMode = TextOverflowModes.Overflow; + tmp.fontSize = UiTypography.Scale(24); + tmp.alignment = TextAlignmentOptions.Midline; + tmp.color = new Color(0.82f, 0.85f, 0.92f, 0.92f); + tmp.characterSpacing = 0.25f; + ApplyPrimaryUiTypography(tmp, equationStyle, outlineWidth: 0.14f, outlineAlpha: 0.5f); + controlsHintText = tmp; } + + RefreshControlsHintLocalized(); } /// Top-right control: opens (same body as level-select math tips). @@ -1043,6 +1134,30 @@ private void RefreshStageHud() LocalizationManager.ApplyTextDirection(stageHudText); } + void ResetGameplayScoreForNewLevel() + { + gameplayScore = GameplayStartingScore; + RefreshScoreHud(); + } + + void OnDerivativeLineGrazePenalty() + { + if (graphCalculatorMode) + return; + gameplayScore = Mathf.Max(0, gameplayScore - DerivativeTouchPenaltyPoints); + RefreshScoreHud(); + } + + void RefreshScoreHud() + { + if (scoreHudText == null) + return; + string label = LocalizationManager.Get("hud.points", "PTS"); + scoreHudText.text = + $"{label}\n{gameplayScore}"; + LocalizationManager.ApplyTextDirection(scoreHudText); + } + /// Square / UI sprite for flat panels (falls back to a tiny white sprite so Image always draws). private Sprite GetHudPanelSprite() { @@ -2688,6 +2803,9 @@ private void LoadLevel(int index) if (levels.Count == 0 || functionPlotter == null) return; + if (!graphCalculatorMode) + ResetGameplayScoreForNewLevel(); + currentLevelIndex = Mathf.Clamp(index, 0, levels.Count - 1); nextStageIndex = 0; lastStageHudKey = int.MinValue; @@ -2742,6 +2860,9 @@ private void ApplyLevelTheme(LevelDefinition def) curveRenderer.color = def.curveColor; derivRenderer.color = def.derivativeColor; + derivRenderer.thickness = DerivRendererUI.DefaultThicknessPixels; + if (popAnimator != null) + popAnimator.SyncRestThicknessFromTarget(); if (def.functionType == FunctionType.AeroDragPolarTriple) { @@ -2806,11 +2927,59 @@ private void ApplyLevelTheme(LevelDefinition def) // Story + roleplay intro run from after the world is built. } + /// + /// Stops full-screen overlays that can survive (same scene) and block touch raycasts. + /// + private void TearDownInterruptedLevelFlowUi() + { + if (stageIntroRoot != null) + { + if (stageIntroCanvasGroup != null) + { + stageIntroCanvasGroup.blocksRaycasts = false; + stageIntroCanvasGroup.interactable = false; + } + + stageIntroRoot.SetActive(false); + } + + var canvas = FindAnyObjectByType(); + if (canvas == null) + return; + + var safe = MobileUiRoots.GetSafeContentParent(canvas.transform); + Transform parent = safe != null ? safe : canvas.transform; + for (int i = parent.childCount - 1; i >= 0; i--) + { + var c = parent.GetChild(i); + if (c.name == "MobileControlGuideOverlay") + Destroy(c.gameObject); + } + } + + /// + /// Re-creates / re-parents the full-screen touch catcher after layout so it stays above the graph stack. + /// + private void EnsureGameplayTouchZonesAfterLevelReady() + { + if (graphCalculatorMode || !DeviceLayout.PreferOnScreenGameControls) + return; + + var canvas = FindAnyObjectByType(); + if (canvas == null) + return; + + GameplayScreenTouchZones.EnsureForGameCanvas(canvas.transform); + GameplayScreenTouchZones.SetActiveForGameplayMode(true); + } + /// /// Builds platforms after plot refresh; then optional roleplay “page”, then the ordinary story banner fade. /// private IEnumerator LoadLevelFullRoutine(LevelDefinition def) { + TearDownInterruptedLevelFlowUi(); + if (playerController != null) playerController.SetInputLocked(true); @@ -2843,6 +3012,8 @@ private IEnumerator LoadLevelFullRoutine(LevelDefinition def) playerController.SetInputLocked(false); } + EnsureGameplayTouchZonesAfterLevelReady(); + if (storyText != null) { RefreshStoryBannerForCurrentMode(def); diff --git a/First Principles/Assets/Scripts/Game/LevelSelectController.cs b/First Principles/Assets/Scripts/Game/LevelSelectController.cs index 2d229e1..9b70ecf 100644 --- a/First Principles/Assets/Scripts/Game/LevelSelectController.cs +++ b/First Principles/Assets/Scripts/Game/LevelSelectController.cs @@ -637,7 +637,100 @@ private void BuildLevelViewForCategory(int categoryIndex, int firstLevel, int la private void StartGameAt(int index) { + if (GameLevelCatalog.IsComingSoonLevel(index)) + { + ShowComingSoonOverlay(); + return; + } + LevelSelection.SetSelectedLevel(index); SceneTransitionHost.LoadSingleScene("Game"); } + + private const string ComingSoonOverlayName = "ComingSoonOverlayRoot"; + + /// Full-screen message for catalog levels not yet playable (e.g. Hohmann transfer). + private void ShowComingSoonOverlay() + { + var canvas = FindAnyObjectByType(); + if (canvas == null) + return; + + var existing = canvas.transform.Find(ComingSoonOverlayName); + if (existing != null) + Destroy(existing.gameObject); + + var root = new GameObject(ComingSoonOverlayName); + var rootRt = root.AddComponent(); + rootRt.SetParent(canvas.transform, false); + rootRt.anchorMin = Vector2.zero; + rootRt.anchorMax = Vector2.one; + rootRt.offsetMin = Vector2.zero; + rootRt.offsetMax = Vector2.zero; + rootRt.SetAsLastSibling(); + + var dim = root.AddComponent(); + dim.color = new Color(0.04f, 0.05f, 0.1f, 0.88f); + dim.raycastTarget = true; + + var dimBtn = root.AddComponent public class DerivRendererUI : Graphic { + /// Scene / level default stroke width (reset on theme load and after derivative pop animation). + public const float DefaultThicknessPixels = 10f; + public Vector2Int gridSize; public List points = new List(); - public float thickness = 10f; + public float thickness = DefaultThicknessPixels; [Tooltip("When < 1, the polyline fades in left→right (set by FunctionPlotter).")] [Range(0f, 1f)] diff --git a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs index d2b63b3..d85b353 100644 --- a/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs +++ b/First Principles/Assets/Scripts/UI/GameplayScreenTouchZones.cs @@ -10,6 +10,8 @@ public class GameplayScreenTouchZones : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler { + public const string RootObjectName = "GameplayScreenTouchZonesRoot"; + private static GameplayScreenTouchZones _instance; private readonly Dictionary _pointerSide = new Dictionary(); @@ -22,13 +24,8 @@ public static void EnsureForGameCanvas(Transform canvasTransform) DestroyLegacyButtonBar(canvasTransform); - Transform existing = canvasTransform.Find("GameplayScreenTouchZonesRoot"); - if (existing == null) - { - var safe = canvasTransform.Find(MobileUiRoots.SafeContentName); - if (safe != null) - existing = safe.Find("GameplayScreenTouchZonesRoot"); - } + // Deep find: after ReparentTouchLayerAboveGraph the root lives under GraphContainer, not a direct canvas child. + Transform existing = FindDeepChildByName(canvasTransform, RootObjectName); RectTransform rt; if (existing != null) @@ -44,7 +41,7 @@ public static void EnsureForGameCanvas(Transform canvasTransform) if (parentRt == null) return; - var go = new GameObject("GameplayScreenTouchZonesRoot", typeof(RectTransform)); + var go = new GameObject(RootObjectName, typeof(RectTransform)); rt = go.GetComponent(); rt.SetParent(parentRt, false); rt.anchorMin = Vector2.zero; @@ -66,6 +63,27 @@ public static void EnsureForGameCanvas(Transform canvasTransform) ReparentTouchLayerAboveGraph(canvasTransform, rt); } + /// + /// Full-screen touch layer is created whenever mobile gameplay prefers it, but disabled in graphing calculator + /// so the same scene path always has the object (avoids missing controls after Menu → calculator → level). + /// + public static void SetActiveForGameplayMode(bool gameplayMovementEnabled) + { + if (_instance != null) + { + if (_instance.gameObject.activeSelf != gameplayMovementEnabled) + _instance.gameObject.SetActive(gameplayMovementEnabled); + return; + } + + var canvas = Object.FindAnyObjectByType(); + if (canvas == null) + return; + var t = FindDeepChildByName(canvas.transform, RootObjectName); + if (t != null && t.gameObject.activeSelf != gameplayMovementEnabled) + t.gameObject.SetActive(gameplayMovementEnabled); + } + /// /// Inserts the touch catcher just above Graph inside GraphContainer so Footer/HUD stays on top. /// diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset index 2ad2e8c..36e9e7e 100644 --- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset +++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset @@ -1324,6 +1324,15 @@ MonoBehaviour: - {fileID: 0} - {fileID: 0} - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} m_FontWeightTable: - regularTypeface: {fileID: 0} italicTypeface: {fileID: 0} From 3c6b72471e3e4d092e8edb35c8f638bd335ed3d1 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:36:45 -0400 Subject: [PATCH 08/14] Updated --- First Principles/Assets/Resources/Localization/ar.txt | 2 +- First Principles/Assets/Resources/Localization/cs.txt | 2 +- First Principles/Assets/Resources/Localization/de.txt | 2 +- First Principles/Assets/Resources/Localization/en.txt | 4 ++-- First Principles/Assets/Resources/Localization/es.txt | 2 +- First Principles/Assets/Resources/Localization/fr.txt | 2 +- First Principles/Assets/Resources/Localization/hi.txt | 2 +- First Principles/Assets/Resources/Localization/it.txt | 2 +- First Principles/Assets/Resources/Localization/ja.txt | 2 +- First Principles/Assets/Resources/Localization/ko.txt | 2 +- First Principles/Assets/Resources/Localization/pl.txt | 2 +- First Principles/Assets/Resources/Localization/ru.txt | 2 +- First Principles/Assets/Resources/Localization/ur.txt | 2 +- First Principles/Assets/Resources/Localization/zh.txt | 2 +- .../Assets/Scripts/Game/GraphCalculatorToolbar.cs | 4 ++-- .../LiberationSans SDF - Fallback.asset | 9 +++++++++ First Principles/ProjectSettings/ProjectSettings.asset | 10 +++++----- 17 files changed, 31 insertions(+), 22 deletions(-) diff --git a/First Principles/Assets/Resources/Localization/ar.txt b/First Principles/Assets/Resources/Localization/ar.txt index 2b10076..c4a0547 100644 --- a/First Principles/Assets/Resources/Localization/ar.txt +++ b/First Principles/Assets/Resources/Localization/ar.txt @@ -21,7 +21,7 @@ graph.status_graphed=تم الرسم graph.line1=وضع آلة الرسوم البيانية graph.line2=اكتب f(u) أدناه (المتغير x في المربع = u الداخلي). ثم: graph.line3=Trans ← {0} · نقرتان + · اضغط مطولًا · Scale تكبير باللمس / اضغط مطولًا للتصغير · قرصة بإصبعين -graph.line4=A={0}  k={1}  C={2}  D={3}   x في [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x في [{4},{5}] graph.param_a=A (مقياس عمودي) graph.param_k=k (مقياس أفقي) graph.param_c=C (إزاحة عمودية) diff --git a/First Principles/Assets/Resources/Localization/cs.txt b/First Principles/Assets/Resources/Localization/cs.txt index 8562d61..f1748c3 100644 --- a/First Principles/Assets/Resources/Localization/cs.txt +++ b/First Principles/Assets/Resources/Localization/cs.txt @@ -34,7 +34,7 @@ graph.status_graphed=Vykresleno graph.line1=Režim grafické kalkulačky graph.line2=Napište f(u) níže (proměnná x v poli = vnitřní u). Pak: graph.line3=Trans → {0} · dvojité klepnutí + · podržte · Měřítko přiblížení / podržte oddálení · špetka dvěma prsty -graph.line4=A={0}  k={1}  C={2}  D={3}   x v [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x v [{4},{5}] graph.param_a=A (svislé měřítko) graph.param_k=k (vodorovné měřítko) graph.param_c=C (svislý posun) diff --git a/First Principles/Assets/Resources/Localization/de.txt b/First Principles/Assets/Resources/Localization/de.txt index 44e52d4..24b07fa 100644 --- a/First Principles/Assets/Resources/Localization/de.txt +++ b/First Principles/Assets/Resources/Localization/de.txt @@ -21,7 +21,7 @@ graph.status_graphed=Gezeichnet graph.line1=Grafikrechner-Modus graph.line2=Geben Sie unten f(u) ein (Variable x im Feld = inneres u). Dann: graph.line3=Trans → {0} · Doppeltipp + · halten · Maßstab hereinzoomen / halten herauszoomen · Zweifinger-Pinch -graph.line4=A={0}  k={1}  C={2}  D={3}   x in [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}] graph.param_a=A (vertikaler Maßstab) graph.param_k=k (horizontaler Maßstab) graph.param_c=C (vertikale Verschiebung) diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index e7886e7..ddb6c8c 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -45,7 +45,7 @@ graph.status_graphed=Graphed graph.line1=Graphing calculator mode graph.line2=Type f(u) below (variable x in the box = inner u). Then: graph.line3=Deriv adds f′ once (numeric) · ∫ area Riemann strips once + primitive guess · Trans → {0} · double-tap + · hold · Scale / pinch -graph.line4=A={0}  k={1}  C={2}  D={3}   x in [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}] graph.param_a=A (vertical scale) graph.param_k=k (horizontal scale) graph.param_c=C (vertical shift) @@ -55,7 +55,7 @@ graph.polar.param_a=A (r scale) graph.polar.param_k=k (θ scale) graph.polar.param_c=C (r shift) graph.polar.param_d=D (θ phase / axis shift) -graph.polar.line4=A={0}  k={1}  C={2}  D={3}   θ∈[{4},{5}] +graph.polar.line4=A={0} k={1} C={2} D={3} θ∈[{4},{5}] graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale · pinch zoom the window. # Prepended to story text for every Aerospace stage (indices 35–41). aerospace.story_drag_polar_preamble=Drag polar refresher (every Aerospace stage)\nParasitic (zero-lift) drag — skin friction, form drag, interference lumped as CD0 in the parabolic model (roughly not the part that grows with lift).\nInduced drag — the cost of making lift: trailing vortices add ~ K CL² (higher CL / tighter turns → more induced).\nOverall drag polarCD = CD0 + K CL²: an upward-opening parabola in CL; min-drag CL sits between “too slow / high α” and “too fast / low α” for real missions. diff --git a/First Principles/Assets/Resources/Localization/es.txt b/First Principles/Assets/Resources/Localization/es.txt index 5596395..dd9fd68 100644 --- a/First Principles/Assets/Resources/Localization/es.txt +++ b/First Principles/Assets/Resources/Localization/es.txt @@ -21,7 +21,7 @@ graph.status_graphed=Graficado graph.line1=Modo calculadora gráfica graph.line2=Escribe f(u) abajo (la variable x en el cuadro = u interior). Luego: graph.line3=Trans → {0} · doble toque + · mantén · Escala acercar / mantén alejar · pellizco con dos dedos -graph.line4=A={0}  k={1}  C={2}  D={3}   x en [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x en [{4},{5}] graph.param_a=A (escala vertical) graph.param_k=k (escala horizontal) graph.param_c=C (desplazamiento vertical) diff --git a/First Principles/Assets/Resources/Localization/fr.txt b/First Principles/Assets/Resources/Localization/fr.txt index db0a8cd..238fba0 100644 --- a/First Principles/Assets/Resources/Localization/fr.txt +++ b/First Principles/Assets/Resources/Localization/fr.txt @@ -21,7 +21,7 @@ graph.status_graphed=Tracé graph.line1=Mode calculatrice graphique graph.line2=Saisissez f(u) ci-dessous (la variable x dans la zone = u interne). Ensuite : graph.line3=Trans → {0} · double appui + · maintenir · Échelle zoom avant / maintenir zoom arrière · pincer deux doigts -graph.line4=A={0}  k={1}  C={2}  D={3}   x ∈ [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}] graph.param_a=A (échelle verticale) graph.param_k=k (échelle horizontale) graph.param_c=C (translation verticale) diff --git a/First Principles/Assets/Resources/Localization/hi.txt b/First Principles/Assets/Resources/Localization/hi.txt index 5d54566..4afb9ac 100644 --- a/First Principles/Assets/Resources/Localization/hi.txt +++ b/First Principles/Assets/Resources/Localization/hi.txt @@ -22,7 +22,7 @@ graph.status_graphed=ग्राफ़ तैयार graph.line1=ग्राफ़िंग कैलकुलेटर मोड graph.line2=नीचे f(u) लिखें (बॉक्स में चर x = आंतरिक u)। फिर: graph.line3=Trans → {0} · + पर डबल-टैप · दबाकर रखें · Scale ज़ूम इन / आउट दबाकर रखें · दो उंगलियों से पिंच -graph.line4=A={0}  k={1}  C={2}  D={3}   x ∈ [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}] graph.param_a=A (लंबवत स्केल) graph.param_k=k (क्षैतिज स्केल) graph.param_c=C (लंबवत खिसकाव) diff --git a/First Principles/Assets/Resources/Localization/it.txt b/First Principles/Assets/Resources/Localization/it.txt index e4b78ea..837711b 100644 --- a/First Principles/Assets/Resources/Localization/it.txt +++ b/First Principles/Assets/Resources/Localization/it.txt @@ -34,7 +34,7 @@ graph.status_graphed=Tracciato graph.line1=Modalità calcolatrice grafica graph.line2=Digita f(u) sotto (la variabile x nella casella = u interno). Poi: graph.line3=Trasf → {0} · doppio tocco + · tieni premuto · Scala zoom avanti / tieni zoom indietro · pizzica a due dita -graph.line4=A={0}  k={1}  C={2}  D={3}   x in [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}] graph.param_a=A (scala verticale) graph.param_k=k (scala orizzontale) graph.param_c=C (traslazione verticale) diff --git a/First Principles/Assets/Resources/Localization/ja.txt b/First Principles/Assets/Resources/Localization/ja.txt index 734ddd9..d839b83 100644 --- a/First Principles/Assets/Resources/Localization/ja.txt +++ b/First Principles/Assets/Resources/Localization/ja.txt @@ -21,7 +21,7 @@ graph.status_graphed=描画済み graph.line1=グラフ電卓モード graph.line2=下にf(u)を入力(欄内の変数xは内側の u)。次に: graph.line3=Trans → {0} · ダブルタップ + · 長押し · Scale はタップで拡大/長押しで縮小 · 2本指ピンチ -graph.line4=A={0}  k={1}  C={2}  D={3}   x は [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x は [{4},{5}] graph.param_a=A(縦スケール) graph.param_k=k(横スケール) graph.param_c=C(縦シフト) diff --git a/First Principles/Assets/Resources/Localization/ko.txt b/First Principles/Assets/Resources/Localization/ko.txt index fb1d3f4..a655e00 100644 --- a/First Principles/Assets/Resources/Localization/ko.txt +++ b/First Principles/Assets/Resources/Localization/ko.txt @@ -39,7 +39,7 @@ graph.status_graphed=그래프 완료 graph.line1=그래프 계산기 모드 graph.line2=아래에 f(u) 입력(상자 안 변수 x = 내부 u). 그다음: graph.line3=Trans → {0} · 더블탭 + · 길게 · Scale 탭 확대 / 길게 축소 · 두 손가락 핀치 -graph.line4=A={0}  k={1}  C={2}  D={3}   x ∈ [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}] graph.param_a=A (세로 스케일) graph.param_k=k (가로 스케일) graph.param_c=C (세로 이동) diff --git a/First Principles/Assets/Resources/Localization/pl.txt b/First Principles/Assets/Resources/Localization/pl.txt index ce6396f..94d2eba 100644 --- a/First Principles/Assets/Resources/Localization/pl.txt +++ b/First Principles/Assets/Resources/Localization/pl.txt @@ -34,7 +34,7 @@ graph.status_graphed=Narysowano graph.line1=Tryb kalkulatora graficznego graph.line2=Wpisz f(u) poniżej (zmienna x w polu = wewnętrzne u). Potem: graph.line3=Trans → {0} · podwójne dotknięcie + · przytrzymaj · Skala przybliż / przytrzymaj oddal · szczyp dwoma palcami -graph.line4=A={0}  k={1}  C={2}  D={3}   x w [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x w [{4},{5}] graph.param_a=A (skala pionowa) graph.param_k=k (skala pozioma) graph.param_c=C (przesunięcie pionowe) diff --git a/First Principles/Assets/Resources/Localization/ru.txt b/First Principles/Assets/Resources/Localization/ru.txt index a04cf9e..d3cfc82 100644 --- a/First Principles/Assets/Resources/Localization/ru.txt +++ b/First Principles/Assets/Resources/Localization/ru.txt @@ -34,7 +34,7 @@ graph.status_graphed=Построено graph.line1=Режим графического калькулятора graph.line2=Введите f(u) ниже (переменная x в поле = внутреннее u). Затем: graph.line3=Транс → {0} · двойной тап + · удерживайте · Масштаб увеличить / удерживайте уменьшить · щипок двумя пальцами -graph.line4=A={0}  k={1}  C={2}  D={3}   x ∈ [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}] graph.param_a=A (вертикальный масштаб) graph.param_k=k (горизонтальный масштаб) graph.param_c=C (вертикальный сдвиг) diff --git a/First Principles/Assets/Resources/Localization/ur.txt b/First Principles/Assets/Resources/Localization/ur.txt index a884411..4e27ac0 100644 --- a/First Principles/Assets/Resources/Localization/ur.txt +++ b/First Principles/Assets/Resources/Localization/ur.txt @@ -22,7 +22,7 @@ graph.status_graphed=گراف مکمل graph.line1=گرافنگ کیلکولیٹر موڈ graph.line2=f(u) نیچے لکھیں (باکس میں متغیر x = اندرونی u)۔ پھر: graph.line3=Trans → {0} · + پر ڈبل-تھپتھی · دبائے رکھیں · Scale زوم اندر / باہر دبائے رکھیں · دو انگلیوں سے پنچ -graph.line4=A={0}  k={1}  C={2}  D={3}   x ∈ [{4},{5}] +graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}] graph.param_a=A (عمودی پیمانہ) graph.param_k=k (افقی پیمانہ) graph.param_c=C (عمودی بِدائل) diff --git a/First Principles/Assets/Resources/Localization/zh.txt b/First Principles/Assets/Resources/Localization/zh.txt index c3a7bce..71e6bf4 100644 --- a/First Principles/Assets/Resources/Localization/zh.txt +++ b/First Principles/Assets/Resources/Localization/zh.txt @@ -21,7 +21,7 @@ graph.status_graphed=已绘制 graph.line1=图形计算器模式 graph.line2=在下方输入 f(u)(框内变量 x 为内层 u)。然后: graph.line3=Trans → {0} · 双击 + · 长按 · Scale 点按放大 / 长按缩小 · 双指 捏合 -graph.line4=A={0}  k={1}  C={2}  D={3}   x 在 [{4},{5}] 内 +graph.line4=A={0} k={1} C={2} D={3} x 在 [{4},{5}] 内 graph.param_a=A(纵向缩放) graph.param_k=k(横向缩放) graph.param_c=C(纵向平移) diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs index 75797ca..8fdf9d2 100644 --- a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs +++ b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs @@ -168,9 +168,9 @@ private void RefreshHint() float th1 = plot.transK * (plot.xEnd - plot.transD); string line4Fmt = polar ? LocalizationManager.Get("graph.polar.line4", - "A={0}  k={1}  C={2}  D={3}   θ∈[{4},{5}]") + "A={0} k={1} C={2} D={3} θ∈[{4},{5}]") : LocalizationManager.Get("graph.line4", - "A={0}  k={1}  C={2}  D={3}   x∈[{4},{5}]"); + "A={0} k={1} C={2} D={3} x∈[{4},{5}]"); string line4 = polar ? string.Format(line4Fmt, plot.transA.ToString("0.##"), diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset index 36e9e7e..8897c1f 100644 --- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset +++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset @@ -1333,6 +1333,15 @@ MonoBehaviour: - {fileID: 0} - {fileID: 0} - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} m_FontWeightTable: - regularTypeface: {fileID: 0} italicTypeface: {fileID: 0} diff --git a/First Principles/ProjectSettings/ProjectSettings.asset b/First Principles/ProjectSettings/ProjectSettings.asset index 65193d6..006f5e1 100644 --- a/First Principles/ProjectSettings/ProjectSettings.asset +++ b/First Principles/ProjectSettings/ProjectSettings.asset @@ -8,7 +8,7 @@ PlayerSettings: AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 AndroidEnableSustainedPerformanceMode: 0 - defaultScreenOrientation: 4 + defaultScreenOrientation: 1 targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 @@ -59,10 +59,10 @@ PlayerSettings: androidShowActivityIndicatorOnLoading: -1 iosUseCustomAppBackgroundBehavior: 0 allowedAutorotateToPortrait: 1 - allowedAutorotateToPortraitUpsideDown: 1 - allowedAutorotateToLandscapeRight: 1 - allowedAutorotateToLandscapeLeft: 1 - useOSAutorotation: 1 + allowedAutorotateToPortraitUpsideDown: 0 + allowedAutorotateToLandscapeRight: 0 + allowedAutorotateToLandscapeLeft: 0 + useOSAutorotation: 0 use32BitDisplayBuffer: 1 preserveFramebufferAlpha: 0 disableDepthAndStencilBuffers: 0 From b3ecace61d1489253509cea81b6d2a6bbcdc6678 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:41:13 -0400 Subject: [PATCH 09/14] Update LevelManager.cs --- .../Assets/Scripts/Game/LevelManager.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 33e38cb..5d677fe 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -316,6 +316,7 @@ private void SetupReferences() { FitCartesianPlaneForGameplay(); SyncGameplayLayoutToCartesianPlane(); + EnsurePlatformerHudPresentation(); } } @@ -1013,6 +1014,7 @@ private void CreateGameplayHudIfNeeded() tmp.characterSpacing = 0.25f; ApplyPrimaryUiTypography(tmp, equationStyle, outlineWidth: 0.14f, outlineAlpha: 0.5f); controlsHintText = tmp; + barRt.SetAsLastSibling(); } RefreshControlsHintLocalized(); @@ -1158,6 +1160,31 @@ void RefreshScoreHud() LocalizationManager.ApplyTextDirection(scoreHudText); } + /// + /// Stage + score live on StageHudPanel; graphing calculator mode deactivates that parent. Other UI + /// (equation strip, overlays) can also reparent later and steal draw order — re-activate and bring HUD forward + /// so stage, PTS, and the bottom controls hint stay visible in platformer mode. + /// + private void EnsurePlatformerHudPresentation() + { + if (graphCalculatorMode) + return; + + if (stageHudText != null && stageHudText.transform.parent != null) + { + var stagePanel = stageHudText.transform.parent.gameObject; + stagePanel.SetActive(true); + stagePanel.transform.SetAsLastSibling(); + } + + if (controlsHintText != null && controlsHintText.transform.parent != null) + { + var hintPanel = controlsHintText.transform.parent.gameObject; + hintPanel.SetActive(true); + hintPanel.transform.SetAsLastSibling(); + } + } + /// Square / UI sprite for flat panels (falls back to a tiny white sprite so Image always draws). private Sprite GetHudPanelSprite() { @@ -3013,6 +3040,7 @@ private IEnumerator LoadLevelFullRoutine(LevelDefinition def) } EnsureGameplayTouchZonesAfterLevelReady(); + EnsurePlatformerHudPresentation(); if (storyText != null) { From 98d9e5685688beacc81728fb75759b3b0e7451ac Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:43:44 -0400 Subject: [PATCH 10/14] Updated --- .../Assets/Resources/Localization/ar.txt | 2 - .../Assets/Resources/Localization/cs.txt | 2 - .../Assets/Resources/Localization/de.txt | 2 - .../Assets/Resources/Localization/en.txt | 4 - .../Assets/Resources/Localization/es.txt | 2 - .../Assets/Resources/Localization/fr.txt | 2 - .../Assets/Resources/Localization/hi.txt | 2 - .../Assets/Resources/Localization/it.txt | 2 - .../Assets/Resources/Localization/ja.txt | 2 - .../Assets/Resources/Localization/ko.txt | 2 - .../Assets/Resources/Localization/pl.txt | 2 - .../Assets/Resources/Localization/ru.txt | 2 - .../Assets/Resources/Localization/ur.txt | 2 - .../Assets/Resources/Localization/zh.txt | 2 - .../Assets/Scripts/Game/LevelManager.cs | 144 +----------------- .../Assets/Scripts/UI/DeviceLayout.cs | 4 +- 16 files changed, 3 insertions(+), 175 deletions(-) diff --git a/First Principles/Assets/Resources/Localization/ar.txt b/First Principles/Assets/Resources/Localization/ar.txt index c4a0547..0c85d4b 100644 --- a/First Principles/Assets/Resources/Localization/ar.txt +++ b/First Principles/Assets/Resources/Localization/ar.txt @@ -12,8 +12,6 @@ ui.jump=قفز ui.move=تحرك ui.keyboard_hint_mobile=(لوحة المفاتيح: الأسهم / المسافة) hud.stage=المرحلة -controls.desktop=تحرك · قفز مسافة -controls.calculator=آلة رسومية اكتب f(u) · Trans · Scale · قرصة · رجوع graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) عندما x>0 · min(x,3)... graph.status_enter=Enter / اضغط خارج الحقل للرسم diff --git a/First Principles/Assets/Resources/Localization/cs.txt b/First Principles/Assets/Resources/Localization/cs.txt index f1748c3..d53fcac 100644 --- a/First Principles/Assets/Resources/Localization/cs.txt +++ b/First Principles/Assets/Resources/Localization/cs.txt @@ -25,8 +25,6 @@ ui.jump=Skok ui.move=Pohyb ui.keyboard_hint_mobile=(klávesnice: šipky / Mezerník) hud.stage=FÁZE -controls.desktop=Pohyb · Skok Mezerník -controls.calculator=Grafická kalkulačka Zadejte f(u) · Trans · Měřítko · Špetka · Zpět graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) pro x>0 · min(x,3)... graph.status_enter=Enter / klepněte mimo pro graf diff --git a/First Principles/Assets/Resources/Localization/de.txt b/First Principles/Assets/Resources/Localization/de.txt index 24b07fa..3d5ec57 100644 --- a/First Principles/Assets/Resources/Localization/de.txt +++ b/First Principles/Assets/Resources/Localization/de.txt @@ -12,8 +12,6 @@ ui.jump=Sprung ui.move=Bewegen ui.keyboard_hint_mobile=(Tastatur: Pfeile / Leertaste) hud.stage=PHASE -controls.desktop=Bewegen · Sprung Leertaste -controls.calculator=Grafikrechner f(u) eingeben · Trans · Maßstab · Pinch · Zurück graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) für x>0 · min(x,3)... graph.status_enter=Eingabe / außerhalb tippen zum Zeichnen diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt index ddb6c8c..8eeddaa 100644 --- a/First Principles/Assets/Resources/Localization/en.txt +++ b/First Principles/Assets/Resources/Localization/en.txt @@ -30,10 +30,6 @@ ui.move=Move ui.keyboard_hint_mobile=(keyboard: arrows / Space) hud.stage=STAGE hud.points=PTS -controls.mobile=Left hold ◀ · Right hold ▶ · 2nd finger jump (keyboard: arrows / Space) -controls.guide_overlay=Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nWhile holding, tap with another finger — jump\n\nKeyboard: Arrow keys move · Space jumps -controls.desktop=Move · Jump Space -controls.calculator=Graphing calculator Type f(u) · Deriv · · Trans · Scale · Pinch · Back graph.calc_deriv=Deriv graph.calc_integral=∫ area graph.calc_primitive_prefix=Primitive (guess): diff --git a/First Principles/Assets/Resources/Localization/es.txt b/First Principles/Assets/Resources/Localization/es.txt index dd9fd68..cf2e452 100644 --- a/First Principles/Assets/Resources/Localization/es.txt +++ b/First Principles/Assets/Resources/Localization/es.txt @@ -12,8 +12,6 @@ ui.jump=Saltar ui.move=Mover ui.keyboard_hint_mobile=(teclado: flechas / Espacio) hud.stage=FASE -controls.desktop=Mover · Saltar Espacio -controls.calculator=Calculadora gráfica Escribir f(u) · Trans · Escala · Pellizco · Atrás graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) para x>0 · min(x,3)... graph.status_enter=Intro / tocar fuera para graficar diff --git a/First Principles/Assets/Resources/Localization/fr.txt b/First Principles/Assets/Resources/Localization/fr.txt index 238fba0..fbdcb0d 100644 --- a/First Principles/Assets/Resources/Localization/fr.txt +++ b/First Principles/Assets/Resources/Localization/fr.txt @@ -12,8 +12,6 @@ ui.jump=Saut ui.move=Déplacer ui.keyboard_hint_mobile=(clavier : flèches / Espace) hud.stage=NIVEAU -controls.desktop=Déplacer · Saut Espace -controls.calculator=Calculatrice graphique Saisir f(u) · Trans · Échelle · Pincer · Retour graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) si x>0 · min(x,3)... graph.status_enter=Entrée / toucher ailleurs pour tracer diff --git a/First Principles/Assets/Resources/Localization/hi.txt b/First Principles/Assets/Resources/Localization/hi.txt index 4afb9ac..f729fbc 100644 --- a/First Principles/Assets/Resources/Localization/hi.txt +++ b/First Principles/Assets/Resources/Localization/hi.txt @@ -13,8 +13,6 @@ ui.jump=कूद ui.move=चलें ui.keyboard_hint_mobile=(कीबोर्ड: तीर / स्पेस) hud.stage=चरण -controls.desktop=चलें · कूद स्पेस -controls.calculator=ग्राफ़िंग कैलकुलेटर f(u) लिखें · Trans · Scale · पिंच · वापस graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) जब x>0 · min(x,3)... graph.status_enter=Enter / ग्राफ़ के लिए बाहर टैप करें diff --git a/First Principles/Assets/Resources/Localization/it.txt b/First Principles/Assets/Resources/Localization/it.txt index 837711b..243ddd4 100644 --- a/First Principles/Assets/Resources/Localization/it.txt +++ b/First Principles/Assets/Resources/Localization/it.txt @@ -25,8 +25,6 @@ ui.jump=Salta ui.move=Muoviti ui.keyboard_hint_mobile=(tastiera: frecce / Spazio) hud.stage=STADIO -controls.desktop=Muoviti · Salta Spazio -controls.calculator=Calcolatrice grafica Digita f(u) · Trasf · Scala · Pizzica · Indietro graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) per x>0 · min(x,3)... graph.status_enter=Invio / tocca fuori per tracciare diff --git a/First Principles/Assets/Resources/Localization/ja.txt b/First Principles/Assets/Resources/Localization/ja.txt index d839b83..4a78070 100644 --- a/First Principles/Assets/Resources/Localization/ja.txt +++ b/First Principles/Assets/Resources/Localization/ja.txt @@ -12,8 +12,6 @@ ui.jump=ジャンプ ui.move=移動 ui.keyboard_hint_mobile=(キーボード:矢印/スペース) hud.stage=ステージ -controls.desktop=移動 · ジャンプ スペース -controls.calculator=グラフ電卓 f(u) を入力 · Trans · Scale · ピンチ · 戻る graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) (x>0)· min(x,3)... graph.status_enter=Enter/外側タップでグラフ描画 diff --git a/First Principles/Assets/Resources/Localization/ko.txt b/First Principles/Assets/Resources/Localization/ko.txt index a655e00..b931127 100644 --- a/First Principles/Assets/Resources/Localization/ko.txt +++ b/First Principles/Assets/Resources/Localization/ko.txt @@ -30,8 +30,6 @@ ui.jump=점프 ui.move=이동 ui.keyboard_hint_mobile=(키보드: 방향키 / 스페이스) hud.stage=스테이지 -controls.desktop=이동 · 점프 스페이스 -controls.calculator=그래프 계산기 f(u) 입력 · Trans · Scale · 핀치 · 뒤로 graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) (x>0) · min(x,3)... graph.status_enter=Enter / 바깥 탭으로 그래프 diff --git a/First Principles/Assets/Resources/Localization/pl.txt b/First Principles/Assets/Resources/Localization/pl.txt index 94d2eba..e16f0d3 100644 --- a/First Principles/Assets/Resources/Localization/pl.txt +++ b/First Principles/Assets/Resources/Localization/pl.txt @@ -25,8 +25,6 @@ ui.jump=Skok ui.move=Ruch ui.keyboard_hint_mobile=(klawiatura: strzałki / Spacja) hud.stage=ETAP -controls.desktop=Ruch · Skok Spacja -controls.calculator=Kalkulator graficzny Wpisz f(u) · Trans · Skala · Szczyp · Wstecz graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) dla x>0 · min(x,3)... graph.status_enter=Enter / dotknij poza pole, aby narysować diff --git a/First Principles/Assets/Resources/Localization/ru.txt b/First Principles/Assets/Resources/Localization/ru.txt index d3cfc82..595cc09 100644 --- a/First Principles/Assets/Resources/Localization/ru.txt +++ b/First Principles/Assets/Resources/Localization/ru.txt @@ -25,8 +25,6 @@ ui.jump=Прыжок ui.move=Движение ui.keyboard_hint_mobile=(клавиатура: стрелки / Пробел) hud.stage=ЭТАП -controls.desktop=Движение · Прыжок Пробел -controls.calculator=Граф. калькулятор Ввод f(u) · Транс · Масштаб · Щипок · Назад graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) при x>0 · min(x,3)... graph.status_enter=Enter / тап вне поля для графика diff --git a/First Principles/Assets/Resources/Localization/ur.txt b/First Principles/Assets/Resources/Localization/ur.txt index 4e27ac0..982201c 100644 --- a/First Principles/Assets/Resources/Localization/ur.txt +++ b/First Principles/Assets/Resources/Localization/ur.txt @@ -13,8 +13,6 @@ ui.jump=چھلانگ ui.move=حرکت ui.keyboard_hint_mobile=(کی بورڈ: تیر / اسپیس) hud.stage=اسٹیج -controls.desktop=حرکت · چھلانگ اسپیس -controls.calculator=گرافنگ کیلکولیٹر f(u) لکھیں · Trans · Scale · پنچ · واپس graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x) جب x>0 · min(x,3)... graph.status_enter=Enter / گراف کے لیے باہر تھپتھپائیں diff --git a/First Principles/Assets/Resources/Localization/zh.txt b/First Principles/Assets/Resources/Localization/zh.txt index 71e6bf4..83dcc99 100644 --- a/First Principles/Assets/Resources/Localization/zh.txt +++ b/First Principles/Assets/Resources/Localization/zh.txt @@ -12,8 +12,6 @@ ui.jump=跳跃 ui.move=移动 ui.keyboard_hint_mobile=(键盘:方向键 / 空格) hud.stage=阶段 -controls.desktop=移动 · 跳跃 空格 -controls.calculator=图形计算器 输入 f(u) · Trans · Scale · 双指缩放 · 返回 graph.label_fu=f(u) = graph.placeholder=x^2 + sin(x) · ln(x)(x>0)· min(x,3)... graph.status_enter=回车 / 点击外部绘制图象 diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 5d677fe..1a0db61 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -55,7 +55,6 @@ public class LevelManager : MonoBehaviour private TextMeshProUGUI storyText; private TextMeshProUGUI stageHudText; private TextMeshProUGUI scoreHudText; - private TextMeshProUGUI controlsHintText; private int lastStageHudKey = int.MinValue; private Sprite cachedHudPanelSprite; private float storyMiddlePauseSeconds = 1.65f; @@ -92,9 +91,6 @@ public class LevelManager : MonoBehaviour [Tooltip("Total time from level ready until controls unlock from spotlight (fade in + hold + fade out).")] [SerializeField] private float spawnSpotlightTotalSeconds = 1.5f; - [Tooltip("Full-screen touch control instructions (mobile only), shown before spawn spotlight.")] - [SerializeField] private float mobileControlGuideSeconds = 1.5f; - [Tooltip("Optional; if null, loads Resources/UI_SpotlightDim then Shader.Find.")] [SerializeField] private Shader spawnSpotlightShader; @@ -134,7 +130,6 @@ private void OnDisable() private void OnLocalizationChanged() { - RefreshControlsHintLocalized(); RefreshMathConceptsLabelLocalized(); RefreshStageHudLocalizedForce(); @@ -161,30 +156,6 @@ private void OnLocalizationChanged() RefreshScoreHud(); } - private void RefreshControlsHintLocalized() - { - if (controlsHintText == null) - return; - - if (graphCalculatorMode) - { - controlsHintText.text = LocalizationManager.Get("controls.calculator", - "Graphing calculator Type f(u) · Deriv · · Trans · Scale · Pinch · Back"); - } - else if (DeviceLayout.PreferOnScreenGameControls) - { - controlsHintText.text = LocalizationManager.Get("controls.mobile", - "Move \u25C0 \u25B6 \u00b7 Jump tap (keyboard: arrows / Space)"); - } - else - { - controlsHintText.text = LocalizationManager.Get("controls.desktop", - "Move \u2190 \u2192 \u00b7 Jump Space"); - } - - LocalizationManager.ApplyTextDirection(controlsHintText); - } - private void RefreshMathConceptsLabelLocalized() { var go = GameObject.Find("MathConceptsButton"); @@ -656,8 +627,6 @@ private void EnterGraphCalculatorMode() if (calcAnalysis == null) calcAnalysis = gameObject.AddComponent(); calcAnalysis.Configure(functionPlotter, riemannRenderer, curveRenderer, equationStyleRef, transRowBottom); - - RefreshControlsHintLocalized(); } /// Trans / Scale labels use the project TMP default font and bold weight in calculator mode. @@ -974,50 +943,6 @@ private void CreateGameplayHudIfNeeded() } CreateMathConceptsButtonIfNeeded(canvas, equationStyle); - - // Build hint for every mode so graphing calculator → platformer does not skip creation on first HUD pass. - if (controlsHintText == null) - { - bool tabletUi = DeviceLayout.IsTabletLike(); - var barGo = new GameObject("ControlsHintPanel"); - var barRt = barGo.AddComponent(); - var safe = MobileUiRoots.GetSafeContentParent(canvas.transform); - barRt.SetParent(safe != null ? safe : canvas.transform, false); - barRt.anchorMin = new Vector2(0.5f, 0f); - barRt.anchorMax = new Vector2(0.5f, 0f); - barRt.pivot = new Vector2(0.5f, 0f); - float up = DeviceLayout.PreferOnScreenGameControls ? DeviceLayout.TouchHintVerticalOffset : 22f; - barRt.anchoredPosition = new Vector2(0f, up); - barRt.sizeDelta = new Vector2(tabletUi ? 900f : 760f, tabletUi ? 60f : 56f); - - var barBg = barGo.AddComponent(); - barBg.sprite = panelSprite; - barBg.color = new Color(0.08f, 0.09f, 0.13f, 0.85f); - barBg.raycastTarget = false; - barBg.type = panelSprite != null && panelSprite.border.sqrMagnitude > 0.001f ? Image.Type.Sliced : Image.Type.Simple; - - var textGo = new GameObject("ControlsHint"); - var textRt = textGo.AddComponent(); - textRt.SetParent(barGo.transform, false); - textRt.anchorMin = Vector2.zero; - textRt.anchorMax = Vector2.one; - textRt.offsetMin = new Vector2(20f, 8f); - textRt.offsetMax = new Vector2(-20f, -8f); - - var tmp = textGo.AddComponent(); - tmp.richText = true; - tmp.textWrappingMode = TextWrappingModes.Normal; - tmp.overflowMode = TextOverflowModes.Overflow; - tmp.fontSize = UiTypography.Scale(24); - tmp.alignment = TextAlignmentOptions.Midline; - tmp.color = new Color(0.82f, 0.85f, 0.92f, 0.92f); - tmp.characterSpacing = 0.25f; - ApplyPrimaryUiTypography(tmp, equationStyle, outlineWidth: 0.14f, outlineAlpha: 0.5f); - controlsHintText = tmp; - barRt.SetAsLastSibling(); - } - - RefreshControlsHintLocalized(); } /// Top-right control: opens (same body as level-select math tips). @@ -1163,7 +1088,7 @@ void RefreshScoreHud() /// /// Stage + score live on StageHudPanel; graphing calculator mode deactivates that parent. Other UI /// (equation strip, overlays) can also reparent later and steal draw order — re-activate and bring HUD forward - /// so stage, PTS, and the bottom controls hint stay visible in platformer mode. + /// so stage and PTS stay visible in platformer mode. /// private void EnsurePlatformerHudPresentation() { @@ -1176,13 +1101,6 @@ private void EnsurePlatformerHudPresentation() stagePanel.SetActive(true); stagePanel.transform.SetAsLastSibling(); } - - if (controlsHintText != null && controlsHintText.transform.parent != null) - { - var hintPanel = controlsHintText.transform.parent.gameObject; - hintPanel.SetActive(true); - hintPanel.transform.SetAsLastSibling(); - } } /// Square / UI sprite for flat panels (falls back to a tiny white sprite so Image always draws). @@ -3026,9 +2944,6 @@ private IEnumerator LoadLevelFullRoutine(LevelDefinition def) if (showIntro) yield return RunEnumerated(RunStageIntroCoroutine(def)); - if (DeviceLayout.PreferOnScreenGameControls && runSpawnSpotlight && playerController != null) - yield return RunEnumerated(RunMobileControlGuideRoutine()); - if (runSpawnSpotlight && playerController != null) yield return RunEnumerated(RunSpawnSpotlightRoutine()); @@ -3061,63 +2976,6 @@ private static IEnumerator RunEnumerated(IEnumerator inner) yield return inner.Current; } - /// - /// Mobile: full-screen instruction card before spawn spotlight (input still locked). - /// - private IEnumerator RunMobileControlGuideRoutine() - { - var canvas = FindAnyObjectByType(); - if (canvas == null) - yield break; - - var safe = MobileUiRoots.GetSafeContentParent(canvas.transform) as RectTransform; - Transform parent = safe != null ? safe.transform : canvas.transform; - - var go = new GameObject("MobileControlGuideOverlay", typeof(RectTransform)); - var rt = go.GetComponent(); - rt.SetParent(parent, false); - rt.SetAsLastSibling(); - rt.anchorMin = Vector2.zero; - rt.anchorMax = Vector2.one; - rt.offsetMin = Vector2.zero; - rt.offsetMax = Vector2.zero; - - var dim = go.AddComponent(); - dim.color = new Color(0.04f, 0.05f, 0.12f, 0.92f); - dim.raycastTarget = true; - - var textGo = new GameObject("GuideText", typeof(RectTransform)); - var trt = textGo.GetComponent(); - trt.SetParent(go.transform, false); - trt.anchorMin = new Vector2(0.06f, 0.12f); - trt.anchorMax = new Vector2(0.94f, 0.88f); - trt.offsetMin = Vector2.zero; - trt.offsetMax = Vector2.zero; - - var tmp = textGo.AddComponent(); - tmp.richText = true; - tmp.textWrappingMode = TextWrappingModes.Normal; - tmp.overflowMode = TextOverflowModes.Overflow; - tmp.alignment = TextAlignmentOptions.Midline; - tmp.fontSize = UiTypography.Scale(DeviceLayout.IsTabletLike() ? 30 : 26); - tmp.lineSpacing = 6f; - tmp.color = new Color(0.94f, 0.95f, 0.98f, 1f); - tmp.text = TmpLatex.Process(LocalizationManager.Get("controls.guide_overlay", - "Touch controls\n\nLeft half — hold to move left\nRight half — hold to move right\nWhile holding, tap with another finger — jump\n\nKeyboard: Arrow keys move · Space jumps")); - LocalizationManager.ApplyTextDirection(tmp); - ApplyPrimaryUiTypography(tmp, FindPrimaryEquationTmp(), outlineWidth: 0.1f, outlineAlpha: 0.42f); - - float dur = Mathf.Max(0.2f, mobileControlGuideSeconds); - float t = 0f; - while (t < dur) - { - t += Time.unscaledDeltaTime; - yield return null; - } - - Destroy(go); - } - /// /// Fullscreen dim with a soft hole on the player — runs while input is still locked (after optional roleplay card). /// diff --git a/First Principles/Assets/Scripts/UI/DeviceLayout.cs b/First Principles/Assets/Scripts/UI/DeviceLayout.cs index 7f584c7..85fa059 100644 --- a/First Principles/Assets/Scripts/UI/DeviceLayout.cs +++ b/First Principles/Assets/Scripts/UI/DeviceLayout.cs @@ -78,12 +78,12 @@ public static float RecommendedCanvasMatchWidthOrHeight() /// True in Game when we use left/right screen halves + second-finger jump (no ◀ ▶ Jump strip). public static bool GameplayUsesFullScreenTouchZones => PreferOnScreenGameControls; - /// Bottom offset for the small controls hint chip (above graph; no virtual bar when zones are on). + /// Bottom inset for game UI anchored above the safe area (no on-screen controls strip). public static float TouchHintVerticalOffset => !PreferOnScreenGameControls ? 22f : GameplayUsesFullScreenTouchZones - ? (IsTabletLike() ? 118f : 96f) + ? (IsTabletLike() ? 28f : 18f) : (IsTabletLike() ? 212f : 188f); // Leave vertical room for bottom “Math tips” / “How to play” band + back chip. From 0c8c84bb6066063bd43d33c7129521060deb4610 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:45:43 -0400 Subject: [PATCH 11/14] Update LevelManager.cs --- .../Assets/Scripts/Game/LevelManager.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 1a0db61..4b77ce4 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -152,8 +152,7 @@ private void OnLocalizationChanged() else if (levels.Count > 0 && currentLevelIndex >= 0 && currentLevelIndex < levels.Count) RefreshStoryBannerForCurrentMode(levels[currentLevelIndex]); - if (!graphCalculatorMode) - RefreshScoreHud(); + RefreshScoreHud(); } private void RefreshMathConceptsLabelLocalized() @@ -507,8 +506,14 @@ private void EnterGraphCalculatorMode() TightenGraphCalculatorStoryBanner(); } - if (stageHudText != null && stageHudText.transform.parent != null) - stageHudText.transform.parent.gameObject.SetActive(false); + // Keep score on the same panel; hide only STAGE (not meaningful in calculator). + if (stageHudText != null) + stageHudText.gameObject.SetActive(false); + if (scoreHudText != null) + { + scoreHudText.gameObject.SetActive(true); + RefreshScoreHud(); + } functionPlotter.transA = 1f; functionPlotter.transK = 1f; @@ -1086,9 +1091,8 @@ void RefreshScoreHud() } /// - /// Stage + score live on StageHudPanel; graphing calculator mode deactivates that parent. Other UI - /// (equation strip, overlays) can also reparent later and steal draw order — re-activate and bring HUD forward - /// so stage and PTS stay visible in platformer mode. + /// Stage + score share StageHudPanel. Graphing calculator hides only the stage line; platformer needs + /// both visible. Other UI can reparent later — re-activate panel + stage and bring HUD forward. /// private void EnsurePlatformerHudPresentation() { @@ -1099,6 +1103,7 @@ private void EnsurePlatformerHudPresentation() { var stagePanel = stageHudText.transform.parent.gameObject; stagePanel.SetActive(true); + stageHudText.gameObject.SetActive(true); stagePanel.transform.SetAsLastSibling(); } } From d70af8e43a4eccc9764b760dadde5021c676429a Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:49:06 -0400 Subject: [PATCH 12/14] Create MathArticleLevelSectionMap.cs --- .../Game/MathArticleLevelSectionMap.cs | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs diff --git a/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs b/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs new file mode 100644 index 0000000..eb9f849 --- /dev/null +++ b/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; + +/// +/// Which @@SECTION=id blocks from Localization/MathArticle/*.txt to show when opening +/// Math concepts during a level. Level select passes for the full article. +/// +public static class MathArticleLevelSectionMap +{ + /// Ordered section ids to concatenate for . + public static IReadOnlyList GetSectionKeysForLevel(int levelIndex) + { + if (levelIndex < 0 || levelIndex >= GameLevelCatalog.LevelCount) + return new[] { "intro", "how_graph" }; + + if (GameLevelCatalog.IsComingSoonLevel(levelIndex)) + return new[] { "intro", "how_graph" }; + + // 0 — First Principles Primer + if (levelIndex == 0) + return new[] { "intro", "how_graph", "s1", "rules", "biz" }; + + if (levelIndex == 1) + return new[] { "intro", "how_graph", "s1", "s2" }; + + if (levelIndex is >= 2 and <= 3) + return new[] { "intro", "how_graph", "s1", "s3" }; + + if (levelIndex == 4) + return new[] { "intro", "how_graph", "s1", "s4" }; + + if (levelIndex == 5) + return new[] { "intro", "how_graph", "s1", "s5", "rules" }; + + if (levelIndex == 6) + return new[] { "intro", "how_graph", "s1", "s5" }; + + if (levelIndex == 7) + return new[] { "intro", "how_graph", "s1", "s6" }; + + if (levelIndex is >= 8 and <= 9) + return new[] { "intro", "how_graph", "s1", "s7" }; + + if (levelIndex == 10) + return new[] { "intro", "how_graph", "s1", "s8", "int_block" }; + + if (levelIndex is >= 11 and <= 13) + return new[] { "intro", "how_graph", "s8", "int_block" }; + + if (levelIndex == 14) + return new[] { "intro", "how_graph", "s10", "s9" }; + + if (levelIndex == 15) + return new[] { "intro", "how_graph", "s11" }; + + if (levelIndex == 16) + return new[] { "intro", "how_graph", "s12" }; + + if (levelIndex == 17) + return new[] { "intro", "how_graph", "s1", "rules" }; + + if (levelIndex == 18) + return new[] { "intro", "how_graph", "rules", "int_block" }; + + if (levelIndex is >= 19 and <= 20) + return new[] { "intro", "how_graph", "rules", "exam" }; + + if (levelIndex == 21) + return new[] { "intro", "how_graph", "s5", "rules" }; + + if (levelIndex == 22) + return new[] { "intro", "how_graph", "s10", "rules" }; + + if (levelIndex == 23) + return new[] { "intro", "how_graph", "rules", "exam" }; + + if (levelIndex == 24) + return new[] { "intro", "how_graph", "s2", "exam" }; + + if (levelIndex == 25) + return new[] { "intro", "how_graph", "s5", "rules" }; + + if (levelIndex == 26) + return new[] { "intro", "how_graph", "rules", "int_block" }; + + if (levelIndex == 27) + return new[] { "intro", "how_graph", "s4", "rules" }; + + if (levelIndex == 28) + return new[] { "intro", "how_graph", "s1", "rules", "s3" }; + + if (levelIndex == 29) + return new[] { "intro", "how_graph", "s1", "rules" }; + + if (levelIndex == 30) + return new[] { "intro", "how_graph", "s3", "s10" }; + + if (levelIndex == 31) + return new[] { "intro", "how_graph", "s1", "rules" }; + + if (levelIndex == 32) + return new[] { "intro", "how_graph", "rules" }; + + if (levelIndex == 33) + return new[] { "intro", "how_graph", "s13" }; + + if (levelIndex == 34) + return new[] { "intro", "how_graph", "s9", "exam" }; + + if (levelIndex is >= 35 and <= 41) + return new[] { "intro", "how_graph", "aero" }; + + if (levelIndex is >= 42 and <= 43) + return new[] { "intro", "how_graph", "s2", "s3" }; + + if (levelIndex is >= 44 and <= 45) + return new[] { "intro", "how_graph", "s9", "rules", "int_block" }; + + if (levelIndex is >= 46 and <= 49) + return new[] { "intro", "how_graph", "rules", "exam" }; + + if (levelIndex == 50) + return new[] { "intro", "how_graph", "s10", "s3", "exam" }; + + if (levelIndex is >= 51 and <= 58) + return new[] { "intro", "how_graph", "s1", "rules" }; + + return new[] { "intro", "how_graph" }; + } +} From 6028e67c3d04d2b4571bd456d52d897540f2c9ee Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:50:34 -0400 Subject: [PATCH 13/14] Updated --- .../Resources/Localization/MathArticle/en.txt | 20 ++++ .../Scripts/Game/LearningArticleLibrary.cs | 100 +++++++++++++++++- .../Assets/Scripts/Game/LevelManager.cs | 5 +- .../Game/MathArticleLevelSectionMap.cs.meta | 11 ++ .../Assets/Scripts/UI/MathArticlesOverlay.cs | 12 ++- 5 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs.meta diff --git a/First Principles/Assets/Resources/Localization/MathArticle/en.txt b/First Principles/Assets/Resources/Localization/MathArticle/en.txt index 2a46f31..54a23c9 100644 --- a/First Principles/Assets/Resources/Localization/MathArticle/en.txt +++ b/First Principles/Assets/Resources/Localization/MathArticle/en.txt @@ -1,7 +1,9 @@ +@@SECTION=intro Math concepts — in-game reader The game First Principles takes its name from public remarks by Elon Musk on a first-principles approach to business and to solving problems in life and work—then teaches calculus-first ideas on the graph as a matching metaphor. Use Math concepts while playing, or Math tips & snippets on Level select — same scrollable notes. Tap the dark backdrop or Close to dismiss. +@@SECTION=how_graph How this game teaches calculus (read the graph while you play) Main curve — the thick path on the Cartesian grid is \(y = f(x)\) for this stage. Your character tries to stand on platforms that follow that shape. The Equation label (when visible) names the rule being plotted. @@ -17,9 +19,11 @@ Everything below is a topic glossary you can skim between deaths or after finishing a graph — plus a First principles thinking (business) section before exam prep. +@@SECTION=s1 1. Derivatives = slope & rate The derivative \(f'(x)\) measures how steeply \(f(x)\) rises or falls. In physics it is often a rate: how fast position changes (velocity), how fast temperature changes along a bar, etc. In this game, the derivative helps decide where the ground exists. +@@SECTION=rules ──────── Differentiation rules — your skill tree ──────── These are the combo moves for turning \(f(x)\) into \(f'(x)\) without rebuilding from the limit every time. Read them like perks that change how your main curve and derivative HUD stay in sync. @@ -43,6 +47,7 @@ If \(y = f(g(x))\), then \(\displaystyle \frac{dy}{dx} = f'(g(x))\cdot g'(x)\). The game still draws \(f'\) with a numeric sampler on wild stages, but these identities explain why textbook curves snap into clean forms — and what AP / TMUA expects you to simplify before you sketch. Longer write-up: docs/derivative-rules.md. +@@SECTION=int_block ──────── Integrals: definite vs indefinite — score vs loadout ──────── Indefinite \(\displaystyle \int f(x)\,dx\) asks for an antiderivative — a whole family \(F(x)+C\) whose derivative is \(f\). Think loadout class: many valid builds differ by +\(C\) (same gameplay up to vertical shift in \(F\)). Definite \(\displaystyle \int_a^b f(x)\,dx\) is a single number (signed area from \(a\) to \(b\)) — like a run score for one fixed segment. No “+\(C\)” in the answer: endpoints pin it down. @@ -54,42 +59,55 @@ Rectangles (left / right / midpoint) estimate the definite score before y More detail: docs/definite-indefinite-integrals.md. (Graphing calculator / FTC proofs — see course notes; this is the game glossary.) +@@SECTION=s2 2. Parabola (power / quadratic) A quadratic \(y = a(x-h)^2+k\) is the shape of projectile motion in ideal textbook setups and many optimization problems (min/max). One smooth hump; the slope switches sign at the vertex. +@@SECTION=s3 3. Sine & cosine = waves & rotation Sines and cosines describe vibrations, AC signals, sound, and anything that repeats. Cosine is sine shifted: same wave, different starting phase. Complex numbers (below) make these waves easier to solve in circuits and vibrations. +@@SECTION=s4 4. Absolute value & kinks \(|x|\) bends the graph so there is a corner on the axis. The derivative jumps there in ideal math — in real programs we plot smooth samples, but the idea matters: nonsmooth points need special care in analysis and simulation. +@@SECTION=s5 5. Taylor & Maclaurin series Smooth functions can be approximated near a point by polynomials with matching derivatives. Maclaurin means “expand around \(0\).” More terms usually improve the fit nearby; the full infinite sum is the series (where it converges). +@@SECTION=s6 6. Geometric series Sums \(u^0+u^1+u^2+\cdots\) appear in probability, signal processing, and digital math. When \(|u|<1\) the tail shrinks and the infinite sum has a clean closed form; that is the same mood as stability and “things settle.” +@@SECTION=s7 7. Multivariable slices Surfaces \(z = f(x,y)\) can be cut by fixing \(y=y_0\) — you get a 1D curve in \(x\). That is how higher-dimensional calculus is often reasoned about in engineering: fix all but one variable, take partial derivatives, gradients, directional slopes. +@@SECTION=s8 8. Integrals & area (Riemann sums) The definite integral \(\displaystyle \int_a^b f(x)\,dx\) is the signed area under the curve. Riemann sums chop \([a,b]\) into thin rectangles: pick sample heights (left, right, midpoint), add \(f(x^\ast)\,\Delta x\). More rectangles → closer to the true integral. +@@SECTION=s9 9. Engineering math — modeling mindset Engineering math picks tools that match the world: linear algebra for structures and networks, complex numbers / phasors for steady AC, differential equations for motion and heat, transforms (Laplace/Fourier) for signals and control. The goal is a usable model, then check it against reality. +@@SECTION=s10 10. Damped oscillation Many systems lose energy while oscillating: \(e^{-\alpha t}\sin(\omega t)\) style decay is the cartoon of that idea — envelope shrinks, oscillation persists briefly. Mechanical damping, resistor–capacitor–inductor circuits, and control systems all share this language. +@@SECTION=s11 11. Catenary & cosh A hanging cable under its own weight forms a catenary; \(\cosh\) is the hyperbolic cosine that models that ideal shape (and shows up in hyperbolic PDEs and relativity too). Different from a parabola even if both look “like arches.” +@@SECTION=s12 12. Rectified sine \(|\sin|\) Full-wave rectification flips negative lobes upward — a first step in turning AC into something closer to DC for power supplies. Corners at zeros mean derivatives jump — a reminder that idealized circuits still start from calculus intuitions. +@@SECTION=s13 13. Circle \((x-h)^2 + (y-k)^2 = R^2\) A circle is usually written implicitly. Solving for \(y\) gives two branches (\(\pm\sqrt{\cdot}\)). The game’s circle stage uses the upper semicircle so the path stays a function \(y(x)\) over one sweep. Implicit differentiation yields \(\frac{dy}{dx} = -\frac{x-h}{y-k}\); at the ends of the diameter the tangent is vertical (slope blows up). +@@SECTION=aero ──────── Aerospace engineering & aerodynamics ──────── Levels prefixed Aerospace: turn textbook flight‑vehicle math into paths you run. They are toy models for pedagogy — not CFD, flight test, or ITAR‑grade simulations. @@ -101,6 +119,7 @@ A circle is usually written implicitly. Solving for \(y\) gives two branches (\( See docs/engineering-math.md § Aerospace for a longer map. +@@SECTION=biz ──────── First principles thinking (business) ──────── Startup culture often cites Elon Musk for reviving first principles at places like Tesla / SpaceX: stop trusting “the market always prices it this way,” and instead unpack assumptions until you hit bedrock facts (materials, energy, physics, true unit costs), then reason upward into a new design. The idea is older than any one founder — but the habit matches this game’s visuals. @@ -112,6 +131,7 @@ A circle is usually written implicitly. Solving for \(y\) gives two branches (\( This is not legal, tax, or investing advice — a thinking drill you can pair with real advisors and data. Full write-up: docs/first-principles-business.md on GitHub Pages. +@@SECTION=exam ──────── Exam prep (separate tracks) ──────── Competition mathematics (contest lens) diff --git a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs index 71b73d1..5ec1d85 100644 --- a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs +++ b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs @@ -1,28 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Text; using UnityEngine; /// /// Plain-language math snippets for the in-game reader (TextMesh Pro rich text). /// Mathematical parts use LaTeX delimiters \( … \) / \[ … \]; converts them at load time. /// Body text loads from Resources/Localization/MathArticle/{language}.txt (fallback: en.txt) so every locale can ship a translation. -/// Mirror ideas in docs (MathJax on GitHub Pages). +/// Optional lines @@SECTION=id split the article; in-game can request a subset by level. /// public static class LearningArticleLibrary { private const string MathArticleResourcePrefix = "Localization/MathArticle/"; + private const string SectionDirectivePrefix = "@@SECTION="; - /// Large TMP block; per-locale file is UTF-8 with meaningful newlines. - public static string GetLevelSelectArticleRichText() + /// Full glossary (level select, or locales without section markers). + public static string GetLevelSelectArticleRichText() => GetArticleRichTextForOverlay(forLevelIndex: null); + + /// = entire article (section directive lines stripped). Otherwise sections from . + public static string GetArticleRichTextForOverlay(int? forLevelIndex) { string raw = LoadRawArticleForCurrentLanguage(); + string selected = SelectRawForOverlay(raw, forLevelIndex); + return ProcessArticleBody(selected); + } + + private static string ProcessArticleBody(string raw) + { string processed = TmpLatex.Process(raw); - // MathArticle/*.txt used XML-style & for "&"; TMP does not decode entities. return processed.Replace("&", "&"); } + private static string SelectRawForOverlay(string raw, int? forLevelIndex) + { + if (string.IsNullOrEmpty(raw) || raw.IndexOf(SectionDirectivePrefix, StringComparison.Ordinal) < 0) + return raw; + + if (forLevelIndex == null) + return StripSectionDirectiveLines(raw); + + Dictionary sections = ParseSectionDictionary(raw); + if (sections.Count == 0) + return StripSectionDirectiveLines(raw); + + IReadOnlyList keys = MathArticleLevelSectionMap.GetSectionKeysForLevel(forLevelIndex.Value); + var sb = new StringBuilder(); + foreach (string key in keys) + { + if (!sections.TryGetValue(key, out string chunk) || string.IsNullOrWhiteSpace(chunk)) + continue; + if (sb.Length > 0) + sb.Append("\n\n"); + sb.Append(chunk.Trim()); + } + + if (sb.Length == 0) + return StripSectionDirectiveLines(raw); + + return sb.ToString(); + } + + private static string StripSectionDirectiveLines(string raw) + { + string[] lines = raw.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); + var sb = new StringBuilder(); + foreach (string line in lines) + { + if (line.TrimStart().StartsWith(SectionDirectivePrefix, StringComparison.Ordinal)) + continue; + if (sb.Length > 0) + sb.Append('\n'); + sb.Append(line); + } + + return sb.ToString(); + } + + private static Dictionary ParseSectionDictionary(string raw) + { + var d = new Dictionary(StringComparer.Ordinal); + string[] lines = raw.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); + string currentKey = null; + var chunk = new StringBuilder(); + + void Flush() + { + if (currentKey != null) + d[currentKey] = chunk.ToString().TrimEnd(); + chunk.Clear(); + } + + foreach (string line in lines) + { + string t = line.Trim(); + if (t.StartsWith(SectionDirectivePrefix, StringComparison.Ordinal) && t.Length > SectionDirectivePrefix.Length) + { + Flush(); + currentKey = t.Substring(SectionDirectivePrefix.Length).Trim(); + continue; + } + + if (chunk.Length > 0) + chunk.Append('\n'); + chunk.Append(line); + } + + Flush(); + return d; + } + private static string LoadRawArticleForCurrentLanguage() { string code = LocalizationManager.CurrentLanguage; - var ta = Resources.Load($"{MathArticleResourcePrefix}{code}"); + TextAsset ta = Resources.Load($"{MathArticleResourcePrefix}{code}"); if (ta == null || string.IsNullOrWhiteSpace(ta.text)) ta = Resources.Load($"{MathArticleResourcePrefix}en"); diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 4b77ce4..4604802 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -950,7 +950,7 @@ private void CreateGameplayHudIfNeeded() CreateMathConceptsButtonIfNeeded(canvas, equationStyle); } - /// Top-right control: opens (same body as level-select math tips). + /// Top-right control: opens with math sections scoped to the current level (full glossary in graphing-calculator mode). private void CreateMathConceptsButtonIfNeeded(Canvas canvas, TextMeshProUGUI equationStyle) { if (canvas == null || GameObject.Find("MathConceptsButton") != null) @@ -979,7 +979,8 @@ private void CreateMathConceptsButtonIfNeeded(Canvas canvas, TextMeshProUGUI equ RuntimeUiPolish.ApplyButtonTransitions(btn, RuntimeUiPolish.AccentTeal, Color.Lerp(RuntimeUiPolish.AccentTeal, Color.white, 0.18f), Color.Lerp(RuntimeUiPolish.AccentTeal, Color.black, 0.25f)); - btn.onClick.AddListener(() => MathArticlesOverlay.Open(canvas.transform)); + btn.onClick.AddListener(() => MathArticlesOverlay.Open(canvas.transform, + graphCalculatorMode ? (int?)null : currentLevelIndex)); RuntimeUiPolish.ApplyDropShadow(rt, new Vector2(2f, -3f), 0.3f); var textGo = new GameObject("Text"); diff --git a/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs.meta b/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs.meta new file mode 100644 index 0000000..386eb55 --- /dev/null +++ b/First Principles/Assets/Scripts/Game/MathArticleLevelSectionMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7e2f4a91c3d405e8b6d7091a2c4e5f8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs b/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs index 16282f5..1a993e8 100644 --- a/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs +++ b/First Principles/Assets/Scripts/UI/MathArticlesOverlay.cs @@ -4,7 +4,7 @@ /// /// Full-screen scroll overlay for — opened from Level select -/// (Math tips & snippets) or from the Game scene (Math concepts). +/// (Math tips & snippets, full glossary) or from the Game scene (Math concepts, sections for the current level when the locale article uses @@SECTION= markers). /// public static class MathArticlesOverlay { @@ -12,13 +12,18 @@ public static class MathArticlesOverlay private static TextMeshProUGUI closeButtonTmp; private static TextMeshProUGUI articleBodyTmp; + /// Preserves level filter when the article reloads after a language change. + private static int? _articleLevelFilter; /// Usually the scene Canvas; overlay becomes its last sibling. - public static void Open(Transform canvasTransform) + /// = full glossary (level select). Otherwise filtered sections for that level. + public static void Open(Transform canvasTransform, int? forGameLevelIndex = null) { if (canvasTransform == null) return; + _articleLevelFilter = forGameLevelIndex; + var existing = canvasTransform.Find(OverlayName); if (existing != null) { @@ -45,6 +50,7 @@ public static void Open(Transform canvasTransform) void Close() { + _articleLevelFilter = null; LocalizationManager.LanguageChanged -= RefreshArticleBodyGlobal; articleBodyTmp = null; UnityEngine.Object.Destroy(root); @@ -200,7 +206,7 @@ private static void RefreshArticleBodyText() { if (articleBodyTmp == null) return; - articleBodyTmp.text = LearningArticleLibrary.GetLevelSelectArticleRichText(); + articleBodyTmp.text = LearningArticleLibrary.GetArticleRichTextForOverlay(_articleLevelFilter); ApplyArticleReadingLayout(articleBodyTmp); LocalizationManager.ApplyTextDirection(articleBodyTmp); var scroll = articleBodyTmp.GetComponentInParent(); From c5f6b8b0e8fb9f10313dc1ec2f2f717fd55a0328 Mon Sep 17 00:00:00 2001 From: John Seong Date: Sun, 22 Mar 2026 19:54:03 -0400 Subject: [PATCH 14/14] Update LevelManager.cs --- .../Assets/Scripts/Game/LevelManager.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs index 4604802..4f84d71 100644 --- a/First Principles/Assets/Scripts/Game/LevelManager.cs +++ b/First Principles/Assets/Scripts/Game/LevelManager.cs @@ -506,13 +506,15 @@ private void EnterGraphCalculatorMode() TightenGraphCalculatorStoryBanner(); } - // Keep score on the same panel; hide only STAGE (not meaningful in calculator). - if (stageHudText != null) - stageHudText.gameObject.SetActive(false); - if (scoreHudText != null) + // No STAGE / PTS HUD in calculator — hide the whole panel (not platformer scoring). + if (stageHudText != null && stageHudText.transform.parent != null) + stageHudText.transform.parent.gameObject.SetActive(false); + else { - scoreHudText.gameObject.SetActive(true); - RefreshScoreHud(); + if (stageHudText != null) + stageHudText.gameObject.SetActive(false); + if (scoreHudText != null) + scoreHudText.gameObject.SetActive(false); } functionPlotter.transA = 1f; @@ -1092,8 +1094,8 @@ void RefreshScoreHud() } /// - /// Stage + score share StageHudPanel. Graphing calculator hides only the stage line; platformer needs - /// both visible. Other UI can reparent later — re-activate panel + stage and bring HUD forward. + /// Stage + score share StageHudPanel. Graphing calculator hides the whole panel; platformer needs + /// both lines visible. Other UI can reparent later — re-activate panel + children and bring HUD forward. /// private void EnsurePlatformerHudPresentation() { @@ -1105,6 +1107,12 @@ private void EnsurePlatformerHudPresentation() var stagePanel = stageHudText.transform.parent.gameObject; stagePanel.SetActive(true); stageHudText.gameObject.SetActive(true); + if (scoreHudText != null) + { + scoreHudText.gameObject.SetActive(true); + RefreshScoreHud(); + } + stagePanel.transform.SetAsLastSibling(); } }