发包版本

This commit is contained in:
SoulliesOfficial
2026-07-26 09:32:51 -04:00
parent a00046128d
commit 923fc5359f
124 changed files with 1252 additions and 387 deletions

View File

@@ -32,7 +32,7 @@ namespace Ichni.RhythmGame
// 1.0 = 纯线性(效果太弱)
// 0.5 = 接近对数(效果太强)
// 0.65 = 推荐起点,可根据实际测试微调(向 1.0 调弱,向 0.5 调强)
private const float PowerExponent = 0.25f;
private const float PowerExponent = 0.35f;
#endregion
#region [] Initialization

View File

@@ -30,7 +30,7 @@ namespace Ichni.RhythmGame
// 1.0 = 纯线性(效果太弱)
// 0.5 = 接近对数(效果太强)
// 0.65 = 推荐起点,可根据实际测试微调(向 1.0 调弱,向 0.5 调强)
private const float PowerExponent = 0.25f;
private const float PowerExponent = 0.35f;
#endregion
#region [] Initialization

View File

@@ -1,4 +1,5 @@
using Ichni.Menu;
using Ichni.UI;
using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
@@ -112,6 +113,7 @@ namespace Ichni
{
string savePath = Application.persistentDataPath + "/GameData/" + SettingsSaveFileName;
bool migratedLegacyLanguageIndex = false;
bool migratedUiEffectsSetting = false;
if (ES3.FileExists(savePath))
{
// 保留原有 ES3 Key确保本次数据模型重命名不会让已有本地设置失效。
@@ -123,12 +125,13 @@ namespace Ichni
}
migratedLegacyLanguageIndex = MigrateLanguageCodeIfNeeded();
migratedUiEffectsSetting = MigrateUiEffectsSettingIfNeeded();
ApplyAudioSettings();
ApplyGraphicSettings();
ApplyLanguageSettings();
// 旧语言索引只应参与一次迁移;立刻写回稳定 Code避免每次启动都重复依赖旧字段。
if (migratedLegacyLanguageIndex)
if (migratedLegacyLanguageIndex || migratedUiEffectsSetting)
{
SaveGameSettings();
}
@@ -176,6 +179,7 @@ namespace Ichni
currentUrpAsset.renderScale = 0.5f + 0.1f * settingsSaveData.renderScaleLevel;
ApplyDisplaySettings();
ApplyPostProcessingSettings();
ApplyUiEffectsSettings();
}
/// <summary>
@@ -206,6 +210,33 @@ namespace Ichni
}
}
/// <summary>
/// 应用 UI 特效总开关。
/// <para>
/// 仅处理显式挂载 <see cref="UiExpandingContoursEffect"/> 的装饰性 UI Image而不修改共享材质本身。
/// 这样关闭特效时会移除对应 Shader 的绘制开销,同时保留页面布局和其它 UI 元素。
/// </para>
/// <para>
/// 使用 Include 是为了让当前处于隐藏状态的 SongSelectionPage、SettingsPage 也同步保存目标状态;
/// 它们下次显示时无需再经过一帧特效可见的过渡。
/// </para>
/// </summary>
public void ApplyUiEffectsSettings()
{
if (settingsSaveData == null)
{
return;
}
UiExpandingContoursEffect[] effectTargets =
FindObjectsByType<UiExpandingContoursEffect>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (UiExpandingContoursEffect effectTarget in effectTargets)
{
effectTarget.ApplyEnabledState(settingsSaveData.enableUiEffects);
}
}
/// <summary>
/// 处理场景切换后新加载的相机与 Global Volume。SettingsManager 会跨场景保留,
/// 因此不能只在首次读取存档时应用一次图形设置。
@@ -215,6 +246,7 @@ namespace Ichni
if (settingsSaveData != null)
{
ApplyPostProcessingSettings();
ApplyUiEffectsSettings();
}
}
@@ -266,6 +298,7 @@ namespace Ichni
private SettingsSaveData CreateDefaultSettingsSaveData()
{
SettingsSaveData defaultSettings = new SettingsSaveData();
defaultSettings.uiEffectsSettingInitialized = true;
defaultSettings.languageCode = DefaultLocaleCode;
defaultSettings.languageIndex = GetLanguageDropdownIndex(DefaultLocaleCode);
defaultSettings.graphicsQualityPreset = GetGraphicsQualityPreset(QualitySettings.GetQualityLevel());
@@ -277,6 +310,25 @@ namespace Ichni
return defaultSettings;
}
/// <summary>
/// 将旧版 SettingsSave 中不存在的 UI 特效开关迁移为默认开启。
/// <para>
/// 不提升 Schema Version项目尚未发布且本字段只补齐一个布尔默认值。迁移标记会随即写回 ES3
/// 之后玩家主动关闭 UI 效果时不会被再次覆盖。
/// </para>
/// </summary>
private bool MigrateUiEffectsSettingIfNeeded()
{
if (settingsSaveData.uiEffectsSettingInitialized)
{
return false;
}
settingsSaveData.enableUiEffects = true;
settingsSaveData.uiEffectsSettingInitialized = true;
return true;
}
private FullScreenMode GetFullScreenMode(GraphicsDisplayMode displayMode)
{
return displayMode switch

View File

@@ -109,6 +109,19 @@ namespace Ichni
/// </summary>
public VfxQuality vfxQuality = VfxQuality.High;
/// <summary>
/// UI 特效总开关。当前控制使用 <c>UI_ExpandingContours</c> Shader 的装饰性 Image
/// 关闭后会停止这些 Image 的绘制,以降低选曲与设置页面在移动设备上的 GPU 开销。
/// </summary>
public bool enableUiEffects = true;
/// <summary>
/// UI 特效开关的迁移标记。
/// 早于该字段的 ES3 存档没有此标记SettingsManager 读取到 false 时会将 UI 特效安全地初始化为开启,
/// 从而保证新增设置不会在旧存档中意外以关闭状态首次出现。
/// </summary>
public bool uiEffectsSettingInitialized;
// Desktop display settings. These values are saved on every platform but only applied on PC and in the Unity Editor.
public bool vSyncEnabled = false;
public GraphicsDisplayMode displayMode = GraphicsDisplayMode.BorderlessFullscreen;

View File

@@ -0,0 +1,56 @@
using UnityEngine;
using UnityEngine.UI;
namespace Ichni.UI
{
/// <summary>
/// 将装饰性 UI Image 纳入「UI 效果」图形设置。
/// <para>
/// 此组件应只挂在使用 <c>UI_ExpandingContours</c> 等可选视觉 Shader 的 Image 上。
/// 关闭设置时仅禁用目标 Image 的绘制,不会停用 GameObject因此布局与子物体状态不受影响。
/// 目标应为不承载输入的装饰性 Image。
/// </para>
/// <para>
/// 新增同类 UI 特效时,只需在对应 Image 上添加本组件;无需再在 SettingsManager 中硬编码页面或物体名称。
/// </para>
/// </summary>
[DisallowMultipleComponent]
[RequireComponent(typeof(Graphic))]
public sealed class UiExpandingContoursEffect : MonoBehaviour
{
[SerializeField] private Graphic targetGraphic;
private void Reset()
{
targetGraphic = GetComponent<Graphic>();
}
private void Awake()
{
if (targetGraphic == null)
{
targetGraphic = GetComponent<Graphic>();
}
}
private void OnEnable()
{
// 页面首次显示或从隐藏状态恢复时,重新读取已经加载的玩家设置。
bool enableUiEffects = SettingsManager.instance?.settingsSaveData?.enableUiEffects ?? true;
ApplyEnabledState(enableUiEffects);
}
/// <summary>
/// 设置目标 Image 是否参与绘制。由 SettingsManager 在载入存档、场景切换和玩家切换开关时调用。
/// </summary>
public void ApplyEnabledState(bool enableUiEffects)
{
if (targetGraphic == null)
{
targetGraphic = GetComponent<Graphic>();
}
targetGraphic.enabled = enableUiEffects;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e47bc8701d1c446184bf62bffaf104f2

View File

@@ -48,6 +48,7 @@ namespace Ichni.Menu
public Switch postProcessingSwitch;
public Dropdown bloomQualityDropdown;
public Dropdown vfxQualityDropdown;
public Switch uiEffectsSwitch;
public Switch vSyncSwitch;
public Dropdown displayModeDropdown;
public Dropdown displayResolutionDropdown;
@@ -78,6 +79,7 @@ namespace Ichni.Menu
};
InitializePostProcessingSettings();
InitializeUiEffectsSettings();
#if UNITY_STANDALONE || UNITY_EDITOR
InitializeDesktopDisplaySettings();
@@ -101,6 +103,11 @@ namespace Ichni.Menu
vfxQualityDropdown.SetValue((int)gameSettings.vfxQuality);
}
if (uiEffectsSwitch != null)
{
uiEffectsSwitch.SetValue(gameSettings.enableUiEffects);
}
#if UNITY_STANDALONE || UNITY_EDITOR
vSyncSwitch.SetValue(gameSettings.vSyncEnabled);
displayModeDropdown.SetValue((int)gameSettings.displayMode);
@@ -141,6 +148,27 @@ namespace Ichni.Menu
};
}
/// <summary>
/// 初始化 UI 特效开关。
/// 它独立于后处理和 VFX 质量:关闭后只停止标记为 UiExpandingContoursEffect 的 UI Image 绘制,
/// 不会影响游戏内 Note 特效、相机后处理或普通 UI。
/// </summary>
private void InitializeUiEffectsSettings()
{
// 兼容尚未补齐新控件的旧 Settings Prefab完成界面布置后必须在 Inspector 绑定该引用。
if (uiEffectsSwitch == null)
{
return;
}
uiEffectsSwitch.SetUp(gameSettings.enableUiEffects);
uiEffectsSwitch.updateValueAction = () =>
{
gameSettings.enableUiEffects = uiEffectsSwitch.GetValue();
SettingsManager.instance.ApplyUiEffectsSettings();
};
}
#if UNITY_STANDALONE || UNITY_EDITOR
private void InitializeDesktopDisplaySettings()
{