using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; public class SliderControl : MonoBehaviour { public event Action OnSelectedState; // [SerializeField] private ParticleSystem _selectPoofPrefab = null; //[SerializeField] private ParticleSystem _selectGlowPrefab = null; private int ItemsCount => _itemsDictionary?.Count ?? 0; private Transform _circleBackgroundsParent; private Transform _circleForegroundsParent; private Transform _circleBackgroundTemplate; private Transform _circleForegroundTemplate; private Transform[] _circlesForeground; private Transform[] _circlesBackground; private Transform _backgroundLine; //private ParticleSystem _selectPoof = null; // private ParticleSystem _selectGlow = null; private Canvas _canvas = null; private GameObject _itemTemplate = null; private Slider _slider = null; private SliderHandle _handle = null; private Dictionary _itemsDictionary = null; private const float SLIDER_SPEED = 20f; private void Awake() { _canvas = UI.Canvas; _itemTemplate = transform.Find("ItemsPanel/Items/ItemTemplate").gameObject; _slider = transform.Find("Slider").gameObject.GetComponent(); _handle = transform.Find("Slider/Handle Slide Area/Handle").gameObject.GetComponent(); _circleBackgroundsParent = transform.Find("ItemsPanel/Background/CircleBackgrounds"); _circleForegroundsParent = transform.Find("ItemsPanel/Background/CircleForegrounds"); _backgroundLine = transform.Find("ItemsPanel/Background/Line"); _circleBackgroundTemplate = _circleBackgroundsParent.Find("CircleTemplate"); _circleBackgroundTemplate.gameObject.SetActive(false); _circleForegroundTemplate = _circleForegroundsParent.Find("CircleTemplate"); _circleForegroundTemplate.gameObject.SetActive(false); } private void Start() { // _selectPoof = Instantiate(_selectPoofPrefab, _canvas.transform); // _selectPoof.Stop(); // // _selectGlow = Instantiate(_selectGlowPrefab, _handle.transform); // _selectGlow.Stop(); _handle.SetShowState(false); } public void SetControlStates(IReadOnlyList argument) { Refresh(); CreateControls(argument); // CreateBackgroundCircles(argument.Count); // CreateForegroundCircles(argument.Count); CreateCircles(_circleBackgroundTemplate, argument.Count, _circleBackgroundsParent, out _circlesBackground); CreateCircles(_circleForegroundTemplate, argument.Count, _circleForegroundsParent, out _circlesForeground); StartCoroutine(SyncLineWidthAfterFrame()); StartCoroutine(SyncSliderWidthAfterFrame()); SetItemListeners(); _itemTemplate.SetActive(false); } private IEnumerator SyncLineWidthAfterFrame() { yield return null; SyncLineWidth(); } private IEnumerator SyncSliderWidthAfterFrame() { yield return null; SyncSliderWidth(); } private void Refresh() { if (ItemsCount == 0) return; foreach (SliderItem item in _itemsDictionary.Values) Destroy(item.gameObject); _itemsDictionary.Clear(); for (int i = _circlesBackground.Length - 1; i >= 0; i--) Destroy(_circlesBackground[i].gameObject); for (int i = _circlesForeground.Length - 1; i >= 0; i--) Destroy(_circlesForeground[i].gameObject); _circlesBackground = new Transform[0]; _circlesForeground = new Transform[0]; } private void CreateControls(IReadOnlyList states) { _itemsDictionary = new Dictionary(); for (int i = 0; i < states.Count && i < 3; i++) { SliderItem item = Instantiate(_itemTemplate, _itemTemplate.transform.parent).AddComponent(); item.gameObject.SetActive(true); // как то вытянуть спрайты // item.SetSpritesForStates(states[i].icon, states[i].icon); _itemsDictionary.Add(states[i], item); } } private void CreateCircles(Transform prefab, int count, Transform parent, out Transform[] container) { container = new Transform[count]; for (int i = 0; i < count; i++) { GameObject circle = Instantiate(prefab.gameObject, parent); circle.SetActive(true); container[i] = circle.transform; } } private void SyncLineWidth() { int itemsCount = 0; if (_circlesBackground != null) itemsCount = _circlesBackground.Length; if (itemsCount == 0) _backgroundLine.GetComponent().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0); else { float xPositionFirstCircle = _circlesBackground[0].GetComponent().anchoredPosition.x; float xPositionLastCircle = _circlesBackground[_circlesBackground.Length - 1].GetComponent().anchoredPosition.x; _backgroundLine.GetComponent().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Mathf.Abs(xPositionFirstCircle - xPositionLastCircle)); } } private void SyncSliderWidth() { int itemsCount = 0; if (_circlesBackground != null) itemsCount = _circlesBackground.Length; if (itemsCount == 0) _slider.GetComponent().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0); else { float xPositionFirstCircle = _circlesBackground[0].GetComponent().anchoredPosition.x; float xPositionLastCircle = _circlesBackground[_circlesBackground.Length - 1].GetComponent().anchoredPosition.x; _slider.GetComponent().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Mathf.Abs(xPositionFirstCircle - xPositionLastCircle) + 217); } _slider.maxValue = itemsCount == 0 ? 0 : itemsCount - 1; } public void SetActiveItemForState(uint state) { SliderItem desiredActiveItem = GetButtonFromState(state); if(desiredActiveItem == null) return; SetOnlyActiveItem(desiredActiveItem); } private SliderItem GetItem(int index) { return _itemsDictionary.Values.ElementAt(index); } private void SetItemListeners() { for (int i = 0; i < ItemsCount; i++) GetItem(i).OnClick += OnItemClick; } private void Update() { #if UNITY_EDITOR CheckKeyboardInput(); #endif _handle.SetShowState(HaveActiveItem()); if (!_handle.IsShowing) return; if (_handle.HandleIsPressed) HandleIsPressedUpdate(); else HandleIsUnpressedUpdate(); } private void CheckKeyboardInput() { #if UNITY_EDITOR if (Input.GetKeyDown(KeyCode.A)) { if(ItemsCount < 1) return; OnItemClick(GetItem(0)); } else if (Input.GetKeyDown(KeyCode.S)) { if(ItemsCount < 2) return; OnItemClick(GetItem(1)); } else if (Input.GetKeyDown(KeyCode.D)) { if(ItemsCount < 3) return; OnItemClick(GetItem(2)); } #endif } private void HandleIsPressedUpdate() { float sliderValue = _slider.value; SliderItem desiredActiveItem = GetDesiredActiveItemFromSliderValue(sliderValue); SliderItem currentActiveItem = GetActiveItem(); if (desiredActiveItem != currentActiveItem) { PlaySelectView(_handle.transform.position, _handle.transform.position); OnSelectedState?.Invoke(GetStateFromButton(desiredActiveItem)); SetActiveItemForState(GetStateFromButton(desiredActiveItem)); } } private void PlaySelectView(Vector3 poofPosition, Vector3 glowPosition) { // _selectPoof.Stop(); // _selectGlow.Stop(); // // _selectPoof.transform.position = poofPosition; // _selectGlow.transform.position = glowPosition; // // _selectPoof.Play(); // _selectGlow.Play(); } private void HandleIsUnpressedUpdate() { float desiredSliderValue = GetDesiredSliderValue(); _slider.value = Mathf.MoveTowards(_slider.value, desiredSliderValue, SLIDER_SPEED * Time.deltaTime); } private void OnItemClick(SliderItem item) { PlaySelectView(item.transform.position, _handle.transform.position); OnSelectedState?.Invoke(GetStateFromButton(item)); SetActiveItemForState(GetStateFromButton(item)); } private void SetOnlyActiveItem(SliderItem item) { if (GetActiveItem() == item) return; if (item == null) return; bool previousActiveItemIsNull = !HaveActiveItem(); for (int i = 0; i < ItemsCount; i++) GetItem(i).SetActiveState(item == GetItem(i)); _handle.SetHandleSprite(item.ActiveSprite); if (previousActiveItemIsNull) _slider.value = GetDesiredSliderValue(); } private SliderItem GetActiveItem() { int activeItemIndex = GetActiveItemIndex(); bool isCorrectItemIndex = activeItemIndex >= 0 && activeItemIndex < ItemsCount; return isCorrectItemIndex ? GetItem(activeItemIndex) : null; } private int GetActiveItemIndex() { for (int i = 0; i < ItemsCount; i++) { if (GetItem(i).IsActive) return i; } return -1; } private bool HaveActiveItem() { return GetActiveItem() != null; } private float GetDesiredSliderValue() { if (!HaveActiveItem()) return _slider.value; return GetActiveItemIndex(); } private SliderItem GetDesiredActiveItemFromSliderValue(float sliderValue) { for (int i = 0; i < ItemsCount; i++) { GetSliderValueRangeForItemIndex(i, out float min, out float max); if (sliderValue >= min && sliderValue <= max) return GetItem(i); } return null; } private void GetSliderValueRangeForItemIndex(int itemIndex, out float min, out float max) { if (itemIndex == 0) { min = 0; max = 0.5f; } else if (itemIndex == ItemsCount - 1) { min = itemIndex - 0.5f; max = itemIndex; } else { min = itemIndex - 0.5f; max = itemIndex + 0.5f; } } private SliderItem GetButtonFromState(uint state) { foreach (KeyValuePair valuePair in _itemsDictionary) { if (valuePair.Key == state) return valuePair.Value; } return null; } private uint GetStateFromButton(SliderItem item) { foreach (KeyValuePair valuePair in _itemsDictionary) { if (valuePair.Value == item) return valuePair.Key; } return 0; } }