2026.06.24
This commit is contained in:
@@ -4,12 +4,19 @@
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public enum InventorySlotClickMode
|
||||
{
|
||||
None,
|
||||
ShowDetail,
|
||||
RequestUse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 인벤토리 슬롯 하나를 담당하는 UI 스크립트입니다.
|
||||
/// FishSlot, CompassSlot, TrashSlot, BottleSlot 등에 각각 붙입니다.
|
||||
/// VR 포인터 Hover/Select, NEW 배지, 0개 흐림 표시, 중요 아이템 강조, 상세보기/사용 클릭을 지원합니다.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class InventorySlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler
|
||||
public class InventorySlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler, ISelectHandler, IDeselectHandler, ISubmitHandler
|
||||
{
|
||||
[Header("Item")]
|
||||
[SerializeField] private InventoryItemType itemType;
|
||||
@@ -20,30 +27,75 @@ public class InventorySlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExit
|
||||
[SerializeField] private TMP_Text countText;
|
||||
[SerializeField] private GameObject newBadge;
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private GameObject importantGlowObject;
|
||||
[SerializeField] private GameObject filteredOutOverlay;
|
||||
|
||||
[Header("Tooltip")]
|
||||
[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<CanvasGroup>();
|
||||
|
||||
if (slotBackground == null)
|
||||
slotBackground = GetComponent<Image>();
|
||||
|
||||
if (inventoryUI == null)
|
||||
inventoryUI = GetComponentInParent<InventoryUI>();
|
||||
|
||||
if (tooltipUI == null)
|
||||
tooltipUI = GetComponentInParent<InventoryTooltipUI>();
|
||||
|
||||
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)
|
||||
@@ -51,10 +103,52 @@ 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();
|
||||
|
||||
@@ -80,6 +174,23 @@ public void SetSlotBackground(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)
|
||||
@@ -106,7 +217,7 @@ public void HideNewBadge()
|
||||
private IEnumerator NewBadgeRoutine()
|
||||
{
|
||||
newBadge.SetActive(true);
|
||||
yield return new WaitForSeconds(newBadgeShowTime);
|
||||
yield return new WaitForSecondsRealtime(newBadgeShowTime);
|
||||
newBadge.SetActive(false);
|
||||
newBadgeRoutine = null;
|
||||
}
|
||||
@@ -116,39 +227,108 @@ private void UpdateVisualState()
|
||||
bool hasItem = currentCount > 0;
|
||||
|
||||
if (countText != null)
|
||||
countText.text = $"x{currentCount}";
|
||||
{
|
||||
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)
|
||||
canvasGroup.alpha = hasItem ? ownedAlpha : zeroAlpha;
|
||||
{
|
||||
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<InventoryUI>();
|
||||
|
||||
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<InventoryTooltipUI>();
|
||||
|
||||
if (tooltipUI != null)
|
||||
tooltipUI.ShowTooltip(itemType, currentCount);
|
||||
tooltipUI.ShowTooltip(itemType, currentCount, currentMaxCount);
|
||||
}
|
||||
|
||||
public void HideTooltip()
|
||||
|
||||
Reference in New Issue
Block a user