291 lines
10 KiB
C#
291 lines
10 KiB
C#
using System;
|
||
using System.Collections;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
public class TextInput : MonoBehaviour
|
||
{
|
||
[Header("Ключ prefs")]
|
||
[SerializeField] private string key;
|
||
[SerializeField] private bool loadData;
|
||
[SerializeField] private bool saveDataOnClose;
|
||
|
||
[Header("Настройки генерации поля")]
|
||
[Tooltip("Якорь лево-низ")][SerializeField] private GameObject SlotPrefab;
|
||
[SerializeField] private RectTransform slotsRoot;
|
||
[SerializeField] private int slotsCount = 10;
|
||
|
||
[SerializeField] private float rootPaddingX = 10;
|
||
[SerializeField] private float rootPaddingY = 10;
|
||
[SerializeField] private float gapSize = 10;
|
||
|
||
|
||
[Header("Настройки анимации")]
|
||
|
||
[SerializeField] private float animationSpeed;
|
||
|
||
[SerializeField] private float fontSizeNormal = 20;
|
||
[SerializeField] private float fontSizeHighlighted = 25;
|
||
[SerializeField] private Color fontColorNormal;
|
||
[SerializeField] private Color fontColorHighlighted;
|
||
|
||
[SerializeField] private float slotSizeMultiplier = 1.1f;
|
||
[SerializeField] private Color slotColorNormal;
|
||
[SerializeField] private Color slotColorHighlighted;
|
||
|
||
[Header("Звуки")]
|
||
[SerializeField] private AudioClip switchSlotSound;
|
||
[SerializeField] private AudioClip switchLetterSound;
|
||
[SerializeField] private AudioClip acceptSound;
|
||
[SerializeField] private AudioClip openSound;
|
||
|
||
|
||
private Vector2 slotSizeNormal; //расчет при генерации
|
||
|
||
[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;
|
||
|
||
private float switchButtonPressedTime = 0;
|
||
private float letterSwitchSpeed = 0;
|
||
private float switchDelayRest = 1;
|
||
|
||
|
||
|
||
|
||
//тут массивы для доступа
|
||
private string[] alphabet; // не забыь добавить пустую строку при генерации (пробел лучше)
|
||
private RectTransform[] slotRects;
|
||
private Graphic[] slotGraphics;
|
||
private TextMeshProUGUI[] slotLabels;
|
||
|
||
private Coroutine animationCoroutine;
|
||
|
||
private int currentSlotIndex = 0;
|
||
private int currentLetterindex = 0;
|
||
|
||
private TextMeshProUGUI currentLabel => slotLabels[currentSlotIndex];
|
||
|
||
|
||
|
||
|
||
public void Initialize()
|
||
{
|
||
Generate();
|
||
LoadSavedData();
|
||
SoundManager.instance.playClip(openSound);
|
||
|
||
animationCoroutine = StartCoroutine(SlotsAnimation());
|
||
}
|
||
|
||
public string AcceptAndClose()
|
||
{
|
||
string result = GetText();
|
||
|
||
if (!string.IsNullOrEmpty(key) && saveDataOnClose)
|
||
{
|
||
PlayerPrefs.SetString(key, result);
|
||
SettingsManager.OnSettingsChanged?.Invoke();
|
||
}
|
||
|
||
StopCoroutine(animationCoroutine);
|
||
SoundManager.instance.playClip(acceptSound);
|
||
Clear();
|
||
return result;
|
||
|
||
}
|
||
private void Generate()
|
||
{
|
||
//Считаем размер одного слота
|
||
Vector2 spaceForSlotsWithGaps = slotsRoot.sizeDelta
|
||
- Vector2.right * rootPaddingX * 2
|
||
- Vector2.up * rootPaddingY * 2;
|
||
|
||
int gapsCount = slotsCount - 1;
|
||
float horizontalSpaceForSlots = spaceForSlotsWithGaps.x - gapsCount * gapSize;
|
||
float slotWidth = horizontalSpaceForSlots / slotsCount;
|
||
|
||
slotSizeNormal = new Vector2(slotWidth,
|
||
spaceForSlotsWithGaps.y);
|
||
|
||
//Расставляем слоты в root
|
||
//у префаба будет якорь лево/низ
|
||
Vector2 startLocalPoint = new Vector2(rootPaddingX, rootPaddingY);
|
||
slotRects = new RectTransform[slotsCount];
|
||
slotGraphics = new Graphic[slotsCount];
|
||
slotLabels = new TextMeshProUGUI[slotsCount];
|
||
|
||
Vector2 slotOffset = (slotSizeNormal.x + gapSize) * Vector2.right;//на сколько сдвигать каждый след. слот
|
||
for (int i = 0; i < slotsCount; i++)
|
||
{
|
||
//Создаем слот
|
||
GameObject slot = Instantiate(SlotPrefab, slotsRoot);
|
||
|
||
//филлим массивы ссылок
|
||
slotRects[i] = slot.GetComponent<RectTransform>();
|
||
slotGraphics[i] = slot.GetComponent<Graphic>();
|
||
slotLabels[i] = slot.transform.GetComponentInChildren<TextMeshProUGUI>();
|
||
|
||
//Выставляем размеры, координаты, цвета, шрифты
|
||
slotRects[i].sizeDelta = slotSizeNormal;
|
||
slotRects[i].anchoredPosition = startLocalPoint + slotOffset * i + slotSizeNormal / 2;
|
||
|
||
slotGraphics[i].color = slotColorNormal;
|
||
slotLabels[i].color = fontColorNormal;
|
||
slotLabels[i].text = "";
|
||
|
||
slotLabels[i].fontSize = fontSizeNormal;
|
||
}
|
||
|
||
//Собираем алфавит
|
||
alphabet = new string[alphabetString.Length + 1];//+1 для пробела
|
||
for (int i = 0; i < alphabetString.Length; i++)
|
||
{
|
||
alphabet[i] = alphabetString[i].ToString();
|
||
}
|
||
alphabet[^1] = " ";
|
||
|
||
//Настраиваем индексы
|
||
currentSlotIndex = 0;
|
||
}
|
||
private void LoadSavedData()
|
||
{
|
||
string data = "";
|
||
|
||
if (loadData)
|
||
data = PlayerPrefs.GetString(key, "");
|
||
|
||
// Очищаем все слоты
|
||
for (int i = 0; i < slotsCount; i++)
|
||
{
|
||
slotLabels[i].text = " ";
|
||
}
|
||
|
||
// Заполняем сохраненными данными
|
||
if (!string.IsNullOrEmpty(data))
|
||
{
|
||
int minLength = Mathf.Min(data.Length, slotsCount);
|
||
for (int i = 0; i < minLength; i++)
|
||
{
|
||
slotLabels[i].text = data[i].ToString();
|
||
}
|
||
}
|
||
}
|
||
|
||
public void SwitchLetter(int continiousDirection)
|
||
{
|
||
continiousDirection = Mathf.Clamp(continiousDirection, -1, 1);
|
||
if (continiousDirection == 0)//сброс переключения
|
||
{
|
||
switchDelayRest = 0;
|
||
switchButtonPressedTime = 0;
|
||
return;
|
||
}
|
||
|
||
if (switchDelayRest < 0)
|
||
{
|
||
|
||
//переключение
|
||
currentLetterindex = (currentLetterindex + continiousDirection + alphabet.Length) % alphabet.Length;
|
||
currentLabel.text = alphabet[currentLetterindex];
|
||
|
||
recalculateRest();
|
||
Debug.Log($"Переключение остаток: {switchDelayRest}");
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
|
||
public void SwitchSlot(int discreteDirection)
|
||
{
|
||
if (discreteDirection == 0) return;
|
||
|
||
currentSlotIndex = (currentSlotIndex + discreteDirection + slotsCount) % slotsCount;
|
||
|
||
string letter = currentLabel.text;
|
||
currentLetterindex = Array.IndexOf(alphabet, letter);
|
||
|
||
|
||
}
|
||
|
||
public void Clear()
|
||
{
|
||
foreach (RectTransform rect in slotRects)
|
||
{
|
||
Destroy(rect.gameObject);
|
||
}
|
||
}
|
||
|
||
public string GetText()
|
||
{
|
||
System.Text.StringBuilder sb = new();
|
||
|
||
foreach (TextMeshProUGUI label in slotLabels)
|
||
{
|
||
// Если текст пустой строка, считаем это пробелом
|
||
if (!string.IsNullOrEmpty(label.text))
|
||
{
|
||
sb.Append(label.text);
|
||
}
|
||
}
|
||
return sb.ToString().Trim();
|
||
}
|
||
|
||
|
||
IEnumerator SlotsAnimation()
|
||
{
|
||
float scaleSpeed = (slotSizeMultiplier - 1) / animationSpeed;
|
||
float slotColorSpeed = Vector4.Distance(slotColorNormal, slotColorHighlighted) / animationSpeed;
|
||
float fontColorSpeed = Vector4.Distance(fontColorNormal, fontColorHighlighted) / animationSpeed;
|
||
float fontSizeSpeed = (fontSizeHighlighted - fontSizeNormal) / animationSpeed;
|
||
|
||
while (true)
|
||
{
|
||
for (int i = 0; i < slotsCount; i++)
|
||
{
|
||
if (i == currentSlotIndex) //подсвечиваем
|
||
{
|
||
slotRects[i].localScale = Vector3.MoveTowards(slotRects[i].localScale, Vector3.one * slotSizeMultiplier, scaleSpeed);
|
||
slotGraphics[i].color = Vector4.MoveTowards(slotGraphics[i].color, slotColorHighlighted, slotColorSpeed);
|
||
|
||
slotLabels[i].color = Vector4.MoveTowards(slotLabels[i].color, fontColorHighlighted, fontColorSpeed);
|
||
slotLabels[i].fontSize = Mathf.MoveTowards(slotLabels[i].fontSize, fontSizeHighlighted, fontSizeSpeed);
|
||
|
||
}
|
||
else //убираем подсветку
|
||
{
|
||
slotRects[i].localScale = Vector3.MoveTowards(slotRects[i].localScale, Vector3.one, scaleSpeed);
|
||
slotGraphics[i].color = Vector4.MoveTowards(slotGraphics[i].color, slotColorNormal, slotColorSpeed);
|
||
|
||
slotLabels[i].color = Vector4.MoveTowards(slotLabels[i].color, fontColorNormal, fontColorSpeed);
|
||
slotLabels[i].fontSize = Mathf.MoveTowards(slotLabels[i].fontSize, fontSizeNormal, fontSizeSpeed);
|
||
}
|
||
}
|
||
|
||
|
||
yield return null;
|
||
}
|
||
|
||
}
|
||
|
||
}
|