증거품 UI
This commit is contained in:
@@ -31,6 +31,10 @@ private void Update()
|
||||
// 무장 안 된 순간에는 클릭을 아예 보지 않는다
|
||||
if (!HiddenBranchResolver.Armed) return;
|
||||
|
||||
// 증거품창이 떠 있으면 월드 클릭을 받지 않는다 — 창이 전체 화면 오버레이라서,
|
||||
// 창 위 클릭이 이 존까지 뚫고 들어와 엉뚱한 분기를 여는 것을 막는다
|
||||
if (ItemHud.Instance != null && ItemHud.Instance.IsOpen) return;
|
||||
|
||||
if (Mouse.current == null || !Mouse.current.leftButton.wasPressedThisFrame) return;
|
||||
|
||||
var cam = Camera.main;
|
||||
|
||||
@@ -10,7 +10,10 @@ public class InputManager : MonoBehaviour, GameInput.IPlayerActions
|
||||
|
||||
private GameInput _input;
|
||||
|
||||
public event Action OnDialogNext_Event;
|
||||
public event Action OnDialogNext_Event;
|
||||
public event Action OnEvidence_Event;
|
||||
public event Action OnEvidencePrev_Event;
|
||||
public event Action OnEvidenceNext_Event;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -37,4 +40,22 @@ public void OnDialogNext(InputAction.CallbackContext ctx)
|
||||
if (ctx.phase == InputActionPhase.Started)
|
||||
OnDialogNext_Event?.Invoke();
|
||||
}
|
||||
|
||||
public void OnEvidence(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.phase == InputActionPhase.Started)
|
||||
OnEvidence_Event?.Invoke();
|
||||
}
|
||||
|
||||
public void OnEvidencePrev(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.phase == InputActionPhase.Started)
|
||||
OnEvidencePrev_Event?.Invoke();
|
||||
}
|
||||
|
||||
public void OnEvidenceNext(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.phase == InputActionPhase.Started)
|
||||
OnEvidenceNext_Event?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ private struct InitialAffection
|
||||
"진행도 초기값과 마찬가지로 플레이를 시작한 씬의 값만 적용되고, 씬 전환으로 넘어온 경우엔 무시된다")]
|
||||
[SerializeField] private List<InitialAffection> _initialAffections = new();
|
||||
|
||||
[Tooltip("플레이 시작 시 소지 아이템 — 이 씬만 직접 열어 테스트할 때 앞 과정 없이 증거품을 들고 시작하게. " +
|
||||
"다른 초기값과 마찬가지로 플레이를 시작한 씬의 값만 적용되고, 씬 전환으로 넘어온 경우엔 무시된다. " +
|
||||
"실제 게임에서의 획득은 AddItem(터치존·버튼 UnityEvent 등)으로")]
|
||||
[SerializeField] private List<ItemData> _initialItems = new();
|
||||
|
||||
private StoryState _state = new();
|
||||
|
||||
// 상태가 바뀔 때마다 발행 (호감도 게이지 등 UI 갱신용)
|
||||
@@ -41,6 +46,11 @@ private void Awake()
|
||||
foreach (var init in _initialAffections)
|
||||
if (init.Character != null)
|
||||
_state.Affection[IdOf(init.Character)] = init.Amount;
|
||||
|
||||
// 테스트용 초기 소지 아이템
|
||||
foreach (var item in _initialItems)
|
||||
if (item != null && !_state.Items.Contains(ItemIdOf(item)))
|
||||
_state.Items.Add(ItemIdOf(item));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -100,6 +110,30 @@ public void SetTrigger(string id)
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
// ── 아이템(증거품) ───────────────────────────────────────────
|
||||
public IReadOnlyList<string> ItemIds => _state.Items;
|
||||
|
||||
public bool HasItem(ItemData item) => item != null && _state.Items.Contains(ItemIdOf(item));
|
||||
|
||||
// UnityEvent 연결용 (대화 터치존·월드 버튼 등에서 증거품 획득). 중복 획득은 무시된다.
|
||||
public void AddItem(ItemData item)
|
||||
{
|
||||
if (item == null) return;
|
||||
string id = ItemIdOf(item);
|
||||
if (_state.Items.Contains(id)) return;
|
||||
_state.Items.Add(id);
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public void RemoveItem(ItemData item)
|
||||
{
|
||||
if (item == null || !_state.Items.Remove(ItemIdOf(item))) return;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
// ItemData의 Id를 키로 사용 (비어있으면 에셋 이름) — 캐릭터 IdOf와 같은 규칙
|
||||
private static string ItemIdOf(ItemData i) => string.IsNullOrEmpty(i.Id) ? i.name : i.Id;
|
||||
|
||||
// ── 선택 이력 ────────────────────────────────────────────────
|
||||
public bool HasChosen(string code) => _state.ChosenCodes.Contains(code);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ public class StoryState
|
||||
public readonly HashSet<string> CompletedDialogs = new(); // 완료한 DialogGroup 이름
|
||||
public readonly HashSet<string> ChosenCodes = new(); // 골랐던 선택지 Code
|
||||
public readonly HashSet<string> Triggers = new(); // 켜진 트리거 Id (대화 조건 검사용)
|
||||
public readonly List<string> Items = new(); // 가진 아이템 Id (획득 순서 유지 — 증거품창 표시 순서)
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
@@ -19,6 +20,7 @@ public void Clear()
|
||||
CompletedDialogs.Clear();
|
||||
ChosenCodes.Clear();
|
||||
Triggers.Clear();
|
||||
Items.Clear();
|
||||
}
|
||||
|
||||
// ── JSON 변환 ────────────────────────────────────────────────
|
||||
@@ -32,6 +34,7 @@ private class JsonData
|
||||
public List<string> CompletedDialogs = new();
|
||||
public List<string> ChosenCodes = new();
|
||||
public List<string> Triggers = new();
|
||||
public List<string> Items = new();
|
||||
}
|
||||
|
||||
public string ToJson()
|
||||
@@ -45,6 +48,7 @@ public string ToJson()
|
||||
data.CompletedDialogs.AddRange(CompletedDialogs);
|
||||
data.ChosenCodes.AddRange(ChosenCodes);
|
||||
data.Triggers.AddRange(Triggers);
|
||||
data.Items.AddRange(Items);
|
||||
return JsonUtility.ToJson(data, prettyPrint: true);
|
||||
}
|
||||
|
||||
@@ -60,6 +64,7 @@ public static StoryState FromJson(string json)
|
||||
state.CompletedDialogs.UnionWith(data.CompletedDialogs);
|
||||
state.ChosenCodes.UnionWith(data.ChosenCodes);
|
||||
state.Triggers.UnionWith(data.Triggers ?? new List<string>());
|
||||
state.Items.AddRange(data.Items ?? new List<string>());
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
8
Assets/02_Scripts/_Data/Item.meta
Normal file
8
Assets/02_Scripts/_Data/Item.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d08e6466f285165448cc7a8751239a65
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/02_Scripts/_Data/Item/ItemData.cs
Normal file
22
Assets/02_Scripts/_Data/Item/ItemData.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
// 증거품/아이템 하나 (역전재판의 법정기록 항목).
|
||||
//
|
||||
// Id가 곧 "제시 키"다 — 대화 노드의 HiddenBranch.Key와 같은 값을 쓰면,
|
||||
// 그 노드가 재생되는 동안 증거품창에서 이 아이템을 클릭했을 때 해당 히든 분기가 열린다.
|
||||
// (DialogTouchZone의 부위 키와 완전히 같은 통로를 쓴다)
|
||||
[CreateAssetMenu(menuName = "Item/Item Data")]
|
||||
public class ItemData : ScriptableObject
|
||||
{
|
||||
[Tooltip("고유 Id — 저장 파일과 히든 분기 Key에 쓰인다. 비우면 에셋 이름")]
|
||||
public string Id;
|
||||
|
||||
[Tooltip("증거품창에 표시할 이름")]
|
||||
public string Name;
|
||||
|
||||
[Tooltip("증거품창에 표시할 그림")]
|
||||
public Sprite Icon;
|
||||
|
||||
[Tooltip("증거품창에 표시할 설명")]
|
||||
[TextArea(2, 5)] public string Description;
|
||||
}
|
||||
2
Assets/02_Scripts/_Data/Item/ItemData.cs.meta
Normal file
2
Assets/02_Scripts/_Data/Item/ItemData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70ed680488473ed44ad380007f918f67
|
||||
25
Assets/02_Scripts/_Data/Item/ItemDatabase.cs
Normal file
25
Assets/02_Scripts/_Data/Item/ItemDatabase.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// 게임에 존재하는 모든 아이템의 목록 (StoryDatabase와 같은 "단일 원본" 역할).
|
||||
// 저장 파일에는 Id 문자열만 남으므로, Id → ItemData 복원은 이 에셋이 담당한다.
|
||||
// 게임에 하나만 만들어 ItemHud에 꽂아 쓴다.
|
||||
[CreateAssetMenu(menuName = "Item/Item Database")]
|
||||
public class ItemDatabase : ScriptableObject
|
||||
{
|
||||
[SerializeField] private List<ItemData> _items = new();
|
||||
|
||||
public IReadOnlyList<ItemData> Items => _items;
|
||||
|
||||
public ItemData FindById(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id)) return null;
|
||||
foreach (var item in _items)
|
||||
{
|
||||
if (item == null) continue;
|
||||
string itemId = string.IsNullOrEmpty(item.Id) ? item.name : item.Id;
|
||||
if (itemId == id) return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/_Data/Item/ItemDatabase.cs.meta
Normal file
2
Assets/02_Scripts/_Data/Item/ItemDatabase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6c0a1fdc73b78049aa22e3aa4e84290
|
||||
8
Assets/02_Scripts/_UI/Item.meta
Normal file
8
Assets/02_Scripts/_UI/Item.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c3122efb3a7a304ca03b2bfaa0fad18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
267
Assets/02_Scripts/_UI/Item/ItemHud.cs
Normal file
267
Assets/02_Scripts/_UI/Item/ItemHud.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
// 증거품창 (역전재판의 법정기록). ItemListUI.uxml을 띄우고 가진 아이템을 좌우 화살표로 넘겨 본다.
|
||||
//
|
||||
// 제시(들이대기): 대화 노드가 히든 분기로 무장돼 있는 동안 아이템 그림을 클릭하면
|
||||
// HiddenBranchResolver.Fire(아이템 Id)를 쏜다 — DialogTouchZone의 부위 키와 완전히 같은 통로라서,
|
||||
// 노드에 Key = 아이템 Id 인 히든 분기를 달아두면 그 분기가 열린다. 발동하면 창은 자동으로 닫힌다.
|
||||
// 무장돼 있지 않으면(평소) 클릭해도 아무 일도 없다 — 그냥 열람용 창이다.
|
||||
//
|
||||
// 목록은 StoryManager의 아이템 이력(Id)을 ItemDatabase로 복원해 만든다. 획득 순서 = 표시 순서.
|
||||
[RequireComponent(typeof(PanelRenderer))]
|
||||
public class ItemHud : MonoBehaviour
|
||||
{
|
||||
public static ItemHud Instance { get; private set; }
|
||||
|
||||
[Tooltip("Id → ItemData 복원용 아이템 전체 목록 (게임에 하나)")]
|
||||
[SerializeField] private ItemDatabase _database;
|
||||
|
||||
[Tooltip("증거품이 하나도 없을 때 설명 칸에 표시할 문구")]
|
||||
[SerializeField] private string _emptyText = "가지고 있는 증거품이 없습니다.";
|
||||
|
||||
[Tooltip("제시가 실제로 발동했을 때 호출 (연출·사운드용). 발동하지 않은 클릭에는 불리지 않는다")]
|
||||
[SerializeField] private UnityEvent _onPresented;
|
||||
|
||||
[Header("Slide")]
|
||||
[Tooltip("아이템 전환 슬라이드 전체 시간(초). 0이면 연출 없이 즉시 교체")]
|
||||
[Min(0f)] [SerializeField] private float _slideDuration = 0.16f;
|
||||
|
||||
[Tooltip("슬라이드로 밀려나는 거리(px)")]
|
||||
[Min(0f)] [SerializeField] private float _slideDistance = 500f;
|
||||
|
||||
private PanelRenderer _panelRenderer;
|
||||
private VisualElement _root; // 전체 토글 대상(#Body)
|
||||
private VisualElement _itemNode; // 슬라이드 대상 (.ItemNode — 그림+설명 묶음)
|
||||
private Image _image;
|
||||
private Label _label;
|
||||
|
||||
// Step마다 증가 — 연타하면 진행 중이던 슬라이드가 즉시 물러나고 새 슬라이드가 이어받는다
|
||||
// (Typewriter의 세대 패턴과 동일)
|
||||
private int _slideGen;
|
||||
|
||||
// 같은 버전으로 콜백이 중복 호출될 때 헛일을 막는다 (Unity 권장 패턴)
|
||||
private int _uiVersion = -1;
|
||||
|
||||
// 현재 표시 상태. 리로드로 요소가 새로 만들어져도 이 값으로 복원된다.
|
||||
private bool _visible;
|
||||
private int _index;
|
||||
private readonly List<ItemData> _owned = new();
|
||||
|
||||
// 창이 떠 있는가 (DialogTouchZone이 창 뒤 월드 클릭을 무시하는 데 쓴다)
|
||||
public bool IsOpen => _visible;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this) { Destroy(gameObject); return; }
|
||||
Instance = this;
|
||||
|
||||
_panelRenderer = GetComponent<PanelRenderer>();
|
||||
_panelRenderer.RegisterUIReloadCallback(OnUIReload);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 창이 열려 있는 동안 아이템을 얻으면 목록이 바로 갱신되게
|
||||
if (StoryManager.Instance != null)
|
||||
StoryManager.Instance.Changed += OnStoryChanged;
|
||||
|
||||
// 증거품창 버튼 (Evidence 액션) — 입력 해석은 InputManager가, 여닫는 행동은 창 자신이 맡는다
|
||||
if (InputManager.Instance != null)
|
||||
{
|
||||
InputManager.Instance.OnEvidence_Event += Toggle;
|
||||
InputManager.Instance.OnEvidencePrev_Event += OnPrevPressed;
|
||||
InputManager.Instance.OnEvidenceNext_Event += OnNextPressed;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (StoryManager.Instance != null)
|
||||
StoryManager.Instance.Changed -= OnStoryChanged;
|
||||
if (InputManager.Instance != null)
|
||||
{
|
||||
InputManager.Instance.OnEvidence_Event -= Toggle;
|
||||
InputManager.Instance.OnEvidencePrev_Event -= OnPrevPressed;
|
||||
InputManager.Instance.OnEvidenceNext_Event -= OnNextPressed;
|
||||
}
|
||||
if (_panelRenderer != null)
|
||||
_panelRenderer.UnregisterUIReloadCallback(OnUIReload);
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
// UI가 (재)구성될 때마다 요소를 다시 잡고 클릭 콜백을 걸고 현재 상태를 되돌린다.
|
||||
private void OnUIReload(PanelRenderer panelRenderer, VisualElement root, int version)
|
||||
{
|
||||
if (_uiVersion == version) return;
|
||||
_uiVersion = version;
|
||||
|
||||
_root = root.Q<VisualElement>("Body");
|
||||
_itemNode = root.Q(className: "ItemNode");
|
||||
_image = root.Q<Image>("Image");
|
||||
_label = root.Q<Label>("Label");
|
||||
|
||||
root.Q<Image>("PrevArrow")?.RegisterCallback<ClickEvent>(_ => Step(-1));
|
||||
root.Q<Image>("NextArrow")?.RegisterCallback<ClickEvent>(_ => Step(+1));
|
||||
_image?.RegisterCallback<ClickEvent>(_ => TryPresent());
|
||||
|
||||
ApplyState(); // 첫 호출에선 _visible=false라 숨김 상태로 시작한다
|
||||
}
|
||||
|
||||
// ── 공개 API (버튼 UnityEvent 연결용) ────────────────────────
|
||||
public void Toggle() { if (_visible) Hide(); else Show(); }
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_visible = true;
|
||||
_slideGen++; // 진행 중이던 슬라이드 취소
|
||||
ResetSlideStyle();
|
||||
ApplyState();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
_visible = false;
|
||||
_slideGen++; // 진행 중이던 슬라이드 취소
|
||||
ResetSlideStyle();
|
||||
ApplyState();
|
||||
}
|
||||
|
||||
// ── 내부 ─────────────────────────────────────────────────────
|
||||
private ItemData CurrentItem =>
|
||||
_owned.Count > 0 && _index >= 0 && _index < _owned.Count ? _owned[_index] : null;
|
||||
|
||||
private void Step(int delta)
|
||||
{
|
||||
if (_owned.Count == 0) return;
|
||||
_index = (_index + delta + _owned.Count) % _owned.Count; // 양끝에서 반대편으로 순환
|
||||
|
||||
// 슬라이드 연출: 현재 카드가 진행 방향으로 빠지고 → (빈 순간에 내용 교체) →
|
||||
// 반대쪽에서 새 카드가 들어온다. 연출 불가 조건이면 즉시 교체.
|
||||
if (_itemNode == null || _slideDuration <= 0f || _owned.Count < 2)
|
||||
{
|
||||
ApplyState();
|
||||
return;
|
||||
}
|
||||
_ = SlideSwap(delta, ++_slideGen);
|
||||
}
|
||||
|
||||
// 두 단계 슬라이드. 연타로 세대가 바뀌면 그 자리에서 물러난다 —
|
||||
// 새 Step의 SlideSwap이 리셋부터 다시 시작하므로 상태가 꼬이지 않는다.
|
||||
private async Awaitable SlideSwap(int dir, int gen)
|
||||
{
|
||||
float half = _slideDuration * 0.5f;
|
||||
try
|
||||
{
|
||||
ResetSlideStyle(); // 이전 슬라이드가 중간에 밀려났어도 항상 제자리에서 시작
|
||||
|
||||
// 1단계: 현재 카드가 진행 방향으로 빠지며 사라진다
|
||||
if (!await Animate(0f, -dir * _slideDistance, 1f, 0f, half, gen)) return;
|
||||
|
||||
ApplyState(); // 화면 밖(투명)인 순간 내용 교체
|
||||
|
||||
// 2단계: 새 카드가 반대쪽에서 들어온다
|
||||
if (!await Animate(dir * _slideDistance, 0f, 0f, 1f, half, gen)) return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 오브젝트 파괴/씬 전환 — 조용히 종료
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 내 세대일 때만 제자리로 — 이미 다음 슬라이드가 시작됐다면 그쪽이 처리한다
|
||||
if (gen == _slideGen) ResetSlideStyle();
|
||||
}
|
||||
}
|
||||
|
||||
// fromX→toX(px), fromA→toA(불투명도)로 부드럽게 이동. 세대가 바뀌면 false.
|
||||
private async Awaitable<bool> Animate(float fromX, float toX, float fromA, float toA,
|
||||
float duration, int gen)
|
||||
{
|
||||
float t = 0f;
|
||||
while (t < duration)
|
||||
{
|
||||
if (gen != _slideGen || _itemNode == null) return false;
|
||||
|
||||
t += Time.deltaTime;
|
||||
float k = Mathf.Clamp01(t / duration);
|
||||
float e = k * k * (3f - 2f * k); // SmoothStep — 끝에서 감속해 카드 무게감이 생긴다
|
||||
_itemNode.style.translate = new Translate(Mathf.Lerp(fromX, toX, e), 0f);
|
||||
_itemNode.style.opacity = Mathf.Lerp(fromA, toA, e);
|
||||
|
||||
await Awaitable.NextFrameAsync(destroyCancellationToken);
|
||||
}
|
||||
return gen == _slideGen;
|
||||
}
|
||||
|
||||
private void ResetSlideStyle()
|
||||
{
|
||||
if (_itemNode == null) return;
|
||||
_itemNode.style.translate = new Translate(0f, 0f);
|
||||
_itemNode.style.opacity = 1f;
|
||||
}
|
||||
|
||||
// 키 입력(EvidencePrev/Next) — 창이 떠 있을 때만 반응한다.
|
||||
// 화살표 클릭과 같은 Step을 타므로 마우스·키보드 어느 쪽으로 넘겨도 동작이 같다.
|
||||
private void OnPrevPressed() { if (_visible) Step(-1); }
|
||||
private void OnNextPressed() { if (_visible) Step(+1); }
|
||||
|
||||
// 아이템 그림 클릭 = 제시. 무장된 히든 분기의 Key와 일치(또는 catch-all)할 때만 발동한다.
|
||||
private void TryPresent()
|
||||
{
|
||||
var item = CurrentItem;
|
||||
if (item == null || !HiddenBranchResolver.Armed) return;
|
||||
|
||||
string id = string.IsNullOrEmpty(item.Id) ? item.name : item.Id;
|
||||
if (HiddenBranchResolver.Fire(id))
|
||||
{
|
||||
_onPresented?.Invoke();
|
||||
Hide(); // 발동 성공 — 창을 닫고 대화가 히든 분기로 흘러가게 한다
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStoryChanged()
|
||||
{
|
||||
if (_visible) ApplyState();
|
||||
}
|
||||
|
||||
private void RebuildOwned()
|
||||
{
|
||||
_owned.Clear();
|
||||
var story = StoryManager.Instance;
|
||||
if (story == null || _database == null) return;
|
||||
|
||||
foreach (var id in story.ItemIds)
|
||||
{
|
||||
var item = _database.FindById(id);
|
||||
if (item != null) _owned.Add(item);
|
||||
else Debug.LogWarning($"[ItemHud] ItemDatabase에 없는 아이템 Id: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
// 캐시된 상태를 실제 요소에 반영한다. 요소가 아직 없으면(리로드 콜백 전) 조용히 넘어간다.
|
||||
private void ApplyState()
|
||||
{
|
||||
RebuildOwned();
|
||||
if (_index >= _owned.Count) _index = Mathf.Max(0, _owned.Count - 1);
|
||||
|
||||
var item = CurrentItem;
|
||||
if (_image != null)
|
||||
{
|
||||
_image.sprite = item != null ? item.Icon : null;
|
||||
_image.style.visibility = item != null ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
if (_label != null)
|
||||
{
|
||||
_label.text = item != null
|
||||
? $"<b>{item.Name}</b>\n\n{item.Description}"
|
||||
: _emptyText;
|
||||
}
|
||||
|
||||
if (_root != null)
|
||||
_root.style.display = _visible ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/_UI/Item/ItemHud.cs.meta
Normal file
2
Assets/02_Scripts/_UI/Item/ItemHud.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d73c406f0f990445acb325393d12110
|
||||
Reference in New Issue
Block a user