Die Figuren (Einheiten, Monster, Völker, Helden) bekommen den Materialweg der Welt; dazu Umgebungsverdeckung für die ganze Szene. - Surface-Materialien für alle 146 Figurenmaterialien (142 neu unter Materials/Units/, die LN_Boss_* gehörten schon zu den Gebäuden). Farbe, Rauigkeit und Emission bleiben die Blender-Werte; Metalle werden metallisch (vorher war keines der 414 Figurenmaterialien metallisch), ein Randlicht hebt die Silhouetten im Draufblick vom Boden ab. - Oberflächenstruktur je Materialfamilie im eigenen Raum der Figur, nur in den HUD-Porträts. Im Feld (30-60 px hohe Figuren) war sie nicht zu sehen und kostete rund 10 % Bildrate. - Ringborkes 4k-Satz liegt am Schnittholz (RB_Cutwood), wohin er gehört; U5.3 hatte ihn an die Rinde gebunden. Verwaistes RB_Bark.mat entfernt. - SSAO über LuneProjectSetup: nach den opaken Objekten, halbe Auflösung, Radius 0,35 m, Ausblendung ab 260 m. Standardmäßig an (Entscheidung des Projektinhabers), in den Optionen abschaltbar, -luneSsao 0 für eine Sitzung. Die Variante mit Tiefen-Normalen-Vorpass kostete 19-28 %. - Shader: Steinreliefkarte nur noch für Gelände, Stein, Pflaster, Erde. - Werkzeug: Übersichtsbilder mit LUNE_DRESS=1 eingekleidet wie im Spiel; das Materialset wird nach der leeren Vorschauszene geladen (sie entlädt unreferenzierte Assets). - Tests: EditMode 29/29, PlayMode 14/14, Verify 718/0, Player-Selbsttest 30/30 (4 neue zur SSAO-Option), Fingerabdrücke unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5). - Leistung (A/B mit U5.3 im selben Lauf): Mid nah 177,7 -> 148,5 fps (-16 %), Karte 127,8 -> 111,5 fps (-13 %); ohne SSAO -3,5 / -4,5 %. - Doku: U5-VISUAL (U5.4), PORT-STATUS, PORT-QA; Bilder screenshots/u5.4/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
4.2 KiB
C#
127 lines
4.2 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Luneraria.UI
|
|
{
|
|
/// <summary>
|
|
/// Player preferences of the HUD and options (port of scripts/autoload/preferences.gd as far as
|
|
/// the HUD uses it): UI size, reduced motion, volume, mute, full screen; since U5.4 also the
|
|
/// ambient occlusion (SSAO). Stored in PlayerPrefs. Tests can set values without touching the
|
|
/// stored ones (Persist = false); "-luneSsao 0|1" on the command line overrides the SSAO choice
|
|
/// for one session (benchmark).
|
|
/// </summary>
|
|
public static class LunePreferences
|
|
{
|
|
public static event Action Changed;
|
|
/// <summary>False in tests: values change for the session only.</summary>
|
|
public static bool Persist = true;
|
|
|
|
static float _uiScale = -1f;
|
|
static int _reducedMotion = -1;
|
|
static float _volume = -1f;
|
|
static int _muted = -1;
|
|
static int _fullscreen = -1;
|
|
static int _ambientOcclusion = -1;
|
|
|
|
public static float UiScale
|
|
{
|
|
get
|
|
{
|
|
if (_uiScale < 0f)
|
|
_uiScale = PlayerPrefs.GetFloat("lune.ui_scale", 1f);
|
|
return _uiScale;
|
|
}
|
|
set { _uiScale = value; Save("lune.ui_scale", value); }
|
|
}
|
|
|
|
public static bool ReducedMotion
|
|
{
|
|
get
|
|
{
|
|
if (_reducedMotion < 0)
|
|
_reducedMotion = PlayerPrefs.GetInt("lune.reduced_motion", 0);
|
|
return _reducedMotion == 1;
|
|
}
|
|
set { _reducedMotion = value ? 1 : 0; Save("lune.reduced_motion", _reducedMotion); }
|
|
}
|
|
|
|
public static float Volume
|
|
{
|
|
get
|
|
{
|
|
if (_volume < 0f)
|
|
_volume = PlayerPrefs.GetFloat("lune.volume", .8f);
|
|
return _volume;
|
|
}
|
|
set { _volume = Mathf.Clamp01(value); Save("lune.volume", _volume); }
|
|
}
|
|
|
|
public static bool Muted
|
|
{
|
|
get
|
|
{
|
|
if (_muted < 0)
|
|
_muted = PlayerPrefs.GetInt("lune.muted", 0);
|
|
return _muted == 1;
|
|
}
|
|
set { _muted = value ? 1 : 0; Save("lune.muted", _muted); }
|
|
}
|
|
|
|
public static bool Fullscreen
|
|
{
|
|
get
|
|
{
|
|
if (_fullscreen < 0)
|
|
_fullscreen = PlayerPrefs.GetInt("lune.fullscreen", Screen.fullScreen ? 1 : 0);
|
|
return _fullscreen == 1;
|
|
}
|
|
set { _fullscreen = value ? 1 : 0; Save("lune.fullscreen", _fullscreen); }
|
|
}
|
|
|
|
/// <summary>Screen-space ambient occlusion of the renderer (U5.4); on by default.</summary>
|
|
public static bool AmbientOcclusion
|
|
{
|
|
get
|
|
{
|
|
if (_ambientOcclusion < 0)
|
|
{
|
|
string[] args = Environment.GetCommandLineArgs();
|
|
int at = Array.IndexOf(args, "-luneSsao");
|
|
_ambientOcclusion = at >= 0 && at + 1 < args.Length ? (args[at + 1] == "0" ? 0 : 1) : PlayerPrefs.GetInt("lune.ambient_occlusion", 1);
|
|
}
|
|
return _ambientOcclusion == 1;
|
|
}
|
|
set { _ambientOcclusion = value ? 1 : 0; Save("lune.ambient_occlusion", _ambientOcclusion); }
|
|
}
|
|
|
|
static void Save(string key, float value)
|
|
{
|
|
if (Persist)
|
|
PlayerPrefs.SetFloat(key, value);
|
|
Changed?.Invoke();
|
|
}
|
|
|
|
static void Save(string key, int value)
|
|
{
|
|
if (Persist)
|
|
PlayerPrefs.SetInt(key, value);
|
|
Changed?.Invoke();
|
|
}
|
|
|
|
/// <summary>Writes pending values (Godot Preferences.commit).</summary>
|
|
public static void Commit()
|
|
{
|
|
if (Persist)
|
|
PlayerPrefs.Save();
|
|
}
|
|
|
|
/// <summary>Session values back to defaults (tests).</summary>
|
|
public static void ResetSession(float uiScale = 1f, bool reducedMotion = false)
|
|
{
|
|
Persist = false;
|
|
_uiScale = uiScale;
|
|
_reducedMotion = reducedMotion ? 1 : 0;
|
|
Changed?.Invoke();
|
|
}
|
|
}
|
|
}
|