387 lines
13 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
/// <summary>
/// Îòâå÷àåò çà îòîáðàæåíèå ýêðàíà GameOver è îáíîâëåíèå êíîïîê
/// </summary>
public class GameOverUI : MonoBehaviour
{
[SerializeField] private int playerId;
[SerializeField] private GameManager gameManager;
[Header("UI Elements")]
[SerializeField] private Button replayButton;
[SerializeField] private Button continueButton;
[SerializeField] private Button menuButton; // Êíîïêà ìåíþ
[SerializeField] private TextMeshProUGUI resultText;
[SerializeField] private GameObject uiParticle;
[SerializeField] private GameOver gameOverStatusImage;
[Header("Animation Settings")]
[SerializeField] private Image firstImage; // Ïåðâàÿ êàðòèíêà
[SerializeField] private Image secondImage; // Âòîðàÿ êàðòèíêà
[SerializeField] private float popDuration = 0.3f; // Äëèòåëüíîñòü "âûáðîñà" â ýêðàí
[SerializeField] private float popScale = 1.5f; // Ìàêñèìàëüíûé ìàñøòàá ïðè "âûáðîñå"
[SerializeField] private float delayBetweenElements = 0.15f; // Çàäåðæêà ìåæäó ïîÿâëåíèåì ýëåìåíòîâ
[SerializeField] private float buttonSlideDuration = 0.25f; // Äëèòåëüíîñòü âûåçäà êíîïîê
[SerializeField] private float buttonSlideOffset = 500f; // Ðàññòîÿíèå çà ýêðàíîì (ïèêñåëåé)
private Coroutine showAnimationCoroutine;
private Vector2 replayButtonOriginalPos;
private Vector2 continueButtonOriginalPos;
private Vector2 menuButtonOriginalPos;
private bool positionsCached;
private bool eventsSubscribed;
// CanvasGroup äëÿ "âèçóàëüíîãî" ñêðûòèÿ (íå ìåíÿåò activeSelf)
private CanvasGroup replayCg;
private CanvasGroup continueCg;
private CanvasGroup menuCg;
// Äëÿ îáíîâëåíèÿ interactable â UpdateButtons íóæíî ïîìíèòü ðåæèì
private bool lastIsBotGame;
private void OnEnable()
{
ComWrapper.OnInitialize += Subscribe;
if (!eventsSubscribed && (ComWrapper.onCoinAdded != null || ComWrapper.onCoinRemoved != null))
Subscribe();
EnsureCanvasGroups();
}
private void OnDisable()
{
if (eventsSubscribed)
{
if (ComWrapper.onCoinAdded != null) ComWrapper.onCoinAdded.RemoveListener(HandleCoinsChanged);
if (ComWrapper.onCoinRemoved != null) ComWrapper.onCoinRemoved.RemoveListener(HandleCoinsChanged);
eventsSubscribed = false;
}
ComWrapper.OnInitialize -= Subscribe;
}
private void EnsureCanvasGroups()
{
replayCg = EnsureCanvasGroup(replayButton);
continueCg = EnsureCanvasGroup(continueButton);
menuCg = EnsureCanvasGroup(menuButton);
}
private static CanvasGroup EnsureCanvasGroup(Button b)
{
if (b == null) return null;
var cg = b.GetComponent<CanvasGroup>();
if (cg == null) cg = b.gameObject.AddComponent<CanvasGroup>();
return cg;
}
private void Subscribe()
{
if (eventsSubscribed) return;
if (ComWrapper.onCoinAdded != null) ComWrapper.onCoinAdded.AddListener(HandleCoinsChanged);
if (ComWrapper.onCoinRemoved != null) ComWrapper.onCoinRemoved.AddListener(HandleCoinsChanged);
eventsSubscribed = true;
}
private void HandleCoinsChanged(int playerID, int newAmount)
{
// Îáíîâëÿåì êíîïêè òîëüêî åñëè èçìåíèëñÿ áàëàíñ íàøåãî èãðîêà èëè åãî îïïîíåíòà
int oponentId = playerId == 1 ? 2 : 1;
if (playerID == playerId || playerID == oponentId)
{
UpdateButtons();
}
}
public void Show(bool isWin, bool isBotGame)
{
lastIsBotGame = isBotGame;
// Îñòàíàâëèâàåì ïðåäûäóùóþ àíèìàöèþ åñëè îíà åù¸ èä¸ò
if (showAnimationCoroutine != null)
{
StopCoroutine(showAnimationCoroutine);
}
EnsureCanvasGroups();
// 1) Ñðàçó îïðåäåëÿåì, êàêèå êíîïêè àêòèâíû (÷òîáû êóðñîð èõ âèäåë)
ApplyButtonVisibility(isWin, isBotGame);
// 2) Îáíîâëÿåì òåêñòû/èíòåðàêòèâíîñòü äî àíèìàöèé
if (uiParticle != null)
uiParticle.SetActive(isWin);
if (resultText != null)
{
resultText.text = isWin ? "Õîðîø!" : "Óâû...";
resultText.color = isWin ? new Color(1f, 0.84f, 0f) : Color.white;
if (gameOverStatusImage != null)
gameOverStatusImage.GameOverSwitch(isWin);
}
// 3) Ñðàçó îáíîâëÿåì interactable (çàâèñèò îò áàëàíñà)
UpdateButtons();
// 4) Ñðàçó óâåäîìëÿåì êóðñîð, ÷òî íàáîð êíîïîê èçìåíèëñÿ
if (gameManager != null && gameManager.uiManager != null)
gameManager.uiManager.OnPanelChanged?.Invoke();
// 5) Òîëüêî ïîñëå ýòîãî äåëàåì âèçóàëüíîå ñêðûòèå è çàïóñêàåì àíèìàöèþ
PrepVisualsForAnimation();
int credits = ComWrapper.GetPlayerCredits(playerId);
showAnimationCoroutine = StartCoroutine(ShowElementsSequence(isWin, isBotGame, credits));
}
private void ApplyButtonVisibility(bool isWin, bool isBotGame)
{
// - Åñëè ïîáåäà â PvE: òîëüêî continueButton
// - Åñëè ïîðàæåíèå â PvE èëè PvP: replayButton
// - Ìåíþ: âñåãäà
bool showContinueButton = isBotGame && isWin;
bool showReplayButton = !showContinueButton;
if (replayButton != null) replayButton.gameObject.SetActive(showReplayButton);
if (continueButton != null) continueButton.gameObject.SetActive(showContinueButton);
if (menuButton != null) menuButton.gameObject.SetActive(true);
}
/// <summary>
/// Ïîäãîòîâêà òîëüêî âèçóàëüíîãî ñîñòîÿíèÿ: ïðÿ÷åì àêòèâíûå êíîïêè alpha=0 è óâîäèì âíèç,
/// ïðè ýòîì activeSelf ÍÅ ìåíÿåì.
/// </summary>
private void PrepVisualsForAnimation()
{
CacheButtonPositionsIfNeeded();
// Êàðòèíêè: scale=0
if (firstImage != null) firstImage.transform.localScale = Vector3.zero;
if (secondImage != null) secondImage.transform.localScale = Vector3.zero;
// Êíîïêè: alpha=0 è óâîäèì âíèç (òîëüêî åñëè àêòèâíû)
PrepButtonVisual(replayButton, replayCg, replayButtonOriginalPos);
PrepButtonVisual(continueButton, continueCg, continueButtonOriginalPos);
PrepButtonVisual(menuButton, menuCg, menuButtonOriginalPos);
}
private void CacheButtonPositionsIfNeeded()
{
if (positionsCached) return;
if (replayButton != null)
{
var rt = replayButton.GetComponent<RectTransform>();
if (rt != null) replayButtonOriginalPos = rt.anchoredPosition;
}
if (continueButton != null)
{
var rt = continueButton.GetComponent<RectTransform>();
if (rt != null) continueButtonOriginalPos = rt.anchoredPosition;
}
if (menuButton != null)
{
var rt = menuButton.GetComponent<RectTransform>();
if (rt != null) menuButtonOriginalPos = rt.anchoredPosition;
}
positionsCached = true;
}
private void PrepButtonVisual(Button b, CanvasGroup cg, Vector2 original)
{
if (b == null || cg == null) return;
if (!b.gameObject.activeSelf) return;
cg.alpha = 0f;
var rt = b.GetComponent<RectTransform>();
if (rt != null)
rt.anchoredPosition = new Vector2(original.x, original.y - buttonSlideOffset);
}
private IEnumerator ShowElementsSequence(bool isWin, bool isBotGame, int credits)
{
// 1. Ïåðâàÿ êàðòèíêà
if (firstImage != null)
{
yield return StartCoroutine(PopInElement(firstImage.transform));
yield return new WaitForSeconds(delayBetweenElements);
}
// 2. Âòîðàÿ êàðòèíêà
if (secondImage != null)
{
yield return StartCoroutine(PopInElement(secondImage.transform));
yield return new WaitForSeconds(delayBetweenElements);
}
// 3. Êíîïêà ðåçóëüòàòà
if (isBotGame)
yield return StartCoroutine(ShowBotGameButtonsAnimated(isWin, credits));
else
yield return StartCoroutine(ShowPvPGameButtonsAnimated(credits));
// 4. Ìåíþ
yield return StartCoroutine(ShowMenuButtonAnimated());
// Ìîæíî îñòàâèòü áåç OnPanelChanged — ìû óæå îòïðàâèëè åãî ÄÎ àíèìàöèé.
}
private IEnumerator PopInElement(Transform element)
{
float elapsed = 0f;
Vector3 targetScale = Vector3.one;
while (elapsed < popDuration)
{
elapsed += Time.deltaTime;
float progress = elapsed / popDuration;
float scale;
if (progress < 0.4f)
{
scale = Mathf.Lerp(0f, popScale, progress / 0.4f);
}
else
{
float returnProgress = (progress - 0.4f) / 0.6f;
scale = Mathf.Lerp(popScale, 1f, returnProgress);
}
element.localScale = Vector3.one * scale;
yield return null;
}
element.localScale = targetScale;
}
private IEnumerator SlideInButton(RectTransform rectTransform, Vector2 targetPosition)
{
Vector2 startPosition = rectTransform.anchoredPosition;
float elapsed = 0f;
while (elapsed < buttonSlideDuration)
{
elapsed += Time.deltaTime;
float progress = elapsed / buttonSlideDuration;
float easedProgress = 1f - Mathf.Pow(1f - progress, 3f);
rectTransform.anchoredPosition = Vector2.Lerp(startPosition, targetPosition, easedProgress);
yield return null;
}
rectTransform.anchoredPosition = targetPosition;
}
private IEnumerator FadeIn(CanvasGroup cg)
{
if (cg == null) yield break;
float elapsed = 0f;
while (elapsed < buttonSlideDuration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / buttonSlideDuration);
cg.alpha = t;
yield return null;
}
cg.alpha = 1f;
}
private IEnumerator SlideAndFadeIn(Button b, CanvasGroup cg, Vector2 targetPos)
{
if (b == null || cg == null) yield break;
if (!b.gameObject.activeSelf) yield break;
var rt = b.GetComponent<RectTransform>();
if (rt == null)
{
cg.alpha = 1f;
yield break;
}
// Ïàðàëëåëüíî: slide + fade
Coroutine slide = StartCoroutine(SlideInButton(rt, targetPos));
Coroutine fade = StartCoroutine(FadeIn(cg));
yield return slide;
yield return fade;
}
private IEnumerator ShowBotGameButtonsAnimated(bool isWin, int credits)
{
if (isWin)
{
if (continueButton != null && continueButton.gameObject.activeSelf)
{
continueButton.interactable = true;
yield return StartCoroutine(SlideAndFadeIn(continueButton, continueCg, continueButtonOriginalPos));
}
}
else
{
if (replayButton != null && replayButton.gameObject.activeSelf)
{
replayButton.interactable = credits >= 1;
var txt = replayButton.GetComponentInChildren<TMP_Text>();
if (txt != null) txt.text = "Ïåðåèãðàòü";
yield return StartCoroutine(SlideAndFadeIn(replayButton, replayCg, replayButtonOriginalPos));
}
}
}
private IEnumerator ShowPvPGameButtonsAnimated(int credits)
{
if (replayButton != null && replayButton.gameObject.activeSelf)
{
int oponentId = playerId == 1 ? 2 : 1;
int oponentCredits = ComWrapper.GetPlayerCredits(oponentId);
replayButton.interactable = credits >= 2 || (credits >= 1 && oponentCredits >= 1);
var txt = replayButton.GetComponentInChildren<TMP_Text>();
if (txt != null) txt.text = "Åù¸ ðàç!";
yield return StartCoroutine(SlideAndFadeIn(replayButton, replayCg, replayButtonOriginalPos));
}
}
private IEnumerator ShowMenuButtonAnimated()
{
if (menuButton != null && menuButton.gameObject.activeSelf)
{
// ìåíþ îáû÷íî âñåãäà êëèêàáåëüíî
yield return StartCoroutine(SlideAndFadeIn(menuButton, menuCg, menuButtonOriginalPos));
}
}
public void UpdateButtons()
{
int credits = ComWrapper.GetPlayerCredits(playerId);
int oponentId = playerId == 1 ? 2 : 1;
int oponentCredits = ComWrapper.GetPlayerCredits(oponentId);
if (continueButton != null && continueButton.gameObject.activeSelf)
continueButton.interactable = credits >= 1;
if (replayButton != null && replayButton.gameObject.activeSelf)
{
if (lastIsBotGame)
replayButton.interactable = credits >= 1;
else
replayButton.interactable = credits >= 2 || (credits >= 1 && oponentCredits >= 1);
}
}
}