using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public enum InventorySlotClickMode
{
None,
ShowDetail,
RequestUse
}
///
/// 인벤토리 슬롯 하나를 담당하는 UI 스크립트입니다.
/// VR 포인터 Hover/Select, NEW 배지, 0개 흐림 표시, 중요 아이템 강조, 상세보기/사용 클릭을 지원합니다.
///
[DisallowMultipleComponent]
public class InventorySlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler, ISelectHandler, IDeselectHandler, ISubmitHandler
{
[Header("Item")]
[SerializeField] private InventoryItemType itemType;
[Header("UI References")]
[SerializeField] private Image slotBackground;
[SerializeField] private Image itemIcon;
[SerializeField] private TMP_Text countText;
[SerializeField] private GameObject newBadge;
[SerializeField] private CanvasGroup canvasGroup;
[SerializeField] private GameObject importantGlowObject;
[SerializeField] private GameObject filteredOutOverlay;
[Header("Tooltip / Parent UI")]
[SerializeField] private InventoryTooltipUI tooltipUI;
[SerializeField] private InventoryUI inventoryUI;
[Header("Click")]
[SerializeField] private InventorySlotClickMode clickMode = InventorySlotClickMode.ShowDetail;
[Header("Settings")]
[Tooltip("VR에서는 false 권장. 슬롯이 사라지면 Ray 조작 위치가 바뀌어 불편할 수 있습니다.")]
[SerializeField] private bool hideWhenZero = false;
[SerializeField] private bool dimWhenZero = true;
[SerializeField] private float zeroAlpha = 0.35f;
[SerializeField] private float ownedAlpha = 1f;
[SerializeField] private float filteredAlpha = 0.15f;
[SerializeField] private bool showCountWhenZero = true;
[SerializeField] private bool showMaxCount = false;
[SerializeField] private float newBadgeShowTime = 1.2f;
[Header("Hover Effect")]
[SerializeField] private bool useHoverScale = true;
[SerializeField] private float hoverScale = 1.08f;
[SerializeField] private bool bringToFrontOnHover = true;
private int currentCount;
private int currentMaxCount;
private bool filteredOut;
private Coroutine newBadgeRoutine;
private Vector3 originalScale;
private InventoryItemDefinition definition;
public InventoryItemType ItemType => itemType;
public int CurrentCount => currentCount;
public InventoryItemCategory Category => definition != null ? definition.category : InventoryItemCategory.Other;
private void Awake()
{
originalScale = transform.localScale;
if (canvasGroup == null)
canvasGroup = GetComponent();
if (slotBackground == null)
slotBackground = GetComponent();
if (inventoryUI == null)
inventoryUI = GetComponentInParent();
if (tooltipUI == null)
tooltipUI = GetComponentInParent();
if (newBadge != null)
newBadge.SetActive(false);
UpdateVisualState();
}
private void OnDisable()
{
HideNewBadge();
HideTooltip();
ResetHoverVisual();
}
public void SetInventoryUI(InventoryUI ui)
{
inventoryUI = ui;
}
public void SetItemType(InventoryItemType newItemType)
{
itemType = newItemType;
}
public void SetDefinition(InventoryItemDefinition newDefinition)
{
definition = newDefinition;
if (definition == null)
{
UpdateVisualState();
return;
}
if (itemIcon != null)
{
itemIcon.sprite = definition.icon;
itemIcon.enabled = definition.icon != null;
}
if (slotBackground != null && definition.slotBackground != null)
{
slotBackground.sprite = definition.slotBackground;
slotBackground.enabled = true;
}
if (definition.overrideSlotDisplaySettings)
{
hideWhenZero = definition.hideWhenZero;
dimWhenZero = definition.dimWhenZero;
zeroAlpha = definition.zeroAlpha;
ownedAlpha = definition.ownedAlpha;
}
if (importantGlowObject != null)
importantGlowObject.SetActive(definition.importantItem);
UpdateVisualState();
}
public void SetCount(int count, bool showNewBadge)
{
SetCount(count, showNewBadge, currentMaxCount);
}
public void SetCount(int count, bool showNewBadge, int maxCount)
{
int previousCount = currentCount;
currentCount = Mathf.Max(0, count);
currentMaxCount = Mathf.Max(0, maxCount);
UpdateVisualState();
if (showNewBadge && currentCount > previousCount)
ShowNewBadge();
}
public void SetIcon(Sprite sprite)
{
if (itemIcon == null)
return;
itemIcon.sprite = sprite;
itemIcon.enabled = sprite != null;
}
public void SetSlotBackground(Sprite sprite)
{
if (slotBackground == null)
return;
slotBackground.sprite = sprite;
slotBackground.enabled = sprite != null;
}
public void SetFilteredOut(bool value)
{
filteredOut = value;
if (filteredOutOverlay != null)
filteredOutOverlay.SetActive(value);
UpdateVisualState();
}
public void SetHoverSettings(bool useScale, float scale, bool bringToFront)
{
useHoverScale = useScale;
hoverScale = Mathf.Max(1f, scale);
bringToFrontOnHover = bringToFront;
}
public void ShowNewBadge()
{
if (newBadge == null)
return;
if (newBadgeRoutine != null)
StopCoroutine(newBadgeRoutine);
newBadgeRoutine = StartCoroutine(NewBadgeRoutine());
}
public void HideNewBadge()
{
if (newBadgeRoutine != null)
{
StopCoroutine(newBadgeRoutine);
newBadgeRoutine = null;
}
if (newBadge != null)
newBadge.SetActive(false);
}
private IEnumerator NewBadgeRoutine()
{
newBadge.SetActive(true);
yield return new WaitForSecondsRealtime(newBadgeShowTime);
newBadge.SetActive(false);
newBadgeRoutine = null;
}
private void UpdateVisualState()
{
bool hasItem = currentCount > 0;
if (countText != null)
{
if (!showCountWhenZero && currentCount <= 0)
countText.text = string.Empty;
else if (showMaxCount && currentMaxCount > 0)
countText.text = $"x{currentCount}/{currentMaxCount}";
else
countText.text = $"x{currentCount}";
}
if (hideWhenZero)
gameObject.SetActive(hasItem);
if (canvasGroup != null && dimWhenZero)
{
float targetAlpha = hasItem ? ownedAlpha : zeroAlpha;
if (filteredOut)
targetAlpha = Mathf.Min(targetAlpha, filteredAlpha);
canvasGroup.alpha = targetAlpha;
canvasGroup.interactable = !filteredOut;
canvasGroup.blocksRaycasts = !filteredOut;
}
}
public void OnPointerEnter(PointerEventData eventData)
{
ApplyHoverVisual();
ShowTooltip();
}
public void OnPointerExit(PointerEventData eventData)
{
ResetHoverVisual();
HideTooltip();
}
public void OnPointerClick(PointerEventData eventData)
{
ActivateSlot();
}
public void OnSelect(BaseEventData eventData)
{
ApplyHoverVisual();
ShowTooltip();
}
public void OnDeselect(BaseEventData eventData)
{
ResetHoverVisual();
HideTooltip();
}
public void OnSubmit(BaseEventData eventData)
{
ActivateSlot();
}
private void ActivateSlot()
{
if (filteredOut)
return;
if (inventoryUI == null)
inventoryUI = GetComponentInParent();
if (inventoryUI == null)
return;
switch (clickMode)
{
case InventorySlotClickMode.ShowDetail:
inventoryUI.ShowItemDetail(itemType);
break;
case InventorySlotClickMode.RequestUse:
inventoryUI.RequestUseItem(itemType, 1);
break;
}
}
private void ApplyHoverVisual()
{
if (bringToFrontOnHover)
transform.SetAsLastSibling();
if (useHoverScale)
transform.localScale = originalScale * hoverScale;
}
private void ResetHoverVisual()
{
if (useHoverScale)
transform.localScale = originalScale;
}
public void ShowTooltip()
{
if (tooltipUI == null)
tooltipUI = GetComponentInParent();
if (tooltipUI != null)
tooltipUI.ShowTooltip(itemType, currentCount, currentMaxCount);
}
public void HideTooltip()
{
if (tooltipUI != null)
tooltipUI.HideTooltip();
}
}