首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
using UnityEngine;
using UnityEngine.UI;
namespace Ilumisoft.GraphicsControl.UI
{
[RequireComponent(typeof(Button))]
public class ApplySettingsButton : MonoBehaviour
{
Button Button { get; set; }
private void Awake()
{
Button = GetComponent<Button>();
Button.onClick.AddListener(OnClick);
}
private void OnClick()
{
GraphicSettingsManager.Instance.ApplySettings();
GraphicSettingsManager.Instance.SaveSettings();
}
}
}

View File

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

View File

@@ -0,0 +1,118 @@
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Ilumisoft.GraphicsControl.UI
{
/// <summary>
/// <see cref="UnityEngine.UI.ScrollRect"/> does not automatically scroll up or down when using the keyboard or gamepad.
/// This class automatically handles scrolling, by scrolling towards the selected element of a <see cref="UnityEngine.UI.ScrollRect"/> when selection changes.
/// </summary>
[RequireComponent(typeof(ScrollRect))]
[DefaultExecutionOrder(1)]
public class AutoScrollHandler : MonoBehaviour
{
/// <summary>
/// The currently selected game object
/// </summary>
GameObject selected = null;
/// <summary>
/// The previously selected game object
/// </summary>
GameObject previousSelected = null;
[SerializeField]
[Tooltip("Scroll speed when changing selection")]
float scrollSpeed = 5.0f;
/// <summary>
/// Reference to the controlled <see cref="UnityEngine.UI.ScrollRect"/> component
/// </summary>
ScrollRect ScrollRect { get; set; }
private void Awake()
{
ScrollRect = GetComponent<ScrollRect>();
}
private void Start()
{
selected = EventSystem.current.currentSelectedGameObject;
previousSelected = selected;
// Auto focus the first element
ScrollRect.verticalScrollbar.value = 1;
}
void Update()
{
selected = EventSystem.current.currentSelectedGameObject;
// Check whether the selection has changed
if (selected != previousSelected)
{
previousSelected = selected;
if (selected != null)
{
OnSelectionChanged();
}
}
}
/// <summary>
/// Scroll towards the selected element when the selection has changed
/// </summary>
void OnSelectionChanged()
{
if (TryGetIndex(selected, out var index))
{
StopAllCoroutines();
StartCoroutine(ScrollTowards(index));
}
}
/// <summary>
/// Tries to get the index of the given element in the content
/// </summary>
/// <param name="element"></param>
/// <param name="index"></param>
/// <returns></returns>
bool TryGetIndex(GameObject element, out int index)
{
index = 0;
foreach (Transform child in ScrollRect.content)
{
if (element == child.gameObject)
{
return true;
}
index++;
}
return false;
}
/// <summary>
/// Scrolls towards the content element with the given index
/// </summary>
/// <param name="targetIndex"></param>
/// <returns></returns>
IEnumerator ScrollTowards(int targetIndex)
{
var scrollbar = ScrollRect.verticalScrollbar;
float target = 1 - targetIndex / (float)(ScrollRect.content.childCount - 1);
while (Mathf.Abs(scrollbar.value - target) > 0.01f)
{
scrollbar.value = Mathf.MoveTowards(scrollbar.value, target, scrollSpeed * Time.deltaTime);
yield return null;
}
}
}
}

View File

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

View File

