This commit is contained in:
2025-09-17 18:56:28 +08:00
commit 54c72710a5
5244 changed files with 5717609 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Audio;
public class AudioPanel : MonoBehaviour
{
[SerializeField] private Slider masterVolumeSlider;
[SerializeField] private AudioMixer audioMixer;
private void OnEnable()
{
masterVolumeSlider.value = SettingsManager.Instance.CurrentSettings.masterVolume;
if (audioMixer == null) audioMixer = FindAnyObjectByType<AudioMixer>();
}
public void OnMasterVolumeChanged(float value)
{
SettingsManager.Instance.CurrentSettings.masterVolume = value;
SetVolume(value);
}
public void ApplySettings()
{
SetVolume(SettingsManager.Instance.CurrentSettings.masterVolume);
}
private void SetVolume(float volume)
{
if (audioMixer)
audioMixer.SetFloat("MasterVolume", Mathf.Log10(Mathf.Max(volume, 0.0001f)) * 20);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 71d4a15b9c9ec1e4d91d6be9e66bd865
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using TMPro;
using System.Collections;
public class DisplayPanel : MonoBehaviour
{
[Header("UI References")]
[SerializeField] private TMP_Dropdown resolutionDropdown;
[SerializeField] private Toggle fullscreenToggle;
[SerializeField] private Toggle borderlessToggle;
[SerializeField] private TMP_Dropdown displayDropdown;
private Resolution[] resolutions;
private void Awake()
{
InitializeResolutionDropdown();
InitializeDisplayDropdown();
}
private void OnEnable()
{
StartCoroutine(InitializeDelayed());
}
IEnumerator InitializeDelayed()
{
yield return null;
var settings = SettingsManager.Instance.CurrentSettings;
resolutionDropdown.SetValueWithoutNotify(settings.resolutionIndex);
fullscreenToggle.SetIsOnWithoutNotify(settings.fullscreen);
borderlessToggle.SetIsOnWithoutNotify(settings.borderless);
displayDropdown.SetValueWithoutNotify(settings.displayIndex);
UpdateBorderlessToggleState();
}
private void InitializeResolutionDropdown()
{
resolutions = Screen.resolutions;
resolutionDropdown.ClearOptions();
var options = new List<string>();
for (int i = 0; i < resolutions.Length; i++)
{
// ʹ<><CAB9>refreshRateRatio<69><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>refreshRate
int refreshRate = Mathf.RoundToInt((float)resolutions[i].refreshRateRatio.value);
options.Add($"{resolutions[i].width}x{resolutions[i].height} {refreshRate}Hz");
}
resolutionDropdown.AddOptions(options);
}
private void InitializeDisplayDropdown()
{
displayDropdown.ClearOptions();
var options = new List<string>();
for (int i = 0; i < Display.displays.Length; i++)
{
options.Add($"Display {i + 1}");
}
displayDropdown.AddOptions(options);
}
public void OnResolutionChanged(int index)
{
SettingsManager.Instance.CurrentSettings.resolutionIndex = index;
ApplySetResolution();
}
public void OnFullscreenChanged(bool value)
{
SettingsManager.Instance.CurrentSettings.fullscreen = value;
UpdateBorderlessToggleState();
ApplySetResolution();
}
public void OnBorderlessChanged(bool value)
{
SettingsManager.Instance.CurrentSettings.borderless = value;
ApplySetResolution();
}
public void OnDisplayChanged(int index)
{
SettingsManager.Instance.CurrentSettings.displayIndex = index;
ApplySetDisplay();
}
private void UpdateBorderlessToggleState()
{
borderlessToggle.interactable = fullscreenToggle.isOn;
if (!fullscreenToggle.isOn)
borderlessToggle.isOn = false;
ApplySetResolution();
}
public void ApplySettings()
{
ApplySetResolution();
ApplySetDisplay();
}
void ApplySetResolution()
{
if (resolutions == null) return;
var settings = SettingsManager.Instance.CurrentSettings;
Resolution res = resolutions[resolutions.Length];
if (settings.resolutionIndex< resolutions.Length)
{
res = resolutions[settings.resolutionIndex];
}
FullScreenMode mode = settings.borderless ?
FullScreenMode.FullScreenWindow :
(settings.fullscreen ? FullScreenMode.ExclusiveFullScreen : FullScreenMode.Windowed);
// ʹ<><CAB9>refreshRateRatio<69><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>refreshRate
Screen.SetResolution(
res.width,
res.height,
mode,
res.refreshRateRatio
);
}
void ApplySetDisplay()
{
var settings = SettingsManager.Instance.CurrentSettings;
if (settings.displayIndex > 0 && settings.displayIndex < Display.displays.Length)
{
Display.displays[settings.displayIndex].Activate();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b16c03c5d0a387641a3c978840f52037
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class GeneralPanel : MonoBehaviour
{
[SerializeField] private TMP_InputField serverAddressInput;
private void OnEnable()
{
serverAddressInput.text = SettingsManager.Instance.CurrentSettings.serverAddress;
}
public void OnServerAddressChanged(string value)
{
SettingsManager.Instance.CurrentSettings.serverAddress = value;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4949deb4d1315ae4790fc0068c036c04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using TMPro;
using System.Collections;
public class GraphicsPanel : MonoBehaviour
{
[Header("UI References")]
[SerializeField] private TMP_Dropdown qualityDropdown;
[SerializeField] private Toggle vsyncToggle;
[SerializeField] private Slider shadowDistanceSlider;
[SerializeField] private TMP_Dropdown antiAliasingDropdown;
[SerializeField] private Toggle bloomToggle;
[SerializeField] private Slider renderScaleSlider;
[Header("Graphics References")]
[SerializeField] private VolumeProfile urpVolumeProfile;
[Header("Quality Presets")]
[SerializeField]
private QualityPreset[] qualityPresets = new QualityPreset[4]
{
new QualityPreset("Low", 0, false, 20f, 0, false, 0.8f),
new QualityPreset("Medium", 1, false, 40f, 1, true, 1.0f),
new QualityPreset("High", 2, true, 60f, 2, true, 1.2f),
new QualityPreset("Ultra", 3, true, 100f, 2, true, 1.5f)
};
[System.Serializable]
public class QualityPreset
{
public string name;
public int qualityLevel;
public bool vsyncEnabled;
public float shadowDistance;
public int antiAliasing;
public bool bloomEnabled;
public float renderScale;
public QualityPreset(string name, int qualityLevel, bool vsyncEnabled, float shadowDistance,
int antiAliasing, bool bloomEnabled, float renderScale)
{
this.name = name;
this.qualityLevel = qualityLevel;
this.vsyncEnabled = vsyncEnabled;
this.shadowDistance = shadowDistance;
this.antiAliasing = antiAliasing;
this.bloomEnabled = bloomEnabled;
this.renderScale = renderScale;
}
}
private UniversalRenderPipelineAsset _urpAsset;
private Bloom _bloom;
private void OnEnable()
{
StartCoroutine(InitializeDelayed());
}
private IEnumerator InitializeDelayed()
{
yield return null; // <20>ȴ<EFBFBD>һ֡ȷ<D6A1><C8B7>URP<52><50>ʼ<EFBFBD><CABC>
// <20><>ȡURP Asset
_urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
if (_urpAsset == null)
{
Debug.LogError("<22>޷<EFBFBD><DEB7><EFBFBD>ȡURP Asset<65><74><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD>Ŀʹ<C4BF><CAB9>URP");
yield break;
}
// <20><>ȡBloomЧ<6D><D0A7>
if (urpVolumeProfile != null && !urpVolumeProfile.TryGet(out _bloom))
{
Debug.LogWarning("Volume Profile<6C><65>δ<EFBFBD>ҵ<EFBFBD>BloomЧ<6D><D0A7>");
}
// <20><>ʼ<EFBFBD><CABC>UI
//InitializeQualityDropdown();
var settings = SettingsManager.Instance.CurrentSettings;
qualityDropdown.SetValueWithoutNotify(settings.qualityLevel);
vsyncToggle.SetIsOnWithoutNotify(settings.vsyncEnabled);
shadowDistanceSlider.SetValueWithoutNotify(settings.shadowDistance);
antiAliasingDropdown.SetValueWithoutNotify(settings.antiAliasing);
bloomToggle.SetIsOnWithoutNotify(settings.bloomEnabled);
renderScaleSlider.SetValueWithoutNotify(settings.renderScale);
ApplySettings();
}
//private void InitializeQualityDropdown()
//{
// qualityDropdown.ClearOptions();
// foreach (var preset in qualityPresets)
// {
// qualityDropdown.options.Add(new TMP_Dropdown.OptionData(preset.name));
// }
//}
public void OnQualityChanged(int index)
{
SettingsManager.Instance.CurrentSettings.qualityLevel = index;
var settings = SettingsManager.Instance.CurrentSettings;
if (index >= 0 && index < qualityPresets.Length)
{
var preset = qualityPresets[index];
// Ӧ<><D3A6>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
vsyncToggle.SetIsOnWithoutNotify(preset.vsyncEnabled);
shadowDistanceSlider.SetValueWithoutNotify(preset.shadowDistance);
antiAliasingDropdown.SetValueWithoutNotify(preset.antiAliasing);
bloomToggle.SetIsOnWithoutNotify(preset.bloomEnabled);
renderScaleSlider.SetValueWithoutNotify(preset.renderScale);
}
// <20><><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
OnVSyncChanged(settings.vsyncEnabled);
OnShadowDistanceChanged(settings.shadowDistance);
OnAntiAliasingChanged(settings.antiAliasing);
OnBloomChanged(settings.bloomEnabled);
OnRenderScaleChanged(settings.renderScale);
}
public void OnVSyncChanged(bool value)
{
SettingsManager.Instance.CurrentSettings.vsyncEnabled = value;
QualitySettings.vSyncCount = value ? 1 : 0;
}
public void OnShadowDistanceChanged(float value)
{
SettingsManager.Instance.CurrentSettings.shadowDistance = value;
if (_urpAsset != null)
_urpAsset.shadowDistance = value;
}
public void OnAntiAliasingChanged(int index)
{
SettingsManager.Instance.CurrentSettings.antiAliasing = index;
if (_urpAsset != null)
_urpAsset.msaaSampleCount = (int)Mathf.Pow(2, index);
}
public void OnBloomChanged(bool value)
{
SettingsManager.Instance.CurrentSettings.bloomEnabled = value;
if (_bloom != null)
_bloom.active = value;
}
public void OnRenderScaleChanged(float value)
{
SettingsManager.Instance.CurrentSettings.renderScale = value;
if (_urpAsset != null)
_urpAsset.renderScale = value;
}
public void ApplySettings()
{
if (_urpAsset == null) return;
var settings = SettingsManager.Instance.CurrentSettings;
if (settings.qualityLevel != 4)
QualitySettings.SetQualityLevel(settings.qualityLevel);
QualitySettings.vSyncCount = settings.vsyncEnabled ? 1 : 0;
_urpAsset.shadowDistance = settings.shadowDistance;
_urpAsset.msaaSampleCount = (int)Mathf.Pow(2, settings.antiAliasing);
_urpAsset.renderScale = settings.renderScale;
if (_bloom != null) _bloom.active = settings.bloomEnabled;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a15301d059dcf34ea494f21cef46548
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using UnityEngine;
using System.IO;
using YooAsset;
using System;
public class SettingsManager : MonoBehaviour
{
public static SettingsManager Instance { get; private set; }
private GameSettings _currentSettings;
private SettingsWindow settingsWindow;
public GameSettings CurrentSettings => _currentSettings;
private string settingsPath;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
settingsPath = Path.Combine(Application.persistentDataPath, "settings.json");
LoadSettings();
}
public void LoadSettings()
{
if (File.Exists(settingsPath))
{
string json = File.ReadAllText(settingsPath);
_currentSettings = JsonUtility.FromJson<GameSettings>(json);
}
else
{
ResetToDefaultSettings();
}
}
public void SaveSettings()
{
string json = JsonUtility.ToJson(_currentSettings, true);
File.WriteAllText(settingsPath, json);
}
public void ResetToDefaultSettings()
{
_currentSettings = new GameSettings();
SaveSettings();
}
public void OpenSettingWindow()
{
if (settingsWindow != null)
{
settingsWindow.gameObject.SetActive(true);
}
else
{
YooAssets.LoadAssetAsync<GameObject>("SettingsWindow").Completed += (handle) =>
{
settingsWindow = GameObject.Instantiate((GameObject)handle.AssetObject, GameManager.Inst.MainUICanvas.transform).GetComponent<SettingsWindow>();
};
}
}
public void CloseSettingWindow()
{
if (settingsWindow != null)
{
settingsWindow.gameObject.SetActive(false);
}
}
}
[System.Serializable]
public class GameSettings
{
public string serverAddress = "http://127.0.0.1:8080";
public float masterVolume = 0.75f;
public int qualityLevel = 2;
public bool vsyncEnabled = true;
public float shadowDistance = 50f;
public int antiAliasing = 2;
public bool bloomEnabled = true;
public float renderScale = 1.0f;
public int resolutionIndex = 0;
public bool fullscreen = true;
public bool borderless = false;
public int displayIndex = 0;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d1ed5819e87e0f4ebbdf4dad51fcb7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using UnityEngine;
using UnityEngine.UI;
public class SettingsWindow : MonoBehaviour
{
[Header("Panels")]
public GameObject generalPanel;
public GameObject audioPanel;
public GameObject graphicsPanel;
public GameObject displayPanel;
[Header("Tab Buttons")]
public Button generalTab;
public Button audioTab;
public Button graphicsTab;
public Button displayTab;
[Header("Action Buttons")]
public Button applyButton;
public Button cancelButton;
public Button defaultsButton;
public Button quitButton;
private GameObject currentPanel;
private void Awake()
{
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ǩҳ<C7A9><D2B3>ť
generalTab.onClick.AddListener(() => SwitchPanel(generalPanel));
audioTab.onClick.AddListener(() => SwitchPanel(audioPanel));
graphicsTab.onClick.AddListener(() => SwitchPanel(graphicsPanel));
displayTab.onClick.AddListener(() => SwitchPanel(displayPanel));
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ť
applyButton.onClick.AddListener(ApplyAllSettings);
cancelButton.onClick.AddListener(CloseWindow);
defaultsButton.onClick.AddListener(ResetToDefaults);
quitButton.onClick.AddListener(() => { Application.Quit(); });
// Ĭ<>ϴ򿪵<CFB4>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SwitchPanel(generalPanel);
}
private void SwitchPanel(GameObject newPanel)
{
if (currentPanel != null)
currentPanel.SetActive(false);
newPanel.SetActive(true);
currentPanel = newPanel;
UpdateTabButtons();
}
private void UpdateTabButtons()
{
generalTab.interactable = currentPanel != generalPanel;
audioTab.interactable = currentPanel != audioPanel;
graphicsTab.interactable = currentPanel != graphicsPanel;
displayTab.interactable = currentPanel != displayPanel;
}
public void ApplyAllSettings()
{
// Ӧ<><D3A6><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD>ã<EFBFBD><C3A3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ִ<EFBFBD>У<EFBFBD>
displayPanel.GetComponent<DisplayPanel>().ApplySettings();
// Ӧ<><D3A6>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
graphicsPanel.GetComponent<GraphicsPanel>().ApplySettings();
// Ӧ<><D3A6><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
audioPanel.GetComponent<AudioPanel>().ApplySettings();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SettingsManager.Instance.SaveSettings();
CloseWindow();
}
public void CloseWindow()
{
// <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD>
SettingsManager.Instance.LoadSettings();
gameObject.SetActive(false);
}
public void ResetToDefaults()
{
SettingsManager.Instance.ResetToDefaultSettings();
SwitchPanel(currentPanel); // ˢ<>µ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d6ce7fe9c8bcb144bfed87170589a6e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: