387 lines
13 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|