Доработка панели ввода призов персонажей
This commit is contained in:
parent
963115e311
commit
0cfd38da13
@ -423,6 +423,7 @@ GameObject:
|
||||
- component: {fileID: 6087319970201647579}
|
||||
- component: {fileID: 5163440344643624749}
|
||||
- component: {fileID: 7572701421691474762}
|
||||
- component: {fileID: 1117177583243168359}
|
||||
m_Layer: 5
|
||||
m_Name: Added Prizes Table
|
||||
m_TagString: Untagged
|
||||
@ -487,6 +488,32 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &1117177583243168359
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1230475039650522997}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 0
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 0
|
||||
m_ChildControlHeight: 0
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!1 &1590808388917995624
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -719,12 +746,11 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 852fdedcfe3484442b0d7e16ba459a3b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::CharacterSelectionPanel
|
||||
CharacterNameLabel: {fileID: 8964039495605377843}
|
||||
CharacterIcon: {fileID: 5624866514520992697}
|
||||
ClickSound: {fileID: 8300000, guid: 1c48900c9ab0aa8418920a8193050870, type: 3}
|
||||
_characterNameLabel: {fileID: 8964039495605377843}
|
||||
_characterIcon: {fileID: 5624866514520992697}
|
||||
_prizeTable: {fileID: 3273224345942325796}
|
||||
_prizeViewPrefab: {fileID: 1203032466002125781, guid: f8172e74629723c4e993e8ac2f322bdf, type: 3}
|
||||
buttons:
|
||||
_buttons:
|
||||
- {fileID: 1081245877292184043}
|
||||
- {fileID: 6492870122095265573}
|
||||
_selectButton: {fileID: 1081245877292184043}
|
||||
@ -1369,10 +1395,9 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PrizesSelector
|
||||
_addedPrizesTable: {fileID: 6087319970201647579}
|
||||
_prizeViewPrefab: {fileID: 1203032466002125781, guid: f8172e74629723c4e993e8ac2f322bdf, type: 3}
|
||||
_availablePrizesTable: {fileID: 978156554344200501}
|
||||
skipFrame: 0
|
||||
pointer: {fileID: 2717940143288701108}
|
||||
_selectButton: {fileID: 6745117456236530743}
|
||||
_pointer: {fileID: 2717940143288701108}
|
||||
--- !u!1 &8288873238761209220
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -1464,12 +1489,10 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::AvailablePrizesTable
|
||||
_prizeButtonPrefab: {fileID: 942699711437869465, guid: f4d8e373cd4ebc948abb9692f14709e6, type: 3}
|
||||
_buttonsRoot: {fileID: 4388752671798834034}
|
||||
prizeButtons: []
|
||||
countablePrizeConfigurator: {fileID: 5680088572919083885, guid: 8b123b0e9e795b842948d07b6e135d84, type: 3}
|
||||
qrPrizeConfigurator: {fileID: 8201104754896611310, guid: 419ede247f441324681aeb7eeacf4ea0, type: 3}
|
||||
vitrinaPrizeConfigurator: {fileID: 2013129107579668837, guid: fa4e8b6466206ac4cb113d8b98d3a8e5, type: 3}
|
||||
root: {fileID: 4098477273951441249}
|
||||
selector: {fileID: 2866604199148495954}
|
||||
_countablePrizeConfigurator: {fileID: 5680088572919083885, guid: 8b123b0e9e795b842948d07b6e135d84, type: 3}
|
||||
_qrPrizeConfigurator: {fileID: 8201104754896611310, guid: 419ede247f441324681aeb7eeacf4ea0, type: 3}
|
||||
_vitrinaPrizeConfigurator: {fileID: 2013129107579668837, guid: fa4e8b6466206ac4cb113d8b98d3a8e5, type: 3}
|
||||
_configuratorsRoot: {fileID: 4098477273951441249}
|
||||
--- !u!114 &2520044121805980792
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -1676,6 +1699,17 @@ PrefabInstance:
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: c244207dd10914141af206f200c91b0a, type: 3}
|
||||
--- !u!114 &6745117456236530743 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 6123304204807351912, guid: c244207dd10914141af206f200c91b0a, type: 3}
|
||||
m_PrefabInstance: {fileID: 675856799151252063}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6422f146b37ef714db72d2550697c362, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::MSignalButton
|
||||
--- !u!224 &8162745928107063912 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 8657825045506627639, guid: c244207dd10914141af206f200c91b0a, type: 3}
|
||||
|
||||
@ -18836,7 +18836,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1967587903
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -22504,7 +22504,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5423109734219761443, guid: dcef42dd0beb95f4e9b230192966f091, type: 3}
|
||||
propertyPath: m_IsActive
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
|
||||
@ -1,22 +1,65 @@
|
||||
using CharacterSystem;
|
||||
using CharacterSystem;
|
||||
using PrizeSystem;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
public class CharacterPrizeConfigurator : MonoBehaviour
|
||||
{
|
||||
public event Action OnClosed;
|
||||
|
||||
[SerializeField] private CharacterSelectionPanel _characterSelection;
|
||||
[SerializeField] private PrizesSelector _prizesSelector;
|
||||
|
||||
private void OnEnable()
|
||||
private void Awake()
|
||||
{
|
||||
_characterSelection.gameObject.SetActive(true);
|
||||
_prizesSelector.gameObject.SetActive(false);
|
||||
|
||||
_characterSelection.OnCharacterSelected += OnCharacterSelected;
|
||||
_characterSelection.OnCharacterSelected += OpenPrizeSelector;
|
||||
_characterSelection.OnExitRequested += SaveAndClose;
|
||||
_prizesSelector.OnConfirmed += OpenCharacterSelection;
|
||||
}
|
||||
|
||||
private void OnCharacterSelected(Character character)
|
||||
private void OnEnable()
|
||||
{
|
||||
OpenCharacterSelection();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
OpenCharacterSelection();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_characterSelection.OnCharacterSelected -= OpenPrizeSelector;
|
||||
_characterSelection.OnExitRequested -= SaveAndClose;
|
||||
_prizesSelector.OnConfirmed -= OpenCharacterSelection;
|
||||
}
|
||||
|
||||
private void OpenPrizeSelector(Character character)
|
||||
{
|
||||
_characterSelection.gameObject.SetActive(false);
|
||||
_prizesSelector.Open(character);
|
||||
ControlsPerformer.Instance.SetControlable(_prizesSelector);
|
||||
}
|
||||
|
||||
private void OpenCharacterSelection()
|
||||
{
|
||||
_prizesSelector.gameObject.SetActive(false);
|
||||
_characterSelection.gameObject.SetActive(true);
|
||||
_characterSelection.Open();
|
||||
|
||||
if (ControlsPerformer.Instance != null)
|
||||
ControlsPerformer.Instance.SetControlable(_characterSelection);
|
||||
}
|
||||
|
||||
private void SaveAndClose()
|
||||
{
|
||||
PrizeSerializer.SaveToFile();
|
||||
PrizeSystemManager.SavePrizes();
|
||||
|
||||
if (ControlsPerformer.Instance != null)
|
||||
ControlsPerformer.Instance.SetControlable(null);
|
||||
|
||||
gameObject.SetActive(false);
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,81 +1,41 @@
|
||||
using PrizeSystem;
|
||||
using PrizeSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
public class AvailablePrizesTable : MonoBehaviour
|
||||
{
|
||||
public PrizeButton _prizeButtonPrefab;
|
||||
public event Action<Prize> OnPrizeConfigured;
|
||||
|
||||
[SerializeField] RectTransform _buttonsRoot;
|
||||
[SerializeField] private PrizeButton _prizeButtonPrefab;
|
||||
[SerializeField] private RectTransform _buttonsRoot;
|
||||
[SerializeField, FormerlySerializedAs("countablePrizeConfigurator")] private CountablePrizeConfigurator _countablePrizeConfigurator;
|
||||
[SerializeField, FormerlySerializedAs("qrPrizeConfigurator")] private QrPrizeConfigurator _qrPrizeConfigurator;
|
||||
[SerializeField, FormerlySerializedAs("vitrinaPrizeConfigurator")] private VitrinaPrizeConfigurator _vitrinaPrizeConfigurator;
|
||||
[SerializeField, FormerlySerializedAs("root")] private RectTransform _configuratorsRoot;
|
||||
|
||||
public List<PrizeButton> prizeButtons;
|
||||
|
||||
public CountablePrizeConfigurator countablePrizeConfigurator;
|
||||
public QrPrizeConfigurator qrPrizeConfigurator;
|
||||
public VitrinaPrizeConfigurator vitrinaPrizeConfigurator;
|
||||
private readonly List<PrizeButton> _prizeButtons = new();
|
||||
|
||||
public PrizeSet cachedSet;
|
||||
public RectTransform root;
|
||||
public PrizesSelector selector;
|
||||
public IReadOnlyList<PrizeButton> PrizeButtons => _prizeButtons;
|
||||
public PrizeButton PrizeButtonPrefab => _prizeButtonPrefab;
|
||||
|
||||
public void Refresh(PrizeSet set)
|
||||
public void Refresh(PrizeSet prizeSet)
|
||||
{
|
||||
cachedSet = set;
|
||||
ClearButtons();
|
||||
prizeButtons = new();
|
||||
foreach (var type in GetMissingPrizeTypes(set.Prizes))
|
||||
foreach (PrizeType type in GetMissingPrizeTypes(prizeSet.Prizes))
|
||||
{
|
||||
var button = Instantiate(_prizeButtonPrefab, _buttonsRoot);
|
||||
PrizeButton button = Instantiate(_prizeButtonPrefab, _buttonsRoot);
|
||||
button.Configure(type);
|
||||
button.OnPrize += OnPrizeTypeSelected;
|
||||
prizeButtons.Add(button);
|
||||
button.OnPrize += OpenConfigurator;
|
||||
_prizeButtons.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPrizeTypeSelected(PrizeType type)
|
||||
public static List<PrizeType> GetMissingPrizeTypes(IReadOnlyCollection<Prize> prizes)
|
||||
{
|
||||
print($"Выбран приз {type}");
|
||||
|
||||
|
||||
BasePrizeConfigurator window = type switch
|
||||
{
|
||||
PrizeType.Hopper => countablePrizeConfigurator,
|
||||
PrizeType.Marbles => countablePrizeConfigurator,
|
||||
PrizeType.Ticket => countablePrizeConfigurator,
|
||||
PrizeType.VitrinaBox => vitrinaPrizeConfigurator,
|
||||
PrizeType.Qr => qrPrizeConfigurator
|
||||
};
|
||||
|
||||
var configurator = Instantiate(window, root);
|
||||
configurator.Configure(type);
|
||||
|
||||
configurator.OnPrizeConfigured += Configurator_OnPrizeConfigured;
|
||||
ControlsPerformer.Instance.SetControlable(configurator);
|
||||
|
||||
}
|
||||
|
||||
private void Configurator_OnPrizeConfigured(Prize prize)
|
||||
{
|
||||
cachedSet.Prizes.Add(prize);
|
||||
Refresh(cachedSet);
|
||||
selector.skipFrame = true;
|
||||
}
|
||||
|
||||
private void ClearButtons()
|
||||
{
|
||||
for (int i = 0; i < _buttonsRoot.childCount; i++)
|
||||
{
|
||||
var go = _buttonsRoot.GetChild(i).gameObject;
|
||||
Destroy(go);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<PrizeType> GetMissingPrizeTypes(List<Prize> prizes)
|
||||
{
|
||||
// Все типы призов (кроме None и Empty)
|
||||
var allTypes = new List<PrizeType>
|
||||
PrizeType[] allTypes =
|
||||
{
|
||||
PrizeType.Hopper,
|
||||
PrizeType.Marbles,
|
||||
@ -84,62 +44,63 @@ public class AvailablePrizesTable : MonoBehaviour
|
||||
PrizeType.VitrinaBox
|
||||
};
|
||||
|
||||
// Определяем, есть ли в списке хоть один CountablePrize
|
||||
bool hasCountablePrize = prizes.Any(p => p is CountablePrize);
|
||||
bool hasCountablePrize = prizes.Any(prize => prize is CountablePrize);
|
||||
HashSet<PrizeType> existingTypes = prizes
|
||||
.Where(prize => prize is not EmptyPrize)
|
||||
.Select(prize => prize.PrizeType)
|
||||
.ToHashSet();
|
||||
|
||||
// Если есть CountablePrize, все счетные типы считаются добавленными
|
||||
var countableTypes = new HashSet<PrizeType>
|
||||
{
|
||||
PrizeType.Hopper,
|
||||
PrizeType.Marbles,
|
||||
PrizeType.Ticket
|
||||
};
|
||||
|
||||
// Собираем существующие типы
|
||||
var existingTypes = new HashSet<PrizeType>();
|
||||
|
||||
foreach (var prize in prizes)
|
||||
{
|
||||
// Если это EmptyPrize - пропускаем (не влияет на существующие типы)
|
||||
if (prize is EmptyPrize) continue;
|
||||
|
||||
// Если это CountablePrize и у нас уже есть флаг, что счетные есть
|
||||
if (prize is CountablePrize)
|
||||
{
|
||||
// Добавляем все счетные типы, если их еще нет
|
||||
if (hasCountablePrize)
|
||||
{
|
||||
foreach (var type in countableTypes)
|
||||
{
|
||||
existingTypes.Add(type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// На случай, если hasCountablePrize false (но такого быть не может)
|
||||
existingTypes.Add(prize.PrizeType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Для не-счетных призов добавляем их конкретный тип
|
||||
existingTypes.Add(prize.PrizeType);
|
||||
}
|
||||
}
|
||||
|
||||
// Если есть CountablePrize, но не все типы добавлены, добавляем все счетные
|
||||
if (hasCountablePrize)
|
||||
{
|
||||
foreach (var type in countableTypes)
|
||||
{
|
||||
existingTypes.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
// Возвращаем типы, которых нет в существующих
|
||||
return allTypes
|
||||
.Where(type => !existingTypes.Contains(type))
|
||||
.Where(type => IsCountable(type) ? !hasCountablePrize : !existingTypes.Contains(type))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
private void OpenConfigurator(PrizeType type)
|
||||
{
|
||||
BasePrizeConfigurator prefab = GetConfiguratorPrefab(type);
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogError($"Не найден конфигуратор для приза {type}");
|
||||
return;
|
||||
}
|
||||
|
||||
BasePrizeConfigurator configurator = Instantiate(prefab, _configuratorsRoot);
|
||||
configurator.OnPrizeConfigured += CompleteConfiguration;
|
||||
configurator.Configure(type);
|
||||
ControlsPerformer.Instance.SetControlable(configurator);
|
||||
}
|
||||
|
||||
private BasePrizeConfigurator GetConfiguratorPrefab(PrizeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PrizeType.Hopper => _countablePrizeConfigurator,
|
||||
PrizeType.Marbles => _countablePrizeConfigurator,
|
||||
PrizeType.Ticket => _countablePrizeConfigurator,
|
||||
PrizeType.VitrinaBox => _vitrinaPrizeConfigurator,
|
||||
PrizeType.Qr => _qrPrizeConfigurator,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private void CompleteConfiguration(Prize prize)
|
||||
{
|
||||
OnPrizeConfigured?.Invoke(prize);
|
||||
}
|
||||
|
||||
private void ClearButtons()
|
||||
{
|
||||
_prizeButtons.Clear();
|
||||
for (int i = _buttonsRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = _buttonsRoot.GetChild(i);
|
||||
child.SetParent(null, false);
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCountable(PrizeType type)
|
||||
{
|
||||
return type is PrizeType.Hopper or PrizeType.Marbles or PrizeType.Ticket;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
using CharacterSystem;
|
||||
using CharacterSystem;
|
||||
using PrizeSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class CharacterSelectionPanel : MonoBehaviour, IControlable
|
||||
@ -11,114 +12,127 @@ public class CharacterSelectionPanel : MonoBehaviour, IControlable
|
||||
public event Action<Character> OnCharacterSelected;
|
||||
public event Action OnExitRequested;
|
||||
|
||||
[SerializeField] TextMeshProUGUI CharacterNameLabel;
|
||||
[SerializeField] Image CharacterIcon;
|
||||
[SerializeField] AudioClip ClickSound;
|
||||
|
||||
[SerializeField] RectTransform _prizeTable;
|
||||
[SerializeField] PrizeView _prizeViewPrefab;
|
||||
|
||||
|
||||
private Character[] characters;
|
||||
private int characterIndex = 0;
|
||||
|
||||
[SerializeField] private List<MSignalButton> buttons;
|
||||
[SerializeField, FormerlySerializedAs("CharacterNameLabel")] private TextMeshProUGUI _characterNameLabel;
|
||||
[SerializeField, FormerlySerializedAs("CharacterIcon")] private Image _characterIcon;
|
||||
[SerializeField] private RectTransform _prizeTable;
|
||||
[SerializeField] private PrizeView _prizeViewPrefab;
|
||||
[SerializeField, FormerlySerializedAs("buttons")] private List<MSignalButton> _buttons;
|
||||
[SerializeField] private MSignalButton _selectButton;
|
||||
[SerializeField] private MSignalButton _exitButton;
|
||||
|
||||
private int buttonIndex = 0;
|
||||
private Character[] _characters;
|
||||
private int _characterIndex;
|
||||
private int _buttonIndex;
|
||||
|
||||
public int CharactersCount => characters.Length;
|
||||
public Character SelectedCharacter => characters[characterIndex];
|
||||
public int CharactersCount => _characters?.Length ?? 0;
|
||||
public Character SelectedCharacter => _characters[_characterIndex];
|
||||
public bool ControlsEnabled { get; set; } = true;
|
||||
private MSignalButton SelectedButton => _buttons[_buttonIndex];
|
||||
|
||||
public bool ControlsEnabled { get; set; }
|
||||
private MSignalButton SelectedButton => buttons[buttonIndex];
|
||||
|
||||
private void Update()
|
||||
private void Awake()
|
||||
{
|
||||
UpdateControls();
|
||||
_selectButton.OnClick += SelectCharacter;
|
||||
_exitButton.OnClick += RequestExit;
|
||||
}
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_selectButton.OnClick += _selectButton_OnClick;
|
||||
_exitButton.OnClick += _exitButton_OnClick;
|
||||
_characters = CharactersController.GetCharactersArray();
|
||||
Open();
|
||||
}
|
||||
|
||||
characters = CharactersController.GetCharactersArray();
|
||||
characterIndex = 0;
|
||||
DisplaySelectedCharacter();
|
||||
private void OnDestroy()
|
||||
{
|
||||
_selectButton.OnClick -= SelectCharacter;
|
||||
_exitButton.OnClick -= RequestExit;
|
||||
}
|
||||
|
||||
buttonIndex = 0;
|
||||
public void Open()
|
||||
{
|
||||
if (_buttons == null || _buttons.Count == 0)
|
||||
return;
|
||||
|
||||
SelectedButton.DeselectAnimation();
|
||||
_buttonIndex = 0;
|
||||
SelectedButton.SelectAnimation();
|
||||
|
||||
if (_characters == null || _characters.Length == 0)
|
||||
return;
|
||||
|
||||
_characterIndex = Mathf.Clamp(_characterIndex, 0, _characters.Length - 1);
|
||||
DisplaySelectedCharacter();
|
||||
}
|
||||
|
||||
|
||||
private void _selectButton_OnClick()
|
||||
{
|
||||
OnCharacterSelected?.Invoke(SelectedCharacter);
|
||||
}
|
||||
|
||||
private void _exitButton_OnClick()
|
||||
{
|
||||
OnExitRequested?.Invoke();
|
||||
}
|
||||
|
||||
public void SwitchCharacter(int direction)
|
||||
{
|
||||
if (direction == 0) return;
|
||||
if (direction == 0 || CharactersCount == 0)
|
||||
return;
|
||||
|
||||
characterIndex = (characterIndex + direction + characters.Length) % characters.Length;
|
||||
_characterIndex = (_characterIndex + direction + _characters.Length) % _characters.Length;
|
||||
DisplaySelectedCharacter();
|
||||
}
|
||||
|
||||
public void SwitchButton(int direction)
|
||||
{
|
||||
if (direction == 0) return;
|
||||
if (direction == 0)
|
||||
return;
|
||||
|
||||
int newIndex = Mathf.Clamp(buttonIndex + direction, 0, buttons.Count - 1);
|
||||
if (newIndex == buttonIndex) return;
|
||||
int newIndex = Mathf.Clamp(_buttonIndex + direction, 0, _buttons.Count - 1);
|
||||
if (newIndex == _buttonIndex)
|
||||
return;
|
||||
|
||||
SelectedButton.DeselectAnimation();
|
||||
buttonIndex = newIndex;
|
||||
_buttonIndex = newIndex;
|
||||
SelectedButton.SelectAnimation();
|
||||
}
|
||||
|
||||
private void DisplaySelectedCharacter()
|
||||
{
|
||||
CharacterNameLabel.text = SelectedCharacter.characterName;
|
||||
CharacterIcon.sprite = SelectedCharacter.visualModule.icon;
|
||||
|
||||
ClearTable();
|
||||
|
||||
var set = PrizeSystemManager.PrizeContainer.Sets[SelectedCharacter.CharacterIndex];
|
||||
DisplayPrizeSet(set);
|
||||
}
|
||||
|
||||
public void UpdateControls()
|
||||
{
|
||||
if (CharactersCount == 0)
|
||||
return;
|
||||
|
||||
Vector2Int axes = In.GetAxis(JoystickSide.Both, InteractMode.Discrete);
|
||||
SwitchCharacter(axes.x);
|
||||
SwitchButton(-axes.y);
|
||||
|
||||
SelectedButton.TakeInput(In.GetAction(JoystickSide.Both, InteractMode.Continious));
|
||||
}
|
||||
|
||||
private void SelectCharacter()
|
||||
{
|
||||
OnCharacterSelected?.Invoke(SelectedCharacter);
|
||||
}
|
||||
|
||||
private void RequestExit()
|
||||
{
|
||||
OnExitRequested?.Invoke();
|
||||
}
|
||||
|
||||
private void DisplaySelectedCharacter()
|
||||
{
|
||||
_characterNameLabel.text = SelectedCharacter.characterName;
|
||||
_characterIcon.sprite = SelectedCharacter.visualModule.icon;
|
||||
|
||||
ClearTable();
|
||||
PrizeSet prizeSet = PrizeSystemManager.PrizeContainer.Sets[SelectedCharacter.CharacterIndex];
|
||||
DisplayPrizeSet(prizeSet);
|
||||
}
|
||||
|
||||
private void ClearTable()
|
||||
{
|
||||
for (int i = _prizeTable.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var go = _prizeTable.GetChild(i).gameObject;
|
||||
Destroy(go);
|
||||
Transform child = _prizeTable.GetChild(i);
|
||||
child.SetParent(null, false);
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayPrizeSet(PrizeSet prizeSet)
|
||||
{
|
||||
foreach (var item in prizeSet.Prizes)
|
||||
foreach (Prize prize in prizeSet.Prizes)
|
||||
{
|
||||
var view = Instantiate(_prizeViewPrefab, _prizeTable);
|
||||
view.SetPrize(item);
|
||||
PrizeView view = Instantiate(_prizeViewPrefab, _prizeTable);
|
||||
view.SetPrize(prize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,33 +1,45 @@
|
||||
using PrizeSystem;
|
||||
using PrizeSystem;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class CountablePrizeConfigurator : BasePrizeConfigurator, IControlable
|
||||
{
|
||||
public Image icon;
|
||||
public MNumberStepper numberInput;
|
||||
[SerializeField, FormerlySerializedAs("icon")] private Image _icon;
|
||||
[SerializeField, FormerlySerializedAs("numberInput")] private MNumberStepper _numberInput;
|
||||
|
||||
private PrizeType _prizeType;
|
||||
|
||||
public override void Configure(PrizeType prizeType)
|
||||
{
|
||||
icon.sprite = PrizeSystemManager.GetPrizeIcon(prizeType);
|
||||
_prizeType = prizeType;
|
||||
_icon.sprite = PrizeSystemManager.GetPrizeIcon(prizeType);
|
||||
|
||||
int maxValue = prizeType switch
|
||||
{
|
||||
int maxValue = prizeType switch
|
||||
{
|
||||
PrizeType.Hopper => 10,
|
||||
PrizeType.Ticket => 100,
|
||||
PrizeType.Marbles => 10,
|
||||
_ => 1
|
||||
_ => 1
|
||||
};
|
||||
|
||||
numberInput.Initialize(value: 1, min: 1, maxValue);
|
||||
_numberInput.Initialize(value: 1, min: 1, maxValue);
|
||||
}
|
||||
|
||||
public override void UpdateControls()
|
||||
{
|
||||
numberInput.SetDirection(In.GetAxis(JoystickSide.Both, InteractMode.Continious).x);
|
||||
_numberInput.SetDirection(In.GetAxis(JoystickSide.Both, InteractMode.Continious).x);
|
||||
|
||||
if (In.GetAction(JoystickSide.Both, InteractMode.Continious))
|
||||
if (In.GetAction(JoystickSide.Both, InteractMode.Discrete))
|
||||
{
|
||||
Prize prize = PrizeUtils.CreatePrize(CountablePrizeType.Hopper, numberInput.Value);
|
||||
CountablePrizeType countableType = _prizeType switch
|
||||
{
|
||||
PrizeType.Hopper => CountablePrizeType.Hopper,
|
||||
PrizeType.Ticket => CountablePrizeType.Ticket,
|
||||
PrizeType.Marbles => CountablePrizeType.Marbles,
|
||||
_ => CountablePrizeType.Hopper
|
||||
};
|
||||
Prize prize = PrizeUtils.CreatePrize(countableType, _numberInput.Value);
|
||||
Complete(prize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
|
||||
@ -6,40 +6,74 @@ namespace PrizeSystem
|
||||
{
|
||||
public class PrizeConverter : JsonConverter<Prize>
|
||||
{
|
||||
public override Prize ReadJson(JsonReader reader, Type objectType, Prize existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
public override Prize ReadJson(
|
||||
JsonReader reader,
|
||||
Type objectType,
|
||||
Prize existingValue,
|
||||
bool hasExistingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
var jsonObject = JObject.Load(reader);
|
||||
|
||||
var prizeTypeToken = jsonObject["PrizeType"];
|
||||
JObject jsonObject = JObject.Load(reader);
|
||||
JToken prizeTypeToken = jsonObject["PrizeType"];
|
||||
if (prizeTypeToken == null)
|
||||
throw new JsonSerializationException("Missing PrizeType field");
|
||||
|
||||
var prizeType = prizeTypeToken.ToObject<PrizeType>();
|
||||
|
||||
// Создаем объект нужного типа
|
||||
Prize prize = prizeType switch
|
||||
PrizeType prizeType = prizeTypeToken.ToObject<PrizeType>(serializer);
|
||||
return prizeType switch
|
||||
{
|
||||
PrizeType.None => new EmptyPrize(),
|
||||
PrizeType.Qr => new QrPrize(""), // временный, заполним ниже
|
||||
PrizeType.VitrinaBox => new VitrinaPrize(Array.Empty<int>()),
|
||||
PrizeType.Ticket or PrizeType.Marbles or PrizeType.Hopper =>
|
||||
new CountablePrize(CountablePrizeType.Ticket, 0), // временный
|
||||
PrizeType.Qr => new QrPrize(jsonObject.Value<string>("PrizeText") ?? string.Empty),
|
||||
PrizeType.VitrinaBox => new VitrinaPrize(
|
||||
jsonObject["Boxes"]?.ToObject<int[]>(serializer) ?? Array.Empty<int>()),
|
||||
PrizeType.Hopper or PrizeType.Ticket or PrizeType.Marbles => new CountablePrize(
|
||||
jsonObject["Type"]?.ToObject<CountablePrizeType>(serializer)
|
||||
?? GetCountableType(prizeType),
|
||||
jsonObject.Value<int?>("Amount") ?? 0),
|
||||
_ => throw new NotSupportedException($"Unknown prize type: {prizeType}")
|
||||
};
|
||||
|
||||
// Заполняем поля через стандартную десериализацию
|
||||
using (var subReader = jsonObject.CreateReader())
|
||||
{
|
||||
serializer.Populate(subReader, prize);
|
||||
}
|
||||
|
||||
return prize;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, Prize value, JsonSerializer serializer)
|
||||
{
|
||||
var jsonObject = JObject.FromObject(value, serializer);
|
||||
jsonObject.WriteTo(writer);
|
||||
writer.WriteStartObject();
|
||||
WriteProperty(writer, serializer, "PrizeType", value.PrizeType);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case CountablePrize countablePrize:
|
||||
WriteProperty(writer, serializer, "Type", countablePrize.Type);
|
||||
WriteProperty(writer, serializer, "Amount", countablePrize.Amount);
|
||||
break;
|
||||
case QrPrize qrPrize:
|
||||
WriteProperty(writer, serializer, "PrizeText", qrPrize.PrizeText);
|
||||
break;
|
||||
case VitrinaPrize vitrinaPrize:
|
||||
WriteProperty(writer, serializer, "Boxes", vitrinaPrize.Boxes);
|
||||
break;
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void WriteProperty(
|
||||
JsonWriter writer,
|
||||
JsonSerializer serializer,
|
||||
string propertyName,
|
||||
object value)
|
||||
{
|
||||
writer.WritePropertyName(propertyName);
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
private static CountablePrizeType GetCountableType(PrizeType prizeType)
|
||||
{
|
||||
return prizeType switch
|
||||
{
|
||||
PrizeType.Hopper => CountablePrizeType.Hopper,
|
||||
PrizeType.Ticket => CountablePrizeType.Ticket,
|
||||
PrizeType.Marbles => CountablePrizeType.Marbles,
|
||||
_ => CountablePrizeType.Hopper
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,13 @@ public class PrizeButton : MSignalButton
|
||||
_textMeshPro.text = GetText(prizeType);
|
||||
}
|
||||
|
||||
public void Configure(Prize prize)
|
||||
{
|
||||
_prizeType = prize.PrizeType;
|
||||
_image.sprite = PrizeSystemManager.GetPrizeIcon(prize.PrizeType);
|
||||
_textMeshPro.text = PrizeView.GetPrizeText(prize);
|
||||
}
|
||||
|
||||
private string GetText(PrizeType prizeType)
|
||||
=> prizeType switch
|
||||
{
|
||||
@ -43,4 +50,4 @@ public class PrizeButton : MSignalButton
|
||||
_ => "ошибка"
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,78 +1,250 @@
|
||||
using CharacterSystem;
|
||||
using CharacterSystem;
|
||||
using PrizeSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class PrizesSelector : MonoBehaviour
|
||||
public class PrizesSelector : MonoBehaviour, IControlable
|
||||
{
|
||||
[SerializeField] RectTransform _addedPrizesTable;
|
||||
[SerializeField] PrizeView _prizeViewPrefab;
|
||||
public event Action OnConfirmed;
|
||||
|
||||
[SerializeField] AvailablePrizesTable _availablePrizesTable;
|
||||
int index = 0;
|
||||
[SerializeField] private RectTransform _addedPrizesTable;
|
||||
[SerializeField] private AvailablePrizesTable _availablePrizesTable;
|
||||
[SerializeField] private MSignalButton _selectButton;
|
||||
[SerializeField, FormerlySerializedAs("pointer")] private RectTransform _pointer;
|
||||
|
||||
private readonly List<PrizeButton> _addedPrizeButtons = new();
|
||||
private PrizeSet _prizeSet;
|
||||
private SelectionArea _selectionArea;
|
||||
private int _rowIndex;
|
||||
private bool _waitForActionRelease;
|
||||
|
||||
private PrizeSet set;
|
||||
public bool ControlsEnabled { get; set; } = true;
|
||||
|
||||
public bool skipFrame = false;
|
||||
private enum SelectionArea
|
||||
{
|
||||
Available,
|
||||
Added,
|
||||
Confirm
|
||||
}
|
||||
|
||||
[SerializeField] Transform pointer;
|
||||
private void Awake()
|
||||
{
|
||||
_availablePrizesTable.OnPrizeConfigured += OnPrizeConfigured;
|
||||
_selectButton.OnClick += Confirm;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_availablePrizesTable.OnPrizeConfigured -= OnPrizeConfigured;
|
||||
_selectButton.OnClick -= Confirm;
|
||||
}
|
||||
|
||||
public void Open(Character character)
|
||||
{
|
||||
print($"открыто с персонажем {character.CharacterIndex}");
|
||||
gameObject.SetActive(true);
|
||||
_prizeSet = PrizeSystemManager.PrizeContainer.Sets[character.CharacterIndex];
|
||||
RefreshView();
|
||||
|
||||
set = PrizeSystemManager.PrizeContainer.Sets[character.CharacterIndex];
|
||||
UpdateView();
|
||||
_selectionArea = _availablePrizesTable.PrizeButtons.Count > 0
|
||||
? SelectionArea.Available
|
||||
: GetInitialFallbackArea();
|
||||
_rowIndex = 0;
|
||||
_waitForActionRelease = In.GetAction(JoystickSide.Both, InteractMode.Continious);
|
||||
RebuildLayouts();
|
||||
UpdatePointer();
|
||||
}
|
||||
|
||||
private void UpdateView()
|
||||
public void UpdateControls()
|
||||
{
|
||||
ClearTable();
|
||||
DisplayPrizeSet(set);
|
||||
|
||||
_availablePrizesTable.Refresh(set);
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (skipFrame)
|
||||
bool actionPressed = In.GetAction(JoystickSide.Both, InteractMode.Continious);
|
||||
if (_waitForActionRelease)
|
||||
{
|
||||
if(In.AnyButton() == false)
|
||||
skipFrame = false;
|
||||
_waitForActionRelease = actionPressed;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_availablePrizesTable.prizeButtons == null) return;
|
||||
if (_availablePrizesTable.prizeButtons.Count == 0) return;
|
||||
Vector2Int axes = In.GetAxis(JoystickSide.Both, InteractMode.Discrete);
|
||||
NavigateHorizontal(axes.x);
|
||||
NavigateVertical(axes.y);
|
||||
GetSelectedButton()?.TakeInput(actionPressed);
|
||||
}
|
||||
|
||||
index -= In.GetAxis(JoystickSide.Both, InteractMode.Discrete).y;
|
||||
index = Mathf.Clamp(index, 0, _availablePrizesTable.prizeButtons.Count);
|
||||
pointer.position = _availablePrizesTable.prizeButtons[index].transform.position;
|
||||
private void RefreshView()
|
||||
{
|
||||
ClearAddedPrizes();
|
||||
DisplayAddedPrizes();
|
||||
_availablePrizesTable.Refresh(_prizeSet);
|
||||
}
|
||||
|
||||
|
||||
if (In.GetAction(JoystickSide.Both, InteractMode.Continious))
|
||||
private void DisplayAddedPrizes()
|
||||
{
|
||||
foreach (Prize prize in _prizeSet.Prizes.Where(prize => prize is not EmptyPrize))
|
||||
{
|
||||
_availablePrizesTable.prizeButtons[index].ClickAnimation();
|
||||
PrizeButton button = Instantiate(_availablePrizesTable.PrizeButtonPrefab, _addedPrizesTable);
|
||||
button.Configure(prize);
|
||||
button.OnPrize += _ => RemovePrize(prize);
|
||||
_addedPrizeButtons.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearTable()
|
||||
private void ClearAddedPrizes()
|
||||
{
|
||||
_addedPrizeButtons.Clear();
|
||||
for (int i = _addedPrizesTable.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var go = _addedPrizesTable.GetChild(i).gameObject;
|
||||
Destroy(go);
|
||||
Transform child = _addedPrizesTable.GetChild(i);
|
||||
child.SetParent(null, false);
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayPrizeSet(PrizeSet prizeSet)
|
||||
private void OnPrizeConfigured(Prize prize)
|
||||
{
|
||||
foreach (var item in prizeSet.Prizes)
|
||||
_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)
|
||||
{
|
||||
var view = Instantiate(_prizeViewPrefab, _addedPrizesTable);
|
||||
view.SetPrize(item);
|
||||
_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();
|
||||
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()
|
||||
{
|
||||
MSignalButton selectedButton = GetSelectedButton();
|
||||
if (selectedButton != null)
|
||||
_pointer.position = selectedButton.transform.position;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user