Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- доработан flow призовой витрины и связанного UI: добавлены `PrizeStandButtonView` и `RulesPrizeListPage`, обновлены `PrizeStandController`, `PrizeStandPrize`, `PrizeStandModal`, `PrizeStandSettingsModal`, `LevelPrizeSettingsModal`, `QRCodeSettingsModal`, `BalanceDisplay`, `ButtonTextFocusColor` и связанные prefab'ы, чтобы улучшить настройку, навигацию, отображение кнопок и prize flow - расширена система настроек и сохранения значений: `OptionPicker` получил отдельный формат `ValueSelector`, обновлены `SettingsDatabase`, `SettingEntryDrawer`, `SettingUIItem`, `SettingsUIGenerator`, `ValueSelectorRow` и `MainSettingsDatabase.asset`, а сохранение option picker-значений, включая `gameplay.gameDifficulty`, исправлено и синхронизировано с остальными настройками - добавлены универсальные спавнеры сущностей: реализованы `EntitySpawner` и `EntitySpawnerManager` с поддержкой весов префабов, точек спавна, заполнения по проценту, ограничений на количество и автоспавна при инициализации - доработана логика игрового спавна и сложности: процент инициализационного спавна может зависеть от настройки `gameplay.gameDifficulty` с градациями 25/50/75/100, в одном цикле массового спавна повторно не используется та же точка, а gizmo спавнера теперь показывает только сами точки без линий - упрощена работа в редакторе Unity и добавлены editor-инструменты: в `GameManager` лицензия пропускается при запуске в `UNITY_EDITOR`, а `HierarchySelectionCounter`, `HierarchySelectionCountOverlay` и `HierarchyBulkRenamerWindow` добавляют подсчет выделения, realtime overlay в `SceneView` и массовое переименование объектов по правилам нумерации из Unity Project Settings - синхронизированы сцены, ресурсы и UI-ассеты под новый flow: обновлены `MainMenu`, `Level UI`, уровни `1-1` и `1-2`, строки настроек, кнопки, TMP/font assets, изображения UI, `prizes.json` и recovery-данные после правок интерфейса и логики - очищены и переразложены часть внешних и служебных ресурсов: удалён пакет `Lava_Flowing_Shader`, переименованы/заменены отдельные UI-prefab'ы и добавлены сопутствующие проектные артефакты, которые сейчас используются обновлённой конфигурацией проекта
237 lines
8.8 KiB
C#
237 lines
8.8 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
/// <summary>
|
||
/// Ячейка для ввода одного символа.
|
||
/// Символы переключаются циклически при нажатии кнопки "вверх".
|
||
/// Наследуется от Selectable для поддержки навигации.
|
||
/// </summary>
|
||
public class TextInputCell : Selectable
|
||
{
|
||
[Header("UI References")]
|
||
[SerializeField] private TextMeshProUGUI symbolText;
|
||
[SerializeField] private Image backgroundImage;
|
||
[SerializeField] private Image selectionHighlight;
|
||
|
||
[Header("Visual Settings")]
|
||
[SerializeField] private Color highlightColor = new Color(1f, 1f, 0f, 0.3f);
|
||
|
||
private string[] alphabet;
|
||
private int currentIndex;
|
||
private bool isSelected;
|
||
|
||
/// <summary>
|
||
/// Событие, вызываемое при изменении символа
|
||
/// </summary>
|
||
public event System.Action<TextInputCell> OnSymbolChanged;
|
||
|
||
/// <summary>
|
||
/// Текущий выбранный символ
|
||
/// </summary>
|
||
public string CurrentSymbol => alphabet != null && alphabet.Length > 0 ? alphabet[currentIndex] : "";
|
||
|
||
/// <summary>
|
||
/// Индекс текущего символа
|
||
/// </summary>
|
||
public int CurrentIndex => currentIndex;
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
|
||
// Для этой ячейки используем только отдельную подсветку selectionHighlight.
|
||
// Стандартный Selectable tint отключаем, чтобы не менять цвет фона.
|
||
transition = Transition.None;
|
||
targetGraphic = null;
|
||
|
||
if (selectionHighlight)
|
||
{
|
||
selectionHighlight.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Переопределяем DoStateTransition для кастомной визуализации
|
||
/// </summary>
|
||
protected override void DoStateTransition(SelectionState state, bool instant)
|
||
{
|
||
base.DoStateTransition(state, instant);
|
||
|
||
if (!gameObject.activeInHierarchy)
|
||
return;
|
||
|
||
// Обновляем визуализацию в зависимости от состояния
|
||
bool shouldHighlight = (state == SelectionState.Highlighted ||
|
||
state == SelectionState.Selected ||
|
||
state == SelectionState.Pressed) && isSelected;
|
||
|
||
if (selectionHighlight != null)
|
||
{
|
||
selectionHighlight.gameObject.SetActive(shouldHighlight);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Переопределяем OnMove для обработки вверх/вниз и изменения символа
|
||
/// </summary>
|
||
public override void OnMove(UnityEngine.EventSystems.AxisEventData eventData)
|
||
{
|
||
switch (eventData.moveDir)
|
||
{
|
||
case UnityEngine.EventSystems.MoveDirection.Up:
|
||
// Вверх всегда меняет символ
|
||
NextSymbol();
|
||
eventData.Use(); // Отмечаем событие как обработанное
|
||
break;
|
||
|
||
case UnityEngine.EventSystems.MoveDirection.Down:
|
||
// Вниз всегда меняет символ (на предыдущий)
|
||
PreviousSymbol();
|
||
eventData.Use();
|
||
break;
|
||
|
||
case UnityEngine.EventSystems.MoveDirection.Left:
|
||
case UnityEngine.EventSystems.MoveDirection.Right:
|
||
// Для влево/вправо используем стандартную навигацию
|
||
base.OnMove(eventData);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Инициализирует ячейку с алфавитом
|
||
/// </summary>
|
||
/// <param name="newAlphabet">Алфавит символов</param>
|
||
/// <param name="startIndex">Начальный индекс (используется только если symbol = null)</param>
|
||
/// <param name="symbol">Начальный символ (если указан, ищется в алфавите)</param>
|
||
public void Initialize(string[] newAlphabet, int startIndex = 0, string symbol = null)
|
||
{
|
||
this.alphabet = newAlphabet;
|
||
|
||
// Если указан символ, ищем его в алфавите
|
||
if (!string.IsNullOrEmpty(symbol))
|
||
{
|
||
bool found = false;
|
||
|
||
// Ищем точное совпадение
|
||
for (int i = 0; i < newAlphabet.Length; i++)
|
||
{
|
||
if (newAlphabet[i] == symbol)
|
||
{
|
||
this.currentIndex = i;
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Если не найдено, ищем без учета регистра
|
||
if (!found)
|
||
{
|
||
for (int i = 0; i < newAlphabet.Length; i++)
|
||
{
|
||
if (string.Equals(newAlphabet[i], symbol, System.StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
this.currentIndex = i;
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Если символ не найден, устанавливаем первый символ из алфавита
|
||
if (!found)
|
||
{
|
||
this.currentIndex = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Если символ не указан, используем startIndex
|
||
this.currentIndex = Mathf.Clamp(startIndex, 0, newAlphabet.Length - 1);
|
||
}
|
||
|
||
UpdateDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Переключает на следующий символ в алфавите (циклически)
|
||
/// </summary>
|
||
public void NextSymbol()
|
||
{
|
||
if (alphabet == null || alphabet.Length == 0) return;
|
||
|
||
currentIndex = (currentIndex + 1) % alphabet.Length;
|
||
UpdateDisplay();
|
||
OnSymbolChanged?.Invoke(this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Переключает на предыдущий символ в алфавите (циклически)
|
||
/// </summary>
|
||
public void PreviousSymbol()
|
||
{
|
||
if (alphabet == null || alphabet.Length == 0) return;
|
||
|
||
currentIndex--;
|
||
if (currentIndex < 0)
|
||
currentIndex = alphabet.Length - 1;
|
||
|
||
UpdateDisplay();
|
||
OnSymbolChanged?.Invoke(this);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Устанавливает индекс символа
|
||
/// </summary>
|
||
public void SetSymbolIndex(int index)
|
||
{
|
||
if (alphabet == null || alphabet.Length == 0) return;
|
||
|
||
currentIndex = Mathf.Clamp(index, 0, alphabet.Length - 1);
|
||
UpdateDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Устанавливает состояние выделения ячейки
|
||
/// </summary>
|
||
public void SetCellSelected(bool selected)
|
||
{
|
||
isSelected = selected;
|
||
UpdateDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обновляет визуальное отображение ячейки
|
||
/// </summary>
|
||
private void UpdateDisplay()
|
||
{
|
||
// Обновляем текст символа
|
||
if (symbolText && alphabet != null && alphabet.Length > 0)
|
||
{
|
||
symbolText.text = alphabet[currentIndex];
|
||
}
|
||
|
||
// Обновляем подсветку выделения
|
||
if (selectionHighlight)
|
||
{
|
||
selectionHighlight.gameObject.SetActive(isSelected);
|
||
selectionHighlight.color = highlightColor;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Сбрасывает ячейку к первому символу
|
||
/// </summary>
|
||
public new void Reset()
|
||
{
|
||
currentIndex = 0;
|
||
UpdateDisplay();
|
||
}
|
||
}
|
||
}
|
||
|