using System; using System.Collections.Generic; using UnityEngine; public class TextInput : MonoBehaviour, ICompletable { [Header("Генерация")] [SerializeField] private GameObject _letterSlotPrefab; [SerializeField] private RectTransform _group; [Header("Управление")] [SerializeField] private InSignal _nextSlot; [SerializeField] private InSignal _prevSlot; [SerializeField] private InSignal _nextSymbol; [SerializeField] private InSignal _prevSymbol; [SerializeField] private List _exitSignals; [SerializeField] private float _timeToExit = 2; [SerializeField] private Instruction exitDisplay; [Header("Ключ prefs")] [SerializeField] private string key; [SerializeField] private bool loadData; [SerializeField] private bool saveDataOnClose; [Header("Настройки генерации поля")] [SerializeField] private int slotsCount = 11; [Header("Звуки")] [SerializeField] private AudioClip switchSlotSound; [SerializeField] private AudioClip switchLetterSound; [SerializeField] private AudioClip acceptSound; [SerializeField] private AudioClip openSound; [Header("Алфавит")] [SerializeField] private string alphabetString = "0123456789"; [Header("Скорость переключения букв")] [SerializeField] private float MaxSpeedLetterPerSecond = 8; [SerializeField] private float MinSpeedLetterPerSecond = 3; [SerializeField] private float MaxSpeedTime = 3; [SerializeField] private float MinSpeedTime = 0.5f; [SerializeField] private float switchButtonPressedTime = 0; private float letterSwitchSpeed = 0; private float switchDelayRest = 1; private int _slotIndex = 0; private float exitTimer = 0; private LetterSlot[] _slots; public event Action OnComplete; private LetterSlot _activeSlot => _slots[_slotIndex]; private bool exitRequested = false; private bool ready; public void Initialize() { Generate(); LoadSavedData(); exitDisplay.Init(); } private void OnEnable() { ready = false; } private void Update()//условия завершения добавить { if (!ready) { ready = !(In.GetButton(_nextSlot) || In.GetButton(_prevSlot) || In.GetButton(_nextSymbol) || In.GetButton(_prevSymbol)); return; } if (exitRequested) { exitTimer = 0; exitRequested = false; Exit(); return; } int dir = 0; if (In.GetButtonDown(_nextSlot)) dir += 1; if (In.GetButtonDown(_prevSlot)) dir -= 1; SwitchSlot(dir); dir = 0; if (In.GetButton(_nextSymbol)) dir += 1; if (In.GetButton(_prevSymbol)) dir -= 1; SwitchLetter(dir); if (ExitCombinationPressed()) { exitTimer += Time.deltaTime; } else { exitTimer -= Time.deltaTime; } exitTimer = Mathf.Clamp(exitTimer, 0f, _timeToExit); exitDisplay?.SetProgress(exitTimer / _timeToExit); exitRequested = exitTimer >= _timeToExit; } private void Exit() { SaveAndClose(); exitDisplay?.SetProgress(0); OnComplete?.Invoke(); gameObject.SetActive(false); } public string SaveAndClose() { string result = GetText(); if (!string.IsNullOrEmpty(key) && saveDataOnClose) { PlayerPrefs.SetString(key, result); } Clear(); return result; } private void Generate() { _slots = new LetterSlot[slotsCount]; for (int i = 0; i < slotsCount; i++) { var go = Instantiate(_letterSlotPrefab.gameObject, _group); _slots[i] = go.GetComponent(); _slots[i].Init(alphabetString[0], false); } _slotIndex = 0; _slots[0].SetSelected(true); } private void LoadSavedData()//Тут надо проработать { string data = ""; if (loadData) data = PlayerPrefs.GetString(key, ""); // Очищаем все слоты for (int i = 0; i < slotsCount; i++) { _slots[i].SetSymbol(alphabetString[0]); } if (!string.IsNullOrEmpty(data)) { int minLength = Mathf.Min(data.Length, slotsCount); for (int i = 0; i < minLength; i++) { _slots[i].SetSymbol(data[i]); } } } public void SwitchSlot(int discreteDirection) { if (discreteDirection == 0) return; _activeSlot.SetSelected(false); ChangeIndexBounded(ref _slotIndex, delta: discreteDirection, length: slotsCount); _activeSlot.SetSelected(true); } public void SwitchLetter(int continiousDirection) { continiousDirection = Mathf.Clamp(continiousDirection, -1, 1); if (continiousDirection == 0)//сброс переключения { switchDelayRest = 0; switchButtonPressedTime = 0; return; } if (switchDelayRest < 0) { //переключение int currentLetterindex = getSymbolIndex(_activeSlot.GetSymbol(), alphabetString); ChangeIndexLooped(ref currentLetterindex, delta: continiousDirection, alphabetString.Length); _activeSlot.SetSymbol(alphabetString[currentLetterindex]); recalculateRest(); } switchDelayRest -= Time.deltaTime; switchButtonPressedTime += Time.deltaTime; void recalculateRest() { float k = (MaxSpeedLetterPerSecond - MinSpeedLetterPerSecond) / (MaxSpeedTime - MinSpeedTime); float b = MinSpeedLetterPerSecond - k * MinSpeedTime; letterSwitchSpeed = k * switchButtonPressedTime + b; letterSwitchSpeed = Mathf.Clamp(letterSwitchSpeed, MinSpeedLetterPerSecond, MaxSpeedLetterPerSecond); switchDelayRest = 1 / letterSwitchSpeed; } int getSymbolIndex(char symbol, string alphabet) => alphabet.IndexOf(symbol); } public void Clear() { foreach (var slot in _slots) { Destroy(slot.gameObject); } _slots = null; } public string GetText() { System.Text.StringBuilder sb = new(); foreach (var slot in _slots) sb.Append(slot.GetSymbol()); return sb.ToString().Trim(); } private static void ChangeIndexLooped(ref int index, int delta, int length) => index = (index + delta + length) % length; static void ChangeIndexBounded(ref int index, int delta, int length) => index = Mathf.Clamp(index + delta, 0, length - 1); private bool ExitCombinationPressed() { foreach (var signal in _exitSignals) { if (In.GetButton(signal) == false) return false; } return true; } }