2026.06.24
This commit is contained in:
@@ -2,32 +2,77 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class MemoryProgressPopupUI : MonoBehaviour
|
||||
{
|
||||
[Header("Panel")]
|
||||
[Tooltip("실제로 켜고 끌 팝업 패널입니다. 가능하면 이 스크립트는 항상 켜진 MemoryPopupController에 붙이고, 이 필드에 MemoryPopupPanel을 연결하세요.")]
|
||||
[SerializeField] private GameObject popupPanel;
|
||||
[SerializeField] private CanvasGroup popupCanvasGroup;
|
||||
[Tooltip("체크하면 팝업이 끝난 뒤 Popup Panel을 비활성화합니다. 단, Popup Panel이 이 스크립트 오브젝트와 같으면 자동으로 비활성화하지 않습니다.")]
|
||||
[SerializeField] private bool deactivatePanelAfterHide = true;
|
||||
|
||||
[Header("Text")]
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
[SerializeField] private TMP_Text countText;
|
||||
[SerializeField] private TMP_Text addedAmountText;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private string message = "기억의 조각을 얻었다!";
|
||||
[Header("Popup Visual Objects")]
|
||||
[Tooltip("팝업 안의 소켓 이미지입니다. 보통 항상 켜도 됩니다.")]
|
||||
[SerializeField] private GameObject popupCrystalSocket;
|
||||
[Tooltip("팝업 안의 파란 기억 조각 이미지입니다.")]
|
||||
[SerializeField] private GameObject popupCrystalIcon;
|
||||
[Tooltip("팝업 안의 정적 Glow 이미지입니다. 애니메이션 없이 ON/OFF만 합니다.")]
|
||||
[SerializeField] private GameObject popupGlowIcon;
|
||||
[Tooltip("팝업이 표시될 때 Glow를 켭니다.")]
|
||||
[SerializeField] private bool showPopupGlow = true;
|
||||
[Tooltip("체크하면 마지막 조각 획득으로 완료됐을 때만 Popup Glow를 켭니다.")]
|
||||
[SerializeField] private bool showPopupGlowOnlyWhenCompleted = false;
|
||||
|
||||
[Header("Messages")]
|
||||
[SerializeField] private string message = "기억의 조각 획득!";
|
||||
[SerializeField] private string completedMessage = "모든 기억의 조각을 모았습니다!";
|
||||
[SerializeField] private bool useCompletedMessage = true;
|
||||
|
||||
[Header("Added Amount")]
|
||||
[SerializeField] private string addedAmountFormat = "+{0}";
|
||||
[SerializeField] private bool showCompletedTextWhenCompleted = true;
|
||||
[SerializeField] private string completedAddedAmountText = "완료";
|
||||
|
||||
[Header("Timing")]
|
||||
[Tooltip("팝업이 표시되는 시간입니다. 페이드 애니메이션은 제거했고, 이 시간 후 즉시 숨깁니다.")]
|
||||
[SerializeField] private float showTime = 1.5f;
|
||||
[SerializeField] private bool autoHide = true;
|
||||
[SerializeField] private bool useUnscaledTime = false;
|
||||
|
||||
private Coroutine popupRoutine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoFillReferencesIfNeeded();
|
||||
HidePopup();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (popupRoutine != null)
|
||||
{
|
||||
StopCoroutine(popupRoutine);
|
||||
popupRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowPopup(int current, int max)
|
||||
{
|
||||
if (popupRoutine != null)
|
||||
StopCoroutine(popupRoutine);
|
||||
ShowPopupInternal(0, current, max, false);
|
||||
}
|
||||
|
||||
popupRoutine = StartCoroutine(PopupRoutine(current, max));
|
||||
public void ShowPieceAdded(int addedAmount, int current, int max)
|
||||
{
|
||||
if (addedAmount <= 0)
|
||||
return;
|
||||
|
||||
ShowPopupInternal(addedAmount, current, max, true);
|
||||
}
|
||||
|
||||
public void HidePopup()
|
||||
@@ -38,26 +83,157 @@ public void HidePopup()
|
||||
popupRoutine = null;
|
||||
}
|
||||
|
||||
if (popupPanel != null)
|
||||
SetCanvasVisible(false);
|
||||
ApplyPopupObjects(false, false);
|
||||
|
||||
if (ShouldDeactivatePanel() && popupPanel != null)
|
||||
popupPanel.SetActive(false);
|
||||
}
|
||||
|
||||
private IEnumerator PopupRoutine(int current, int max)
|
||||
private void ShowPopupInternal(int addedAmount, int current, int max, bool showAddedAmount)
|
||||
{
|
||||
AutoFillReferencesIfNeeded();
|
||||
|
||||
if (!gameObject.activeInHierarchy)
|
||||
{
|
||||
Debug.LogWarning("[MemoryProgressPopupUI] 스크립트 오브젝트가 비활성화되어 팝업을 표시할 수 없습니다. 항상 켜져 있는 MemoryPopupController 오브젝트에 붙이세요.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (popupRoutine != null)
|
||||
StopCoroutine(popupRoutine);
|
||||
|
||||
ShowPopupNow(addedAmount, current, max, showAddedAmount);
|
||||
|
||||
if (autoHide)
|
||||
popupRoutine = StartCoroutine(AutoHideRoutine());
|
||||
}
|
||||
|
||||
private void ShowPopupNow(int addedAmount, int current, int max, bool showAddedAmount)
|
||||
{
|
||||
bool completed = max > 0 && current >= max;
|
||||
|
||||
if (popupPanel != null)
|
||||
popupPanel.SetActive(true);
|
||||
|
||||
ApplyPopupObjects(true, completed);
|
||||
ApplyTexts(addedAmount, current, max, showAddedAmount, completed);
|
||||
SetCanvasVisible(true);
|
||||
}
|
||||
|
||||
private IEnumerator AutoHideRoutine()
|
||||
{
|
||||
yield return Wait(showTime);
|
||||
HidePopup();
|
||||
}
|
||||
|
||||
private void ApplyTexts(int addedAmount, int current, int max, bool showAddedAmount, bool completed)
|
||||
{
|
||||
if (titleText != null)
|
||||
titleText.text = message;
|
||||
{
|
||||
if (completed && useCompletedMessage)
|
||||
titleText.text = completedMessage;
|
||||
else
|
||||
titleText.text = message;
|
||||
}
|
||||
|
||||
if (countText != null)
|
||||
countText.text = $"{current} / {max}";
|
||||
|
||||
yield return new WaitForSeconds(showTime);
|
||||
if (addedAmountText != null)
|
||||
{
|
||||
bool showText = showAddedAmount || (completed && showCompletedTextWhenCompleted);
|
||||
addedAmountText.gameObject.SetActive(showText);
|
||||
|
||||
if (popupPanel != null)
|
||||
popupPanel.SetActive(false);
|
||||
|
||||
popupRoutine = null;
|
||||
if (showText)
|
||||
{
|
||||
if (completed && showCompletedTextWhenCompleted)
|
||||
addedAmountText.text = completedAddedAmountText;
|
||||
else
|
||||
addedAmountText.text = SafeFormatAddedAmount(addedAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyPopupObjects(bool visible, bool completed)
|
||||
{
|
||||
if (popupCrystalSocket != null)
|
||||
popupCrystalSocket.SetActive(visible);
|
||||
|
||||
if (popupCrystalIcon != null)
|
||||
popupCrystalIcon.SetActive(visible);
|
||||
|
||||
if (popupGlowIcon != null)
|
||||
{
|
||||
bool glowVisible = visible && showPopupGlow && (!showPopupGlowOnlyWhenCompleted || completed);
|
||||
popupGlowIcon.SetActive(glowVisible);
|
||||
}
|
||||
}
|
||||
|
||||
private string SafeFormatAddedAmount(int addedAmount)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(addedAmountFormat, addedAmount);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.LogWarning("[MemoryProgressPopupUI] Added Amount Format이 잘못되어 기본 형식 '+{0}'을 사용합니다.", this);
|
||||
return $"+{addedAmount}";
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoFillReferencesIfNeeded()
|
||||
{
|
||||
if (popupPanel == null)
|
||||
popupPanel = gameObject;
|
||||
|
||||
if (popupCanvasGroup == null)
|
||||
{
|
||||
if (popupPanel != null)
|
||||
popupCanvasGroup = popupPanel.GetComponent<CanvasGroup>();
|
||||
|
||||
if (popupCanvasGroup == null)
|
||||
popupCanvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldDeactivatePanel()
|
||||
{
|
||||
if (!deactivatePanelAfterHide)
|
||||
return false;
|
||||
|
||||
if (popupPanel == null)
|
||||
return false;
|
||||
|
||||
return popupPanel != gameObject;
|
||||
}
|
||||
|
||||
private void SetCanvasVisible(bool visible)
|
||||
{
|
||||
if (popupCanvasGroup == null)
|
||||
return;
|
||||
|
||||
popupCanvasGroup.alpha = visible ? 1f : 0f;
|
||||
popupCanvasGroup.interactable = visible;
|
||||
popupCanvasGroup.blocksRaycasts = visible;
|
||||
}
|
||||
|
||||
private IEnumerator Wait(float duration)
|
||||
{
|
||||
if (duration <= 0f)
|
||||
yield break;
|
||||
|
||||
if (useUnscaledTime)
|
||||
yield return new WaitForSecondsRealtime(duration);
|
||||
else
|
||||
yield return new WaitForSeconds(duration);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
showTime = Mathf.Max(0f, showTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user