183 lines
5.5 KiB
C#
183 lines
5.5 KiB
C#
using UnityEngine;
|
|
using DG.Tweening;
|
|
using Ashwild.Player;
|
|
|
|
namespace Ashwild.Inventory
|
|
{
|
|
public class HotbarUI : MonoBehaviour
|
|
{
|
|
[Header("References")]
|
|
[SerializeField] private SlotUI[] hotbarSlot;
|
|
[SerializeField] private CanvasGroup canvasGroup;
|
|
|
|
[Header("Animation")]
|
|
[SerializeField] private float idleScale = 0.7f;
|
|
[SerializeField] private float activeScale = 1f;
|
|
[SerializeField] private float idleAlpha = 0.5f;
|
|
[SerializeField] private float activeAlpha = 1f;
|
|
[SerializeField] private float zoomInDuration = 0.15f;
|
|
[SerializeField] private float zoomOutDuration = 0.4f;
|
|
[SerializeField] private float activeHoldDuration = 1.5f;
|
|
[SerializeField] private Ease zoomInEase = Ease.OutBack;
|
|
[SerializeField] private Ease zoomOutEase = Ease.InQuad;
|
|
|
|
[Header("Context Menu")]
|
|
[SerializeField] private SlotContextMenu contextMenu;
|
|
|
|
private PlayerInventory inventory;
|
|
private Tweener scaleTween;
|
|
private Tweener alphaTween;
|
|
private float zoomOutTimer;
|
|
private bool inventoryLocked;
|
|
private bool bound;
|
|
|
|
/// <summary>
|
|
/// Waits for the networked local player to spawn before binding to its inventory.
|
|
/// </summary>
|
|
private void OnEnable()
|
|
{
|
|
PlayerEvents.LocalPlayerSpawned += HandleLocalPlayerSpawned;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribes — mirrors OnEnable exactly.
|
|
/// </summary>
|
|
private void OnDisable()
|
|
{
|
|
PlayerEvents.LocalPlayerSpawned -= HandleLocalPlayerSpawned;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
// Visual setup that does not need the player.
|
|
for (int i = 0; i < hotbarSlot.Length; i++)
|
|
hotbarSlot[i].Initialize(i, InventoryUI.OnSwapRequested, OnSlotClicked);
|
|
|
|
transform.localScale = Vector3.one * idleScale;
|
|
if (canvasGroup != null)
|
|
canvasGroup.alpha = idleAlpha;
|
|
|
|
// The player may already exist (late UI init); otherwise we wait for the spawn event.
|
|
if (PlayerInventory.Instance != null)
|
|
BindToInventory();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Binds to the inventory as soon as the local player has spawned on the network.
|
|
/// </summary>
|
|
private void HandleLocalPlayerSpawned() => BindToInventory();
|
|
|
|
/// <summary>
|
|
/// Hooks the hotbar UI onto the local player's inventory; safe to call more than once.
|
|
/// </summary>
|
|
private void BindToInventory()
|
|
{
|
|
if (bound) return;
|
|
inventory = PlayerInventory.Instance;
|
|
if (inventory == null) return;
|
|
bound = true;
|
|
|
|
inventory.onSlotChanged.AddListener(OnSlotChanged);
|
|
inventory.onSelectedSlotChanged.AddListener(OnSelectedSlotChanged);
|
|
|
|
RefreshAll();
|
|
UpdateSelection(inventory.SelectedHotbarIndex);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
scaleTween?.Kill();
|
|
alphaTween?.Kill();
|
|
|
|
if (inventory != null)
|
|
{
|
|
inventory.onSlotChanged.RemoveListener(OnSlotChanged);
|
|
inventory.onSelectedSlotChanged.RemoveListener(OnSelectedSlotChanged);
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (inventoryLocked || zoomOutTimer <= 0f) return;
|
|
|
|
zoomOutTimer -= Time.deltaTime;
|
|
if (zoomOutTimer <= 0f)
|
|
ZoomOut();
|
|
}
|
|
|
|
private void OnSelectedSlotChanged(int selectedIndex)
|
|
{
|
|
UpdateSelection(selectedIndex);
|
|
ZoomIn();
|
|
}
|
|
|
|
private void ZoomIn()
|
|
{
|
|
zoomOutTimer = activeHoldDuration;
|
|
|
|
scaleTween?.Kill();
|
|
scaleTween = transform.DOScale(activeScale, zoomInDuration).SetEase(zoomInEase);
|
|
|
|
if (canvasGroup != null)
|
|
{
|
|
alphaTween?.Kill();
|
|
alphaTween = canvasGroup.DOFade(activeAlpha, zoomInDuration);
|
|
}
|
|
}
|
|
|
|
private void ZoomOut()
|
|
{
|
|
scaleTween?.Kill();
|
|
scaleTween = transform.DOScale(idleScale, zoomOutDuration).SetEase(zoomOutEase);
|
|
|
|
if (canvasGroup != null)
|
|
{
|
|
alphaTween?.Kill();
|
|
alphaTween = canvasGroup.DOFade(idleAlpha, zoomOutDuration);
|
|
}
|
|
}
|
|
|
|
public void OnInventoryOpen()
|
|
{
|
|
inventoryLocked = true;
|
|
zoomOutTimer = 0f;
|
|
ZoomIn();
|
|
}
|
|
|
|
public void OnInventoryClose()
|
|
{
|
|
inventoryLocked = false;
|
|
ZoomOut();
|
|
}
|
|
|
|
private void OnSlotClicked(int index, bool rightClick)
|
|
{
|
|
if (rightClick && PlayerEvents.IsInventoryOpen)
|
|
{
|
|
if (contextMenu != null)
|
|
contextMenu.Show(index);
|
|
else
|
|
inventory.UseItem(index);
|
|
}
|
|
}
|
|
|
|
private void OnSlotChanged(int index)
|
|
{
|
|
if (index >= 0 && index < hotbarSlot.Length)
|
|
hotbarSlot[index].UpdateVisual(inventory.GetSlot(index));
|
|
}
|
|
|
|
private void UpdateSelection(int selectedIndex)
|
|
{
|
|
for (int i = 0; i < hotbarSlot.Length; i++)
|
|
hotbarSlot[i].SetSelected(i == selectedIndex);
|
|
}
|
|
|
|
private void RefreshAll()
|
|
{
|
|
for (int i = 0; i < hotbarSlot.Length; i++)
|
|
hotbarSlot[i].UpdateVisual(inventory.GetSlot(i));
|
|
}
|
|
}
|
|
}
|