sega ec0920350d Обновить интерфейс настройки призов и исправить их добавление
Использовать полную иконку персонажа и крестик для пустого приза.
Добавить звук переключения, указатели выбора и анимацию добавленных призов за 0,3 секунды.
Скрывать экран настроек на время работы с конфигуратором призов.
Восстановить ссылку на префаб добавленного приза и оформить контекстные окна по макетам.
Устранить повторное подтверждение QR-приза и исправить направление вертикальной навигации витрины.

Проверено в Unity в режиме игры: ввод и сохранение значений, добавление и удаление пяти типов призов, анимация выбора и защита от повторного добавления. Ошибок в консоли нет.
2026-09-18 13:24:45 +03:00

266 lines
7.5 KiB
C#

using CharacterSystem;
using PrizeSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class PrizesSelector : MonoBehaviour, IControlable
{
public event Action OnConfirmed;
[SerializeField] private RectTransform _addedPrizesTable;
[SerializeField] private AvailablePrizesTable _availablePrizesTable;
[SerializeField] private MSignalButton _selectButton;
[SerializeField] private AddedPrizeButton _addedPrizeButtonPrefab;
private readonly List<PrizeButton> _addedPrizeButtons = new();
private PrizeSet _prizeSet;
private SelectionArea _selectionArea;
private int _rowIndex;
private bool _waitForActionRelease;
private bool _confirmSelected;
public bool ControlsEnabled { get; set; } = true;
private enum SelectionArea
{
Available,
Added,
Confirm
}
private void Awake()
{
_availablePrizesTable.OnPrizeConfigured += OnPrizeConfigured;
_selectButton.OnClick += Confirm;
}
private void OnDestroy()
{
_availablePrizesTable.OnPrizeConfigured -= OnPrizeConfigured;
_selectButton.OnClick -= Confirm;
}
public void Open(CharacterDefinition character)
{
gameObject.SetActive(true);
_prizeSet = PrizeSystemManager.PrizeContainer.Sets[character.CharacterIndex];
_confirmSelected = false;
_selectButton.DeselectAnimation();
RefreshView();
_selectionArea = _availablePrizesTable.PrizeButtons.Count > 0
? SelectionArea.Available
: GetInitialFallbackArea();
_rowIndex = 0;
_waitForActionRelease = In.GetAction(JoystickSide.Both, InteractMode.Continious);
RebuildLayouts();
UpdatePointer();
}
public void UpdateControls()
{
bool actionPressed = In.GetAction(JoystickSide.Both, InteractMode.Continious);
if (_waitForActionRelease)
{
_waitForActionRelease = actionPressed;
return;
}
Vector2Int axes = In.GetAxis(JoystickSide.Both, InteractMode.Discrete);
NavigateHorizontal(axes.x);
NavigateVertical(axes.y);
GetSelectedButton()?.TakeInput(actionPressed);
}
private void RefreshView()
{
ClearAddedPrizes();
DisplayAddedPrizes();
_availablePrizesTable.Refresh(_prizeSet);
}
private void DisplayAddedPrizes()
{
foreach (Prize prize in _prizeSet.Prizes.Where(prize => prize is not EmptyPrize))
{
PrizeButton button = Instantiate(_addedPrizeButtonPrefab, _addedPrizesTable);
button.Configure(prize);
button.OnPrize += _ => RemovePrize(prize);
_addedPrizeButtons.Add(button);
}
}
private void ClearAddedPrizes()
{
_addedPrizeButtons.Clear();
for (int i = _addedPrizesTable.childCount - 1; i >= 0; i--)
{
Transform child = _addedPrizesTable.GetChild(i);
child.SetParent(null, false);
Destroy(child.gameObject);
}
}
private void OnPrizeConfigured(Prize prize)
{
_prizeSet.Prizes.RemoveAll(item => item is EmptyPrize);
_prizeSet.Prizes.Add(prize);
RefreshView();
_selectionArea = SelectionArea.Added;
_rowIndex = _addedPrizeButtons.Count - 1;
_waitForActionRelease = true;
RebuildLayouts();
UpdatePointer();
ControlsPerformer.Instance.SetControlable(this);
}
private void RemovePrize(Prize prize)
{
_prizeSet.Prizes.Remove(prize);
EnsureEmptyPrizeWhenNeeded();
RefreshView();
_selectionArea = _availablePrizesTable.PrizeButtons.Count > 0
? SelectionArea.Available
: GetInitialFallbackArea();
_rowIndex = 0;
_waitForActionRelease = true;
RebuildLayouts();
UpdatePointer();
}
private void EnsureEmptyPrizeWhenNeeded()
{
if (_prizeSet.Prizes.Count == 0)
_prizeSet.Prizes.Add(new EmptyPrize());
}
private void NavigateHorizontal(int direction)
{
if (direction < 0 && _availablePrizesTable.PrizeButtons.Count > 0)
{
_selectionArea = SelectionArea.Available;
ClampRowIndex();
UpdatePointer();
}
else if (direction > 0 && _addedPrizeButtons.Count > 0)
{
_selectionArea = SelectionArea.Added;
ClampRowIndex();
UpdatePointer();
}
}
private void NavigateVertical(int direction)
{
if (direction == 0)
return;
if (_selectionArea == SelectionArea.Confirm)
{
if (direction > 0)
SelectBottomAvailableRow();
return;
}
int buttonsCount = GetCurrentButtons().Count;
if (buttonsCount == 0)
{
SelectConfirm();
UpdatePointer();
return;
}
if (direction < 0 && _rowIndex == buttonsCount - 1)
SelectConfirm();
else
_rowIndex = Mathf.Clamp(_rowIndex - direction, 0, buttonsCount - 1);
UpdatePointer();
}
private void SelectBottomAvailableRow()
{
if (_availablePrizesTable.PrizeButtons.Count > 0)
{
_selectionArea = SelectionArea.Available;
_rowIndex = _availablePrizesTable.PrizeButtons.Count - 1;
}
else if (_addedPrizeButtons.Count > 0)
{
_selectionArea = SelectionArea.Added;
_rowIndex = _addedPrizeButtons.Count - 1;
}
UpdatePointer();
}
private void SelectConfirm()
{
_selectionArea = SelectionArea.Confirm;
_rowIndex = 0;
}
private void ClampRowIndex()
{
_rowIndex = Mathf.Clamp(_rowIndex, 0, GetCurrentButtons().Count - 1);
}
private void UpdatePointer()
{
PrizeButton selectedButton = GetSelectedButton() as PrizeButton;
foreach (PrizeButton button in _availablePrizesTable.PrizeButtons)
button.SetSelected(button == selectedButton);
foreach (PrizeButton button in _addedPrizeButtons)
button.SetSelected(button == selectedButton);
bool confirmSelected = _selectionArea == SelectionArea.Confirm;
if (_confirmSelected != confirmSelected)
{
_confirmSelected = confirmSelected;
if (confirmSelected)
_selectButton.SelectAnimation();
else
_selectButton.DeselectAnimation();
}
}
private void RebuildLayouts()
{
Canvas.ForceUpdateCanvases();
LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_availablePrizesTable.transform);
LayoutRebuilder.ForceRebuildLayoutImmediate(_addedPrizesTable);
Canvas.ForceUpdateCanvases();
}
private MSignalButton GetSelectedButton()
{
if (_selectionArea == SelectionArea.Confirm)
return _selectButton;
IReadOnlyList<PrizeButton> buttons = GetCurrentButtons();
return buttons.Count > 0 ? buttons[_rowIndex] : null;
}
private IReadOnlyList<PrizeButton> GetCurrentButtons()
{
return _selectionArea == SelectionArea.Added
? _addedPrizeButtons
: _availablePrizesTable.PrizeButtons;
}
private SelectionArea GetInitialFallbackArea()
{
return _addedPrizeButtons.Count > 0 ? SelectionArea.Added : SelectionArea.Confirm;
}
private void Confirm()
{
OnConfirmed?.Invoke();
}
}