2026-05-20 무기슬롯
This commit is contained in:
64
Assets/02_Scripts/UI/WeaponInventory.cs
Normal file
64
Assets/02_Scripts/UI/WeaponInventory.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// ============================================================================
|
||||
// WeaponInventory (UI)
|
||||
// ----------------------------------------------------------------------------
|
||||
// 무기 인벤토리 화면 표시 — 표시 전용 (무기 교체는 1/2/3 키로).
|
||||
//
|
||||
// 이 클래스는 무기 목록을 "소유하지 않는다". 데이터의 단일 진실은
|
||||
// PlayerWeaponInventory이고, 이 UI는 그걸 구독해서 그림만 그린다.
|
||||
// - OnInventoryChanged 이벤트를 받으면 슬롯을 다시 그림
|
||||
// - 현재 장착 무기 슬롯에 하이라이트 표시
|
||||
//
|
||||
// _slots는 데이터가 아니라 생성한 화면 오브젝트 캐시일 뿐 (재사용 풀).
|
||||
// ============================================================================
|
||||
public class WeaponInventory : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private PlayerWeaponInventory _wInvenSource; // 비워두면 런타임에 자동 탐색
|
||||
[SerializeField] private Transform _slotRoot; // 슬롯이 생성될 부모
|
||||
[SerializeField] private WeaponSlot _slotPrefab; // 슬롯 프리팹
|
||||
|
||||
// 생성된 슬롯 UI 캐시. 무기 수가 늘면 추가 생성하고, 남는 슬롯은 비활성화.
|
||||
private readonly List<WeaponSlot> _slots = new();
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (_wInvenSource == null)
|
||||
_wInvenSource = FindFirstObjectByType<PlayerWeaponInventory>();
|
||||
|
||||
if (_wInvenSource != null)
|
||||
_wInvenSource.OnInventoryChanged += Refresh;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_wInvenSource != null)
|
||||
_wInvenSource.OnInventoryChanged -= Refresh;
|
||||
}
|
||||
|
||||
|
||||
// 인벤토리 상태를 화면에 반영. 슬롯 개수를 무기 수에 맞추고 내용/하이라이트 갱신.
|
||||
private void Refresh()
|
||||
{
|
||||
if (_wInvenSource == null || _slotRoot == null || _slotPrefab == null) return;
|
||||
|
||||
IReadOnlyList<WeaponData> weapons = _wInvenSource.Weapons;
|
||||
|
||||
// 슬롯이 모자라면 생성 (한 번 만든 슬롯은 재사용 — GC 최소화).
|
||||
while (_slots.Count < weapons.Count)
|
||||
_slots.Add(Instantiate(_slotPrefab, _slotRoot));
|
||||
|
||||
for (int i = 0; i < _slots.Count; i++)
|
||||
{
|
||||
bool used = i < weapons.Count;
|
||||
_slots[i].gameObject.SetActive(used);
|
||||
if (!used) continue;
|
||||
|
||||
_slots[i].SetWeapon(weapons[i]);
|
||||
_slots[i].SetSelected(i == _wInvenSource.CurrentIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/WeaponInventory.cs.meta
Normal file
2
Assets/02_Scripts/UI/WeaponInventory.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51f5c684956d6ea46baf42375e6f186a
|
||||
61
Assets/02_Scripts/UI/WeaponSlot.cs
Normal file
61
Assets/02_Scripts/UI/WeaponSlot.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
// ============================================================================
|
||||
// WeaponSlot
|
||||
// ----------------------------------------------------------------------------
|
||||
// 무기 인벤토리 UI의 슬롯 한 칸. 데이터는 들고 있지 않고 표시만 한다.
|
||||
// WeaponInventory가 슬롯을 생성/갱신할 때 SetWeapon / SetSelected를 호출한다.
|
||||
// ============================================================================
|
||||
public class WeaponSlot : MonoBehaviour
|
||||
{
|
||||
[Header("Ref")]
|
||||
[SerializeField] public Image Weapon_Img; // 무기 아이콘
|
||||
[SerializeField] public TMP_Text Weapon_Name; // 무기 이름
|
||||
[SerializeField] private GameObject _slotPosObj; // 장착 중일 때 위치를 밀어줄 대상
|
||||
[SerializeField] private float _selectedOffsetX = -100f; // 장착 시 _slotPosObj를 x로 미는 양 (음수 = 왼쪽)
|
||||
|
||||
// _slotPosObj의 기준 위치. 최초 SetSelected 호출 시 한 번만 캡처해서 이동 누적 방지.
|
||||
private RectTransform _slotPosRect;
|
||||
private Vector2 _slotPosBase;
|
||||
private bool _slotPosCaptured;
|
||||
|
||||
// 슬롯에 표시할 무기를 채운다. null이면 빈 슬롯으로 표현.
|
||||
public void SetWeapon(WeaponData weapon)
|
||||
{
|
||||
if (Weapon_Img != null)
|
||||
{
|
||||
Weapon_Img.sprite = weapon != null ? weapon.PickupSprite : null;
|
||||
// 스프라이트가 없으면 아이콘 자체를 숨겨 빈 칸이 깨져 보이지 않게 한다.
|
||||
Weapon_Img.enabled = weapon != null && weapon.PickupSprite != null;
|
||||
}
|
||||
|
||||
if (Weapon_Name != null)
|
||||
Weapon_Name.text = weapon != null ? weapon.DisplayName : string.Empty;
|
||||
}
|
||||
|
||||
// 현재 장착 중인 무기 슬롯이면 _slotPosObj를 x로 _selectedOffsetX만큼 밀어준다.
|
||||
// 해제되면 기준 위치로 복귀. 기준 위치는 처음 한 번만 캡처해서 이동이 누적되지 않게 한다.
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
CaptureSlotPosBase();
|
||||
if (_slotPosRect == null) return;
|
||||
|
||||
Vector2 pos = _slotPosBase;
|
||||
pos.x += selected ? _selectedOffsetX : 0f;
|
||||
_slotPosRect.anchoredPosition = pos;
|
||||
}
|
||||
|
||||
// _slotPosObj의 기준 anchoredPosition을 최초 1회 저장 (오프셋 적용 전 값).
|
||||
private void CaptureSlotPosBase()
|
||||
{
|
||||
if (_slotPosCaptured) return;
|
||||
_slotPosCaptured = true;
|
||||
|
||||
if (_slotPosObj != null)
|
||||
_slotPosRect = _slotPosObj.transform as RectTransform;
|
||||
if (_slotPosRect != null)
|
||||
_slotPosBase = _slotPosRect.anchoredPosition;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/WeaponSlot.cs.meta
Normal file
2
Assets/02_Scripts/UI/WeaponSlot.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4f30534edb02d346b4f6c570709313d
|
||||
Reference in New Issue
Block a user