@@ -0,0 +1,140 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace Ilumisoft.GraphicsControl.UI
{
/// <summary>
/// Default implementation of the <see cref="MultiOptionSelector"/>.
/// </summary>
[RequireComponent(typeof(AudioSource))]
public class DefaultMultiOptionSelector : MultiOptionSelector, IMoveHandler
{
[Header("Text")]
[SerializeField]
TMPro.TextMeshProUGUI labelText;
[SerializeField]
TMPro.TextMeshProUGUI valueText;
[Header("Audio")]
[SerializeField]
AudioClip selectionChangedSFX;
[SerializeField]
AudioClip verticalMovementSFX;
[Header("Settings")]
[Tooltip("When enabled, the selector will loop through the options when reaching the limits.")]
[SerializeField]
bool loop = true;
/// <summary>
/// The index of the current selection
/// </summary>
int currentIndex = 0;
/// <summary>
/// A list of all possible values
/// </summary>
List<string> Values;
/// <summary>
/// Event being invoked when the index has been changed
/// </summary>
UnityAction<int> OnSelectionChanged { get; set; }
/// <summary>
/// Reference to the Audio Source Component
/// </summary>
AudioSource AudioSource { get; set; }
private void Awake()
{
AudioSource = GetComponent<AudioSource>();
}
public override void Initialize(string label, List<string> values, int index, UnityAction<int> onSelectionChanged)
{
OnSelectionChanged += onSelectionChanged;
labelText.text = label;
Values = values;
currentIndex = index;
UpdateValueText();
}
public void OnMove(AxisEventData eventData)
{
Move(eventData.moveVector);
}
/// <summary>
/// Selects the next option
/// </summary>
public void SelectNextOption() => Move(Vector2.right);
/// <summary>
/// Selects the previous Option
/// </summary>
public void SelectPreviousOption() => Move(Vector2.left);
private void Move(Vector2 direction)
{
int previousIndex = currentIndex;
// Increase the index when moving to the right
if (direction.x > 0)
{
currentIndex++;
if (currentIndex >= Values.Count)
{
currentIndex = loop ? 0 : Values.Count - 1;
}
}
// Decrease the index when moving to the left
if (direction.x < 0)
{
currentIndex--;
if (currentIndex < 0)
{
currentIndex = loop ? Values.Count - 1 : 0;
}
}
if (direction.y != 0)
{
if (AudioSource != null && verticalMovementSFX != null)
{
PlayAudioFeedback(verticalMovementSFX);
}
}
// Check whether the index has changed
if (previousIndex != currentIndex)
{
OnSelectionChanged?.Invoke(currentIndex);
UpdateValueText();
PlayAudioFeedback(selectionChangedSFX);
}
}
void UpdateValueText()
{
valueText.text = Values[currentIndex];
}
void PlayAudioFeedback(AudioClip audioClip)
{
if (AudioSource != null && audioClip != null)
{
AudioSource.PlayOneShot(audioClip);
}
}
}
}

View File

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

View File

@@ -0,0 +1,55 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Ilumisoft.GraphicsControl.UI
{
public class GraphicSettingsPanel : MonoBehaviour
{
[SerializeField]
[Tooltip("The parent object all UI selectors will be added to. This would be for example the content GameObject of a ScrollView")]
Transform container;
[SerializeField]
MultiOptionSelector MultiOptionSelectorPrefab;
/// <summary>
/// Reference to the Graphic Settings Manager
/// </summary>
GraphicSettingsManager GraphicSettingsManager { get; set; }
private void Awake()
{
GraphicSettingsManager = FindObjectOfType<GraphicSettingsManager>();
}
private void Start()
{
// Get all graphic settings
var settings = GraphicSettingsManager.GetGraphicSettings();
// List holding all selectors
List<GameObject> selectors = new();
// Create the appropriate selector UI elements for each setting
foreach (var setting in settings)
{
if (setting is IMultiOptionGraphicSetting multiOptionSettings)
{
var multiOptionSelector = Instantiate(MultiOptionSelectorPrefab, container);
multiOptionSelector.Initialize(setting.GetSettingName(), multiOptionSettings.GetOptionNames(), multiOptionSettings.GetIndex(), multiOptionSettings.SetIndex);
selectors.Add(multiOptionSelector.gameObject);
}
}
// Automatically select the first element
if (selectors.Count > 0)
{
EventSystem.current.SetSelectedGameObject(selectors[0]);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3074d3c0feba9fc4f84a74849ac39d65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: cde92c4be2e51894bb915456c3d44460, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "Ilumisoft.GraphicsControl.UI",
"rootNamespace": "",
"references": [
"GUID:7f595fd175e67274183d17fac15b74c9",
"GUID:6055be8ebefd69e48b49212b09b47b2f"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0f167fb3726278c4481b9f96f60458bd
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Ilumisoft.GraphicsControl.UI
{
public abstract class MultiOptionSelector : MonoBehaviour
{
public abstract void Initialize(string label, List<string> values, int index, UnityAction<int> onSelectionChanged);
}
}

View File

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

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace Ilumisoft.GraphicsControl.UI
{
public class PointerDownHandler : MonoBehaviour, IPointerDownHandler
{
public UnityEvent OnClick = new();
public void OnPointerDown(PointerEventData eventData)
{
OnClick.Invoke();
}
}
}

View File

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