feat: Add display customization for balance and main menu texts
- Добавлена система анимированных текстовых сплешей (TextSplash) с настройками масштаба, покачивания, движения и цвета - Добавлена поддержка циклического воспроизведения анимации сплешей - Добавлена настройка частоты покачивания для более плавной и непрерывной анимации - Добавлено отображение валюты в компоненте BalanceDisplay (берется из настройки payment.currency) - Добавлены поля для отображения номера поддержки и суперприза в главном меню - Добавлена возможность форматирования текстов через string.Format в MainMenu (supportNumberFormat, superPrizeFormat) - Валюта и тексты автоматически обновляются при изменении настроек
This commit is contained in:
parent
2417f58f61
commit
a66aa2cb83
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,7 @@ namespace RR.Common.Managers
|
||||
|
||||
// Получаем номер телефона из новой системы настроек (если он есть)
|
||||
var settings = SettingsManager.Instance;
|
||||
_phoneNumber = settings?.GetString("phoneNumber") ?? string.Empty;
|
||||
_phoneNumber = settings?.GetString("prizes.phoneNumber") ?? string.Empty;
|
||||
_phoneNumber = PhoneNumberUtils.ValidatePhoneNumber(_phoneNumber);
|
||||
_phoneNumber = PhoneNumberUtils.ApplyPhoneMask(_phoneNumber, _phoneNumberMask);
|
||||
|
||||
|
||||
@ -225,6 +225,32 @@ MonoBehaviour:
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: payment.currency
|
||||
displayName: "\u0412\u0430\u043B\u044E\u0442\u0430 \u0431\u0430\u043B\u0430\u043D\u0441\u0430"
|
||||
description:
|
||||
group: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C"
|
||||
shownInSettings: 0
|
||||
exposed: 0
|
||||
valueType: 3
|
||||
defaultBool: 0
|
||||
defaultInt: 10
|
||||
defaultFloat: 0
|
||||
defaultString: "\u0440\u0443\u0431."
|
||||
minInt: 5
|
||||
maxInt: 1000
|
||||
intDisplayFormat: 1
|
||||
intStep: 5
|
||||
minFloat: 0
|
||||
maxFloat: 1
|
||||
displayAsPercentage: 0
|
||||
applyTarget: 0
|
||||
audioTargetType: 0
|
||||
buttonText:
|
||||
buttonData:
|
||||
buttonColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: prizes.giveSmallPrize
|
||||
displayName: "\u0412\u044B\u0434\u0430\u0432\u0430\u0442\u044C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0439
|
||||
\u043F\u0440\u0438\u0437"
|
||||
@ -359,6 +385,32 @@ MonoBehaviour:
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: prizes.bigPrize
|
||||
displayName: "\u0421\u0443\u043F\u0435\u0440\u043F\u0440\u0438\u0437"
|
||||
description:
|
||||
group: "\u041F\u0440\u0438\u0437\u044B \u0438 \u0432\u044B\u0434\u0430\u0447\u0430"
|
||||
shownInSettings: 0
|
||||
exposed: 0
|
||||
valueType: 3
|
||||
defaultBool: 0
|
||||
defaultInt: 1
|
||||
defaultFloat: 0
|
||||
defaultString: "\u041D\u0435\u0432\u0430\u043B\u044F\u0448\u043A\u0430"
|
||||
minInt: 0
|
||||
maxInt: 20
|
||||
intDisplayFormat: 0
|
||||
intStep: 1
|
||||
minFloat: 0
|
||||
maxFloat: 1
|
||||
displayAsPercentage: 0
|
||||
applyTarget: 0
|
||||
audioTargetType: 0
|
||||
buttonText: "\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430"
|
||||
buttonData:
|
||||
buttonColor: {r: 0.8490566, g: 0.40749258, b: 0.13216448, a: 1}
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: gameplay.startLives
|
||||
displayName: "\u041D\u0430\u0447\u0430\u043B\u044C\u043D\u044B\u0435 \u0436\u0438\u0437\u043D\u0438"
|
||||
description:
|
||||
@ -547,3 +599,29 @@ MonoBehaviour:
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: btn.currency
|
||||
displayName: "\u0412\u0432\u0435\u0441\u0442\u0438 \u0432\u0430\u043B\u044E\u0442\u0443"
|
||||
description:
|
||||
group: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C"
|
||||
shownInSettings: 1
|
||||
exposed: 0
|
||||
valueType: 4
|
||||
defaultBool: 1
|
||||
defaultInt: 0
|
||||
defaultFloat: 0
|
||||
defaultString:
|
||||
minInt: 0
|
||||
maxInt: 0
|
||||
intDisplayFormat: 0
|
||||
intStep: 1
|
||||
minFloat: 0
|
||||
maxFloat: 1
|
||||
displayAsPercentage: 0
|
||||
applyTarget: 0
|
||||
audioTargetType: 0
|
||||
buttonText: "\u0412\u0432\u0435\u0441\u0442\u0438 \u0432\u0430\u043B\u044E\u0442\u0443"
|
||||
buttonData:
|
||||
buttonColor: {r: 0.16300285, g: 0.64997125, b: 0.9339623, a: 1}
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using RR.Common.Managers;
|
||||
using RR.Common.Settings;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@ -20,8 +21,10 @@ namespace RR.Common.UI
|
||||
[SerializeField] private AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 1, 1, 1);
|
||||
|
||||
private BalanceManager _balanceManager;
|
||||
private SettingsManager _settingsManager;
|
||||
private Coroutine _animationCoroutine;
|
||||
private Vector3 _originalScale;
|
||||
private string _currency = "";
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@ -34,6 +37,15 @@ namespace RR.Common.UI
|
||||
private void Start()
|
||||
{
|
||||
_balanceManager = BalanceManager.Instance;
|
||||
_settingsManager = SettingsManager.Instance;
|
||||
|
||||
// Загружаем валюту из настроек
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
_currency = _settingsManager.GetString("payment.currency");
|
||||
_settingsManager.OnSettingsLoaded += OnSettingsChanged;
|
||||
_settingsManager.OnSettingsSaved += OnSettingsChanged;
|
||||
}
|
||||
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
@ -59,6 +71,29 @@ namespace RR.Common.UI
|
||||
{
|
||||
_balanceManager.OnBalanceChanged.RemoveListener(OnBalanceChanged);
|
||||
}
|
||||
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
_settingsManager.OnSettingsLoaded -= OnSettingsChanged;
|
||||
_settingsManager.OnSettingsSaved -= OnSettingsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик изменения настроек
|
||||
/// </summary>
|
||||
private void OnSettingsChanged()
|
||||
{
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
_currency = _settingsManager.GetString("payment.currency");
|
||||
|
||||
// Обновляем отображение с новой валютой
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
UpdateBalanceDisplay(_balanceManager.CurrentBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -81,7 +116,15 @@ namespace RR.Common.UI
|
||||
{
|
||||
if (balanceText != null)
|
||||
{
|
||||
balanceText.text = string.Format(textFormat, balance);
|
||||
string balanceStr = string.Format(textFormat, balance);
|
||||
|
||||
// Добавляем валюту в конце через пробел, если она указана
|
||||
if (!string.IsNullOrEmpty(_currency))
|
||||
{
|
||||
balanceStr += " " + _currency;
|
||||
}
|
||||
|
||||
balanceText.text = balanceStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
@ -15,14 +15,20 @@ namespace RR.Common.UI
|
||||
|
||||
[Header("Тексты")]
|
||||
[SerializeField] private TextMeshProUGUI paymentText;
|
||||
[SerializeField] private TextMeshProUGUI supportNumberText;
|
||||
[SerializeField] private TextMeshProUGUI superPrizeText;
|
||||
|
||||
[Header("Форматы текстов")]
|
||||
[SerializeField] private string supportNumberFormat = "{0}";
|
||||
[SerializeField] private string superPrizeFormat = "{0}";
|
||||
|
||||
private RR.Common.Managers.BalanceManager _balanceManager;
|
||||
private RR.Common.Settings.SettingsManager _settingsManager;
|
||||
private Managers.BalanceManager _balanceManager;
|
||||
private SettingsManager _settingsManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_balanceManager = RR.Common.Managers.BalanceManager.Instance;
|
||||
_settingsManager = RR.Common.Settings.SettingsManager.Instance;
|
||||
_balanceManager = Managers.BalanceManager.Instance;
|
||||
_settingsManager = SettingsManager.Instance;
|
||||
|
||||
Bootstrap();
|
||||
|
||||
@ -38,6 +44,9 @@ namespace RR.Common.UI
|
||||
{
|
||||
_settingsManager.OnSettingsLoaded += OnSettingsChanged;
|
||||
_settingsManager.OnSettingsSaved += OnSettingsChanged;
|
||||
|
||||
// Обновляем тексты сразу при старте
|
||||
UpdateTextsFromSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +101,26 @@ namespace RR.Common.UI
|
||||
private void OnSettingsChanged()
|
||||
{
|
||||
UpdatePlayButtonState();
|
||||
UpdateTextsFromSettings();
|
||||
}
|
||||
|
||||
private void UpdateTextsFromSettings()
|
||||
{
|
||||
if (_settingsManager == null) return;
|
||||
|
||||
// Обновляем номер поддержки
|
||||
if (supportNumberText != null)
|
||||
{
|
||||
string supportNumber = _settingsManager.GetString("payment.supportNumber");
|
||||
supportNumberText.text = string.Format(supportNumberFormat, supportNumber);
|
||||
}
|
||||
|
||||
// Обновляем описание суперприза
|
||||
if (superPrizeText != null)
|
||||
{
|
||||
string superPrize = _settingsManager.GetString("prizes.bigPrize");
|
||||
superPrizeText.text = string.Format(superPrizeFormat, superPrize);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayButtonState()
|
||||
|
||||
182
Assets/Scripts/UI/TextSplash.cs
Normal file
182
Assets/Scripts/UI/TextSplash.cs
Normal file
@ -0,0 +1,182 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RR.Common.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Компонент для создания анимированного сплеша текста.
|
||||
/// Поддерживает изменение размера, покачивание и изменение цвета.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class TextSplash : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки масштаба")]
|
||||
[SerializeField] private bool animateScale = true;
|
||||
[SerializeField] private AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
[SerializeField] private float startScale = 0.5f;
|
||||
[SerializeField] private float endScale = 1.5f;
|
||||
|
||||
[Header("Настройки покачивания")]
|
||||
[SerializeField] private bool animateSwing = true;
|
||||
[SerializeField] private float swingAmplitude = 20f;
|
||||
[SerializeField] private float swingFrequency = 2f;
|
||||
[SerializeField] private AnimationCurve swingCurve = AnimationCurve.EaseInOut(0, 0, 0.5f, 1);
|
||||
|
||||
[Header("Настройки цвета")]
|
||||
[SerializeField] private bool animateColor = true;
|
||||
[SerializeField] private Gradient colorGradient = new Gradient();
|
||||
|
||||
[Header("Настройки движения")]
|
||||
[SerializeField] private bool animateMovement = true;
|
||||
[SerializeField] private Vector2 movementDirection = Vector2.up;
|
||||
[SerializeField] private float movementDistance = 100f;
|
||||
[SerializeField] private AnimationCurve movementCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
|
||||
[Header("Общие настройки")]
|
||||
[SerializeField] private float animationDuration = 1f;
|
||||
[SerializeField] private bool loopAnimation = false;
|
||||
[SerializeField] private bool destroyOnComplete = true;
|
||||
|
||||
private TextMeshProUGUI _textComponent;
|
||||
private RectTransform _rectTransform;
|
||||
private Vector2 _startPosition;
|
||||
private float _elapsed;
|
||||
private bool _isAnimating;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_textComponent = GetComponent<TextMeshProUGUI>();
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
_startPosition = _rectTransform.anchoredPosition;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
StartAnimation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запускает анимацию сплеша
|
||||
/// </summary>
|
||||
public void StartAnimation()
|
||||
{
|
||||
_elapsed = 0f;
|
||||
_isAnimating = true;
|
||||
_startPosition = _rectTransform.anchoredPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливает текст сплеша
|
||||
/// </summary>
|
||||
public void SetText(string text)
|
||||
{
|
||||
if (_textComponent != null)
|
||||
{
|
||||
_textComponent.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливает начальный цвет
|
||||
/// </summary>
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
if (_textComponent != null)
|
||||
{
|
||||
_textComponent.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!_isAnimating) return;
|
||||
|
||||
_elapsed += Time.unscaledDeltaTime;
|
||||
float t = Mathf.Clamp01(_elapsed / animationDuration);
|
||||
|
||||
// Анимация масштаба
|
||||
if (animateScale)
|
||||
{
|
||||
float scaleValue = Mathf.Lerp(startScale, endScale, scaleCurve.Evaluate(t));
|
||||
_rectTransform.localScale = Vector3.one * scaleValue;
|
||||
}
|
||||
|
||||
// Анимация покачивания (rotation)
|
||||
if (animateSwing)
|
||||
{
|
||||
float swingValue = swingCurve.Evaluate(t) * swingAmplitude;
|
||||
// Используем частоту для создания непрерывного покачивания
|
||||
float swingAngle = Mathf.Sin(t * Mathf.PI * 2 * swingFrequency) * swingValue;
|
||||
_rectTransform.localRotation = Quaternion.Euler(0, 0, swingAngle);
|
||||
}
|
||||
|
||||
// Анимация движения
|
||||
if (animateMovement)
|
||||
{
|
||||
float moveValue = movementCurve.Evaluate(t) * movementDistance;
|
||||
Vector2 offset = movementDirection.normalized * moveValue;
|
||||
_rectTransform.anchoredPosition = _startPosition + offset;
|
||||
}
|
||||
|
||||
// Анимация цвета
|
||||
if (animateColor && _textComponent != null)
|
||||
{
|
||||
_textComponent.color = colorGradient.Evaluate(t);
|
||||
}
|
||||
|
||||
// Завершение анимации
|
||||
if (t >= 1f)
|
||||
{
|
||||
if (loopAnimation)
|
||||
{
|
||||
// Перезапускаем анимацию с начала
|
||||
_elapsed = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isAnimating = false;
|
||||
|
||||
if (destroyOnComplete)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливает длительность анимации
|
||||
/// </summary>
|
||||
public void SetDuration(float duration)
|
||||
{
|
||||
animationDuration = duration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Останавливает анимацию
|
||||
/// </summary>
|
||||
public void StopAnimation()
|
||||
{
|
||||
_isAnimating = false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Предварительный просмотр в редакторе
|
||||
/// </summary>
|
||||
private void OnValidate()
|
||||
{
|
||||
if (colorGradient == null || colorGradient.colorKeys.Length == 0)
|
||||
{
|
||||
// Устанавливаем градиент по умолчанию (белый -> прозрачный)
|
||||
colorGradient = new Gradient();
|
||||
colorGradient.SetKeys(
|
||||
new[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) },
|
||||
new[] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/UI/TextSplash.cs.meta
Normal file
3
Assets/Scripts/UI/TextSplash.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af4127b13263407c8aa7f5a18f82f670
|
||||
timeCreated: 1770901668
|
||||
@ -28,11 +28,6 @@ namespace RR.Common.Utility
|
||||
{
|
||||
// Оставляем только цифры
|
||||
string digitsOnly = System.Text.RegularExpressions.Regex.Replace(number, @"\D", "");
|
||||
|
||||
if (digitsOnly.StartsWith("+") && digitsOnly.Length == 12)
|
||||
{
|
||||
return digitsOnly[2..];
|
||||
}
|
||||
|
||||
// Проверяем формат
|
||||
if ((digitsOnly.StartsWith("8") || digitsOnly.StartsWith("7")) && digitsOnly.Length == 11)
|
||||
|
||||
@ -18,7 +18,7 @@ MonoBehaviour:
|
||||
m_SeeAllPackageVersions: 0
|
||||
m_DismissPreviewPackagesInUse: 0
|
||||
oneTimeWarningShown: 0
|
||||
oneTimeDeprecatedPopUpShown: 0
|
||||
oneTimePackageErrorsPopUpShown: 1
|
||||
m_Registries:
|
||||
- m_Id: main
|
||||
m_Name:
|
||||
@ -35,6 +35,6 @@ MonoBehaviour:
|
||||
m_RegistryInfoDraft:
|
||||
m_Modified: 0
|
||||
m_ErrorMessage:
|
||||
m_UserModificationsInstanceId: -886
|
||||
m_OriginalInstanceId: -888
|
||||
m_UserModificationsInstanceId: -894
|
||||
m_OriginalInstanceId: -896
|
||||
m_LoadAssets: 0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user