com.alicizax.unity.ui.exten.../Runtime/UXComponent/Controller/UXController.cs

274 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace AlicizaX.UI
{
[DisallowMultipleComponent]
[AddComponentMenu("UX/UX Controller")]
public sealed class UXController : MonoBehaviour
{
[Serializable]
public class ControllerData
{
[SerializeField] private string _name = "Controller";
[SerializeField] private int _length = 2;
[SerializeField] private string _description = "";
[NonSerialized] private int _currentIndex = 0;
public string Name
{
get => _name;
set => _name = value;
}
public int Length
{
get => _length;
set => _length = Mathf.Max(1, value);
}
public string Description
{
get => _description;
set => _description = value;
}
public int CurrentIndex
{
get => _currentIndex;
set => _currentIndex = value;
}
}
[SerializeField] private List<ControllerData> _controllers = new List<ControllerData>();
[SerializeField] private List<UXControllerStateRecorder> _recorders = new List<UXControllerStateRecorder>();
private Dictionary<string, int> _controllerIndexMap;
private bool _initialized = false;
#region Public API
public IReadOnlyList<ControllerData> Controllers => _controllers;
public int ControllerCount => _controllers.Count;
public ControllerHandle GetController(string name)
{
EnsureInitialized();
if (_controllerIndexMap.TryGetValue(name, out int index))
{
return new ControllerHandle(this, index);
}
return null;
}
public ControllerHandle GetControllerAt(int index)
{
if (index < 0 || index >= _controllers.Count) return null;
return new ControllerHandle(this, index);
}
public void SetControllerIndex(string name, int selectedIndex)
{
EnsureInitialized();
if (_controllerIndexMap.TryGetValue(name, out int controllerIndex))
{
SetControllerIndexInternal(controllerIndex, selectedIndex);
}
}
public int GetControllerIndex(string name)
{
EnsureInitialized();
if (_controllerIndexMap.TryGetValue(name, out int controllerIndex))
{
return _controllers[controllerIndex].CurrentIndex;
}
return 0;
}
#endregion
#region Internal API
internal IReadOnlyList<UXControllerStateRecorder> Recorders => _recorders;
internal void SetControllerIndexInternal(int controllerIndex, int selectedIndex)
{
if (controllerIndex < 0 || controllerIndex >= _controllers.Count) return;
var cd = _controllers[controllerIndex];
selectedIndex = Mathf.Clamp(selectedIndex, 0, cd.Length - 1);
if (cd.CurrentIndex == selectedIndex) return;
cd.CurrentIndex = selectedIndex;
NotifyRecorders(cd.Name, selectedIndex);
}
internal bool HasRecorder(UXControllerStateRecorder recorder)
{
if (recorder == null) return false;
return _recorders.Exists(r => r != null && r.ID == recorder.ID);
}
internal void RegisterRecorder(UXControllerStateRecorder recorder)
{
if (recorder != null && !HasRecorder(recorder))
{
_recorders.Add(recorder);
}
}
internal void UnregisterRecorder(UXControllerStateRecorder recorder)
{
if (recorder != null)
{
_recorders.RemoveAll(r => r == null || r.ID == recorder.ID);
}
}
#endregion
#region Unity Lifecycle
private void Awake()
{
InitializeRuntime();
}
private void OnValidate()
{
BuildControllerIndexMap();
}
#endregion
#region Private Methods
private void EnsureInitialized()
{
if (!_initialized)
{
BuildControllerIndexMap();
}
}
private void BuildControllerIndexMap()
{
if (_controllerIndexMap == null)
{
_controllerIndexMap = new Dictionary<string, int>();
}
else
{
_controllerIndexMap.Clear();
}
for (int i = 0; i < _controllers.Count; i++)
{
var controller = _controllers[i];
if (!string.IsNullOrEmpty(controller.Name))
{
_controllerIndexMap[controller.Name] = i;
}
}
_initialized = true;
}
private void InitializeRuntime()
{
EnsureInitialized();
for (int i = 0; i < _recorders.Count; i++)
{
if (_recorders[i] != null)
{
_recorders[i].Initialize();
}
}
for (int i = 0; i < _controllers.Count; i++)
{
SetControllerIndexInternal(i, 0);
}
}
private void NotifyRecorders(string controllerName, int selectedIndex)
{
for (int i = 0; i < _recorders.Count; i++)
{
if (_recorders[i] != null)
{
_recorders[i].OnControllerIndexChanged(controllerName, selectedIndex);
}
}
}
#endregion
#region Controller Handle
public class ControllerHandle
{
private readonly UXController _owner;
private readonly int _controllerIndex;
public ControllerHandle(UXController owner, int controllerIndex)
{
_owner = owner;
_controllerIndex = controllerIndex;
}
public bool IsValid => _owner != null && _controllerIndex >= 0 && _controllerIndex < _owner._controllers.Count;
public int SelectedIndex
{
get
{
if (!IsValid) return 0;
return _owner._controllers[_controllerIndex].CurrentIndex;
}
set
{
if (IsValid)
{
_owner.SetControllerIndexInternal(_controllerIndex, value);
}
}
}
public int Length
{
get
{
if (!IsValid) return 0;
return _owner._controllers[_controllerIndex].Length;
}
}
public string Name
{
get
{
if (!IsValid) return null;
return _owner._controllers[_controllerIndex].Name;
}
}
public string Description
{
get
{
if (!IsValid) return null;
return _owner._controllers[_controllerIndex].Description;
}
}
}
#endregion
}
}