PJ/Assets/scripts/dotfs_scripts/UI_ShopItem.cs

282 lines
No EOL
8.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class UI_ShopItem : MonoBehaviour
{
[Header("Databases")]
[SerializeField] private ShopAudioDatabase audioDatabase; // Ссылка на БД звуков
[Header("UI Elements")]
[SerializeField] public Color giftBackgroundColor = new Color32(255, 0, 69, 255); // Твой FF0045
[SerializeField] private TMP_Text titleText;
[SerializeField] private TMP_Text priceText;
[SerializeField] private TMP_Text oldPriceText;
[SerializeField] private TMP_Text descpText;
[SerializeField] private Image iconImage;
[Header("Audio Overrides (Optional)")]
[SerializeField] private AudioClip customPurchaseSfx;
[SerializeField] private AudioClip customErrorSfx;
[Header("Settings & Config")]
[SerializeField] private ShopVisualConfig config;
[SerializeField] private ShopIconDatabase iconDb;
// Внимание: если у тебя несколько товаров, статический инстанс делать нельзя!
// public static UI_ShopItem Instance;
private ShopItem _data;
private Button _button;
private Image _backgroundImage;
private Color _initialColor;
private Vector3 _originalScale;
private Coroutine _pulseCoroutine;
private Coroutine _shakeCoroutine;
private readonly Color _giftBgColor = new Color32(255, 0, 69, 255);
private void Awake()
{
_button = GetComponent<Button>();
_backgroundImage = GetComponent<Image>();
if (_backgroundImage != null)
_initialColor = _backgroundImage.color;
_originalScale = transform.localScale;
if (_button != null) _button.onClick.AddListener(OnPurchaseAttempt);
}
public void Setup(ShopItem item)
{
_data = item;
if (_data.isLocked)
{
gameObject.SetActive(false);
return;
}
gameObject.SetActive(true);
StopAllCoroutines();
transform.localScale = _originalScale;
titleText.text = item.title;
descpText.text = item.description;
if (iconImage != null && iconDb != null)
{
Sprite foundIcon = iconDb.GetIcon(item.icon_id);
iconImage.sprite = foundIcon;
iconImage.gameObject.SetActive(foundIcon != null);
iconImage.preserveAspect = item.preserve_aspect;
}
UpdateVisualState();
HandleAnimations();
}
public void SetPrice(float price, float discountPercent)
{
if (config == null) return;
if (price <= 0)
{
priceText.text = "0000";
priceText.color = config.giftColor;
}
else if (discountPercent > 0 && discountPercent < 100)
{
float finalPrice = price * (1 - (discountPercent / 100f));
priceText.text = Mathf.CeilToInt(finalPrice).ToString();
priceText.color = config.discountedPriceColor;
}
else
{
priceText.text = price.ToString();
priceText.color = config.ironColor;
}
}
public void UpdateVisualState()
{
if (config == null || _data == null) return;
bool isFree = _data.isGift || _data.FinalPrice <= 0;
bool hasDiscount = _data.discount > 0 && _data.discount < 100;
// --- ЛОГИКА ЦВЕТА ФОНА ---
if (_backgroundImage != null)
{
if (isFree)
{
_backgroundImage.color = config.giftBackgroundColor;
}
else if (hasDiscount)
{
_backgroundImage.color = config.discountBackgroundColor;
}
else
{
_backgroundImage.color = _initialColor;
}
}
// --- ЛОГИКА ТЕКСТА ЦЕНЫ ---
if (isFree)
{
priceText.text = "FREE";
priceText.color = config.giftColor;
priceText.outlineWidth = 0;
oldPriceText.gameObject.SetActive(false);
}
else
{
string symbol = _data.currency_type == "Gold" ? "Go" : "Ir";
priceText.text = $"{_data.FinalPrice}{symbol}";
ApplyCurrencyStyle(_data.currency_type);
if (hasDiscount)
{
priceText.color = config.discountedPriceColor;
oldPriceText.text = $"<s>{_data.price}{symbol}</s>";
oldPriceText.gameObject.SetActive(true);
}
else
{
oldPriceText.gameObject.SetActive(false);
}
}
}
private void ApplyCurrencyStyle(string type)
{
if (type == "Gold")
{
priceText.color = config.goldColor;
priceText.outlineWidth = 0;
}
else // Iron
{
priceText.color = config.ironColor;
priceText.outlineColor = config.ironOutlineColor;
priceText.outlineWidth = config.ironOutlineWidth;
}
}
private void HandleAnimations()
{
if (_data.isGift || _data.discount > 0)
{
_pulseCoroutine = StartCoroutine(PulseAnimation());
}
}
private void OnPurchaseAttempt()
{
bool canAfford = MANAGER_Shop.Instance.CanPlayerAfford(_data);
if (canAfford)
{
StartCoroutine(SuccessfulPurchaseSequence());
}
else
{
FeedbackInsufficientFunds();
}
}
private void FeedbackInsufficientFunds()
{
if (_shakeCoroutine != null) StopCoroutine(_shakeCoroutine);
_shakeCoroutine = StartCoroutine(ShakeAndRedden());
// Воспроизводим звук ошибки
PlayShopSound(_data?.errorSfxId, SFX_AudioControl.Instance.defaultErrorSFX, customErrorSfx);
}
private IEnumerator ShakeAndRedden()
{
Color originalColor = priceText.color;
priceText.color = config.insufficientFundsColor;
Vector3 originalPos = transform.localPosition;
float elapsed = 0f;
while (elapsed < config.shakeDuration)
{
elapsed += Time.deltaTime;
float x = Random.Range(-1f, 1f) * config.shakeIntensity;
transform.localPosition = originalPos + new Vector3(x, 0, 0);
yield return null;
}
transform.localPosition = originalPos;
priceText.color = originalColor;
}
private IEnumerator PulseAnimation()
{
while (true)
{
float scale = 1f + Mathf.Sin(Time.time * config.pulseSpeed) * config.pulseAmount;
transform.localScale = _originalScale * scale;
yield return null;
}
}
private IEnumerator SuccessfulPurchaseSequence()
{
// Воспроизводим звук успешной покупки
PlayShopSound(_data?.purchaseSfxId, SFX_AudioControl.Instance.defaultPurchaseSFX, customPurchaseSfx);
_button.interactable = false;
// Анимация исчезновения
float timer = 0;
float duration = 0.3f;
while (timer < duration)
{
timer += Time.deltaTime;
transform.localScale = Vector3.Lerp(_originalScale, Vector3.zero, timer / duration);
yield return null;
}
MANAGER_Shop.Instance.BuyItem(_data);
}
// --- ИДЕТ ПОЛНОСТЬЮ ПЕРЕРАБОТАННЫЙ МЕТОД ЗВУКА ---
private void PlayShopSound(string jsonId, AudioClip globalDefault, AudioClip localOverride)
{
if (SFX_AudioControl.Instance == null) return;
AudioClip clipToPlay = null;
// 1. Поиск клипа (логика та же)
if (audioDatabase != null && !string.IsNullOrEmpty(jsonId))
clipToPlay = audioDatabase.GetAudioClip(jsonId);
if (clipToPlay == null && localOverride != null)
clipToPlay = localOverride;
if (clipToPlay == null)
clipToPlay = globalDefault;
// 2. А вот тут магия затухания!
if (clipToPlay != null)
{
// Если ID из JSON равен "dohodyaga", вызываем метод с затуханием музыки
if (jsonId == "dohodyaga")
{
SFX_AudioControl.Instance.PlaySfxWithDucking(clipToPlay);
}
else
{
// Для всех остальных — обычный звук
SFX_AudioControl.Instance.PlayOneShot(clipToPlay);
}
}
}
}