2026-04-13 스킬,퀵슬롯 시스템 수정중
This commit is contained in:
BIN
Assets/01_Scenes/GameScene.unity
LFS
BIN
Assets/01_Scenes/GameScene.unity
LFS
Binary file not shown.
@@ -43,6 +43,7 @@ public class InputManager : MonoBehaviour
|
||||
public event Action OnKeyDown_DownArrowEvent;
|
||||
public event Action OnKeyDown_EnterEvent;
|
||||
public event Action OnKeyDown_IKeyEvent;
|
||||
public event Action OnKeyDown_KKeyEvent;
|
||||
|
||||
|
||||
|
||||
@@ -94,6 +95,7 @@ public void SetUIInputMap(string mapName)
|
||||
BindActionUI("OnKeyDown_DownArrow", OnKeyDown_DownArrow);
|
||||
BindActionUI("OnKeyDown_Enter", OnKeyDown_Enter);
|
||||
BindActionUI("OnkeyDown_IKey", OnKeyDown_IKey);
|
||||
BindActionUI("OnKeyDown_KKey", OnKeyDown_KKey);
|
||||
|
||||
_uiInputActionMap.Disable();
|
||||
|
||||
@@ -128,6 +130,7 @@ public void SetCharacterInputMap(string mapName)
|
||||
BindActionCharacter("Interaction", OnInteraction);
|
||||
|
||||
BindActionCharacter("OnkeyDown_IKey", OnKeyDown_IKey);
|
||||
BindActionCharacter("OnKeyDown_KKey", OnKeyDown_KKey);
|
||||
|
||||
|
||||
_characterInputActionMap.Disable();
|
||||
@@ -307,5 +310,11 @@ private void OnKeyDown_IKey(InputAction.CallbackContext ctx)
|
||||
if(ctx.started)
|
||||
OnKeyDown_IKeyEvent?.Invoke();
|
||||
}
|
||||
|
||||
private void OnKeyDown_KKey(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.started)
|
||||
OnKeyDown_KKeyEvent?.Invoke();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -385,4 +385,31 @@ public void ItemUse(int slotIndex)
|
||||
}
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
// 퀵슬롯 동기화용: 해당 아이템 데이터의 총 보유량 합산 (0이면 퀵슬롯에서 자동 해제)
|
||||
public int GetTotalStack(Item itemData)
|
||||
{
|
||||
if (itemData == null) return 0;
|
||||
int total = 0;
|
||||
for (int i = 0; i < Items.Length; i++)
|
||||
{
|
||||
if (Items[i] != null && Items[i].Data == itemData)
|
||||
total += Items[i].CurrentStack;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// 퀵슬롯에서 아이템 사용 시 호출: 해당 데이터가 담긴 가장 앞 슬롯을 사용
|
||||
public void UseItemByData(Item itemData)
|
||||
{
|
||||
if (itemData == null) return;
|
||||
for (int i = 0; i < Items.Length; i++)
|
||||
{
|
||||
if (Items[i] != null && Items[i].Data == itemData)
|
||||
{
|
||||
ItemUse(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
|
||||
//UI매핑
|
||||
InputManager.Instance.OnKeyDown_IKeyEvent += GameManager.Instance.InGameUI.InventoryToggle;
|
||||
InputManager.Instance.OnKeyDown_KKeyEvent += GameManager.Instance.InGameUI.SkillWindowToggle;
|
||||
|
||||
//화면 켜기
|
||||
}
|
||||
@@ -204,6 +205,7 @@ private void OnDestroy()
|
||||
if(GameManager.Instance != null)
|
||||
{
|
||||
InputManager.Instance.OnKeyDown_IKeyEvent -= GameManager.Instance.InGameUI.InventoryToggle;
|
||||
InputManager.Instance.OnKeyDown_KKeyEvent -= GameManager.Instance.InGameUI.SkillWindowToggle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ public class InGameUIManager : BaseUIManager
|
||||
public TooltipUI Tooltip;
|
||||
public Transform DragCanvas;
|
||||
public GameObject InventoryRoot;
|
||||
public QuickSlotController QuickSlot;
|
||||
public SkillWindowUI SkillWindow;
|
||||
|
||||
[SerializeField] private GameObject _crosshairRoot;
|
||||
|
||||
@@ -32,6 +34,26 @@ public void InventoryToggle()
|
||||
InventoryOnOff(!InventoryRoot.activeSelf);
|
||||
}
|
||||
|
||||
public void SkillWindowToggle()
|
||||
{
|
||||
if (SkillWindow == null) return;
|
||||
SkillWindow.Toggle();
|
||||
// 인벤토리와 동일한 커서/입력 모드 규칙 적용
|
||||
bool anyOpen = InventoryRoot.activeSelf || SkillWindow.gameObject.activeSelf;
|
||||
if (anyOpen)
|
||||
{
|
||||
InputManager.Instance.ActiveOnlyOneActionMap("InGameUI");
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
InputManager.Instance.ActiveOnlyOneActionMap("Character");
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
Cursor.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void InventoryOnOff(bool isOn)
|
||||
{
|
||||
InventoryRoot.SetActive(isOn);
|
||||
|
||||
@@ -18,6 +18,7 @@ public class SkillModule : MonoBehaviour
|
||||
|
||||
private SkillInstance[] _equippedSkills;
|
||||
private ISkillEffect[] _skillEffects;
|
||||
private SkillData[] _equippedSkillDataCache; // 장착 순서 보존용
|
||||
|
||||
// 차지
|
||||
private int _chargingSlot = -1;
|
||||
@@ -49,13 +50,6 @@ public class SkillModule : MonoBehaviour
|
||||
|
||||
private Dictionary<WeaponType, WeaponSkillSet> _dicSkills = new Dictionary<WeaponType, WeaponSkillSet>();
|
||||
|
||||
// 슬롯 이름 → 런타임 매핑 (Dispatcher 테이블)
|
||||
private Dictionary<string, IUseableRuntime> _skillBindData = new Dictionary<string, IUseableRuntime>();
|
||||
|
||||
// 퀵슬롯에 바인딩할 슬롯 이름 목록 (스킬용)
|
||||
private static readonly string[] SkillSlotNames =
|
||||
{ "UseSlot_Q", "UseSlot_E", "UseSlot_R", "UseSlot_T" };
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_stateMachine = GetComponent<PlayerStateMachine>();
|
||||
@@ -64,6 +58,7 @@ private void Awake()
|
||||
|
||||
_equippedSkills = new SkillInstance[_maxSlots];
|
||||
_skillEffects = new ISkillEffect[_maxSlots];
|
||||
_equippedSkillDataCache = new SkillData[_maxSlots];
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -74,46 +69,17 @@ private void Start()
|
||||
_dicSkills[wss.WeaponType] = wss;
|
||||
}
|
||||
|
||||
// 현재 장착 무기의 스킬셋 로드 (무기 미장착 시 스킬 없음)
|
||||
// 현재 장착 무기의 스킬셋만 "장착 상태"로 로드 (퀵슬롯 자동 바인딩 없음)
|
||||
if (_equippedWeapon != null
|
||||
&& _dicSkills.TryGetValue(_equippedWeapon.WType, out WeaponSkillSet out_wss)
|
||||
&& out_wss != null)
|
||||
{
|
||||
LoadWeaponSkills(out_wss);
|
||||
RegisterSkillsToQuickslot(out_wss);
|
||||
}
|
||||
|
||||
// 각 슬롯에 dispatcher를 한 번만 바인딩 (이후 내용물만 _skillBindData로 교체)
|
||||
foreach (string slotName in SkillSlotNames)
|
||||
{
|
||||
string captured = slotName;
|
||||
GameManager.Instance.Level.BindSlotAction(captured, (state) => DispatchSlot(captured, state));
|
||||
}
|
||||
}
|
||||
|
||||
private void DispatchSlot(string slotName, InputState state)
|
||||
{
|
||||
if (!_skillBindData.TryGetValue(slotName, out IUseableRuntime runtime) || runtime == null)
|
||||
return;
|
||||
|
||||
runtime.Execute(new UseContext
|
||||
{
|
||||
Caster = gameObject,
|
||||
Target = null,
|
||||
UseInputState = state
|
||||
});
|
||||
}
|
||||
|
||||
private void RegisterSkillsToQuickslot(WeaponSkillSet wss)
|
||||
{
|
||||
for (int i = 0; i < SkillSlotNames.Length; i++)
|
||||
{
|
||||
if (i < wss.Skills.Count && wss.Skills[i] != null)
|
||||
_skillBindData[SkillSlotNames[i]] = wss.Skills[i].CreateRuntime();
|
||||
else
|
||||
_skillBindData.Remove(SkillSlotNames[i]);
|
||||
}
|
||||
}
|
||||
// 장착된 스킬 목록 반환 (스킬창 UI에서 사용)
|
||||
public IReadOnlyList<SkillData> GetEquippedSkillDatas() => _equippedSkillDataCache;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
@@ -133,11 +99,13 @@ public void LoadWeaponSkills(WeaponSkillSet skillSet)
|
||||
{
|
||||
_equippedSkills[i] = new SkillInstance(skillSet.Skills[i]);
|
||||
_skillEffects[i] = ResolveEffect(skillSet.Skills[i].TargetType);
|
||||
_equippedSkillDataCache[i] = skillSet.Skills[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
_equippedSkills[i] = null;
|
||||
_skillEffects[i] = null;
|
||||
_equippedSkillDataCache[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d48f60e0be302444809818f411de761
|
||||
guid: 619b9f88d08881b4cb478bfd9f27c22a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
234
Assets/02_Scripts/UI/QuickSlot/QuickSlot.cs
Normal file
234
Assets/02_Scripts/UI/QuickSlot/QuickSlot.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class QuickSlot : MonoBehaviour, IDropHandler, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
[Header("Slot Binding")]
|
||||
public string SlotName; // "UseSlot_Q", "UseSlot_E", ...
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private Image _iconImage;
|
||||
[SerializeField] private TextMeshProUGUI _stackText;
|
||||
|
||||
public UseableEntry CurrentEntry { get; private set; }
|
||||
|
||||
private Transform _dragTransform;
|
||||
private Transform _iconOriginalParent;
|
||||
private CanvasGroup _iconCanvasGroup;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_iconImage != null)
|
||||
{
|
||||
_iconCanvasGroup = _iconImage.GetComponent<CanvasGroup>();
|
||||
if (_iconCanvasGroup == null)
|
||||
_iconCanvasGroup = _iconImage.gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
ClearSlot();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_dragTransform = GameManager.Instance.InGameUI.DragCanvas;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 아이템 퀵슬롯은 인벤토리와 동기화: 스택 수량 갱신 및 소진 시 자동 해제
|
||||
if (CurrentEntry is Item itemData)
|
||||
{
|
||||
int total = GameManager.Instance.Inventory.GetTotalStack(itemData);
|
||||
if (total <= 0)
|
||||
{
|
||||
ClearSlot();
|
||||
return;
|
||||
}
|
||||
if (_stackText != null)
|
||||
{
|
||||
_stackText.text = itemData.IsStackable ? total.ToString() : "";
|
||||
_stackText.enabled = itemData.IsStackable;
|
||||
}
|
||||
}
|
||||
else if (_stackText != null)
|
||||
{
|
||||
_stackText.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEntry(UseableEntry entry)
|
||||
{
|
||||
CurrentEntry = entry;
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
public void ClearSlot()
|
||||
{
|
||||
CurrentEntry = null;
|
||||
if (_iconImage != null)
|
||||
{
|
||||
_iconImage.sprite = null;
|
||||
_iconImage.enabled = false;
|
||||
}
|
||||
if (_stackText != null)
|
||||
{
|
||||
_stackText.text = "";
|
||||
_stackText.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateUI()
|
||||
{
|
||||
if (CurrentEntry == null || CurrentEntry.Icon == null)
|
||||
{
|
||||
if (_iconImage != null) _iconImage.enabled = false;
|
||||
return;
|
||||
}
|
||||
_iconImage.sprite = CurrentEntry.Icon;
|
||||
_iconImage.enabled = true;
|
||||
}
|
||||
|
||||
public void Execute(InputState state)
|
||||
{
|
||||
if (CurrentEntry == null) return;
|
||||
|
||||
if (CurrentEntry is Item itemData)
|
||||
{
|
||||
// 아이템은 누를 때(Started)만 사용
|
||||
if (state == InputState.Started)
|
||||
GameManager.Instance.Inventory.UseItemByData(itemData);
|
||||
}
|
||||
else if (CurrentEntry is SkillData skillData)
|
||||
{
|
||||
// 스킬은 Started/Canceled 모두 전달 (Charge/Channel 지원)
|
||||
var character = GameManager.Instance.Level.CurrentCharacter;
|
||||
if (character == null) return;
|
||||
if (character.TryGetComponent<SkillModule>(out var skillModule))
|
||||
skillModule.SkillInputByData(skillData, state);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
GameObject dropped = eventData.pointerDrag;
|
||||
if (dropped == null) return;
|
||||
|
||||
// 인벤토리에서 드래그
|
||||
InventoryItemControl invItem = dropped.GetComponent<InventoryItemControl>();
|
||||
if (invItem != null && invItem.ParentSlot != null && invItem.ParentSlot.currentItem != null)
|
||||
{
|
||||
SetEntry(invItem.ParentSlot.currentItem.Data);
|
||||
return;
|
||||
}
|
||||
|
||||
// 다른 퀵슬롯에서 드래그 → 스왑
|
||||
QuickSlot otherSlot = dropped.GetComponent<QuickSlot>();
|
||||
if (otherSlot != null && otherSlot != this)
|
||||
{
|
||||
UseableEntry temp = CurrentEntry;
|
||||
SetEntry(otherSlot.CurrentEntry);
|
||||
otherSlot.SetEntry(temp);
|
||||
}
|
||||
|
||||
// 스킬창에서 드래그는 스킬창 제작 시 SkillEntryControl 같은 컴포넌트를 여기서 감지
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button == PointerEventData.InputButton.Right)
|
||||
{
|
||||
ClearSlot();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (CurrentEntry == null || _iconImage == null)
|
||||
{
|
||||
eventData.pointerDrag = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_iconOriginalParent = _iconImage.transform.parent;
|
||||
_iconImage.transform.SetParent(_dragTransform);
|
||||
_iconCanvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (_iconImage == null) return;
|
||||
_iconImage.transform.position = eventData.position;
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
_iconCanvasGroup.blocksRaycasts = true;
|
||||
_iconImage.transform.SetParent(_iconOriginalParent);
|
||||
_iconImage.transform.localPosition = Vector3.zero;
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
변경 요약
|
||||
1. 입력 시스템 (InputManager, LevelManager)
|
||||
추가: OnKeyDown_KKeyEvent 이벤트 + OnKeyDown_KKey 핸들러 → K 키로 스킬창 열기
|
||||
연결: LevelManager에서 K키 → InGameUIManager.SkillWindowToggle에 구독
|
||||
요구사항: Input Action Asset의 Character와 InGameUI 맵 양쪽에 OnKeyDown_KKey 액션 추가 필요
|
||||
2. SkillModule (자동 바인딩 제거)
|
||||
Before: 무기 장착 시 Q/E/R/T가 InputManager에 직접 바인딩 → 누르면 바로 발동
|
||||
After: 무기 장착 시 _equippedSkills만 채움. 키와는 무관. 퀵슬롯에 등록된 스킬만 발동됨
|
||||
|
||||
SkillSlotNames, _skillBindData, DispatchSlot, RegisterSkillsToQuickslot, BindSlotAction 호출 → 삭제
|
||||
_equippedSkillDataCache[] + GetEquippedSkillDatas() → 추가 (스킬창에서 목록 표시용)
|
||||
3. QuickSlot (각 슬롯에 부착)
|
||||
역할: 슬롯 1칸. 스킬이든 아이템이든 UseableEntry 하나를 담음
|
||||
|
||||
SlotName 인스펙터 필드 (UseSlot_Q~UseSlot_G)
|
||||
SetEntry(entry) / ClearSlot() / Execute(state)
|
||||
Execute(): 담긴 게 Item이면 Inventory.UseItemByData(), SkillData면 SkillModule.SkillInputByData()
|
||||
드래그 처리:
|
||||
OnDrop: 인벤토리 아이템 드롭 받으면 등록, 다른 퀵슬롯이면 스왑
|
||||
OnBeginDrag/OnEndDrag: 자기 슬롯 아이콘을 마우스 따라다니게 (인벤토리와 동일)
|
||||
OnPointerClick 우클릭: 해제
|
||||
Update(): 아이템이면 인벤토리 잔여 수량 동기화, 0이면 자동 해제
|
||||
4. QuickSlotController (QuickSlotRoot에 부착)
|
||||
역할: 슬롯들 묶어서 입력 시스템에 일괄 등록
|
||||
|
||||
Awake(): 자식 QuickSlot[] 수집
|
||||
Start(): 각 슬롯의 SlotName으로 LevelManager.BindSlotAction() 호출 → 키 누르면 → slot.Execute(state)
|
||||
RegisterEntry(slotName, entry) / GetSlot(slotName) 외부 API
|
||||
5. InventoryManager (퀵슬롯 동기화 메서드 추가)
|
||||
GetTotalStack(Item): 인벤토리 전체에서 해당 아이템 총 개수 (퀵슬롯 카운트 표시용)
|
||||
UseItemByData(Item): 데이터 기반으로 가장 앞 슬롯의 아이템 사용
|
||||
6. 스킬창 신규
|
||||
SkillEntry: 스킬창 한 줄. IBeginDragHandler/IDragHandler/IEndDragHandler로 드래그 → 마우스 위 퀵슬롯에 SetEntry() 호출. 본체는 항상 제자리 복귀
|
||||
SkillWindowUI: Toggle() 호출되면 활성/비활성 + Refresh()로 SkillModule.GetEquippedSkillDatas() 받아 엔트리 인스턴싱
|
||||
7. InGameUIManager
|
||||
QuickSlot, SkillWindow 참조 필드 추가
|
||||
SkillWindowToggle(): 스킬창 켜고 끄면서 인벤토리와 동일하게 커서/입력맵 토글
|
||||
데이터 흐름
|
||||
키 입력 → 발동
|
||||
|
||||
|
||||
키보드 Q
|
||||
→ InputManager.OnKeyDown_SlotQEvent
|
||||
→ LevelManager.BindSlotAction이 등록한 콜백
|
||||
→ QuickSlot.Execute(state)
|
||||
→ 분기: Item → Inventory.UseItemByData
|
||||
SkillData → SkillModule.SkillInputByData
|
||||
스킬 등록
|
||||
|
||||
|
||||
K키 → SkillWindow 열림 → SkillModule에서 장착 스킬 목록 받아 표시
|
||||
사용자가 SkillEntry 드래그 → QuickSlot 위에서 놓음
|
||||
QuickSlot.SetEntry(skillData) → 아이콘 갱신
|
||||
아이템 등록
|
||||
|
||||
|
||||
인벤토리 슬롯의 InventoryItemControl 드래그
|
||||
QuickSlot.OnDrop → SetEntry(itemData)
|
||||
인벤토리에서 아이템 소진되면 QuickSlot.Update가 감지해서 자동 ClearSlot
|
||||
*/
|
||||
2
Assets/02_Scripts/UI/QuickSlot/QuickSlot.cs.meta
Normal file
2
Assets/02_Scripts/UI/QuickSlot/QuickSlot.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b986e78d40a4ec4ebe640f5dc4defdc
|
||||
41
Assets/02_Scripts/UI/QuickSlot/QuickSlotController.cs
Normal file
41
Assets/02_Scripts/UI/QuickSlot/QuickSlotController.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class QuickSlotController : MonoBehaviour
|
||||
{
|
||||
private QuickSlot[] _slots;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_slots = GetComponentsInChildren<QuickSlot>(true);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
foreach (var slot in _slots)
|
||||
{
|
||||
if (string.IsNullOrEmpty(slot.SlotName)) continue;
|
||||
QuickSlot captured = slot;
|
||||
GameManager.Instance.Level.BindSlotAction(captured.SlotName, (state) => captured.Execute(state));
|
||||
}
|
||||
}
|
||||
|
||||
// 외부(스킬창/SkillModule 등)에서 슬롯에 등록할 때 호출
|
||||
public void RegisterEntry(string slotName, UseableEntry entry)
|
||||
{
|
||||
foreach (var slot in _slots)
|
||||
{
|
||||
if (slot.SlotName == slotName)
|
||||
{
|
||||
slot.SetEntry(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QuickSlot GetSlot(string slotName)
|
||||
{
|
||||
foreach (var slot in _slots)
|
||||
if (slot.SlotName == slotName) return slot;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0150a6644db52824c9b546e9f34c221d
|
||||
8
Assets/02_Scripts/UI/SkillWindow.meta
Normal file
8
Assets/02_Scripts/UI/SkillWindow.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f4e891fc20854a4f9c63c81ade744c6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
77
Assets/02_Scripts/UI/SkillWindow/SkillEntry.cs
Normal file
77
Assets/02_Scripts/UI/SkillWindow/SkillEntry.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class SkillEntry : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
[SerializeField] private Image _iconImage;
|
||||
[SerializeField] private TextMeshProUGUI _nameText;
|
||||
|
||||
public SkillData Data { get; private set; }
|
||||
|
||||
private Transform _dragTransform;
|
||||
private Transform _originalParent;
|
||||
private CanvasGroup _canvasGroup;
|
||||
private Vector3 _originalLocalPos;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (_canvasGroup == null)
|
||||
_canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
public void SetData(SkillData data)
|
||||
{
|
||||
Data = data;
|
||||
if (_iconImage != null)
|
||||
{
|
||||
_iconImage.sprite = data != null ? data.Icon : null;
|
||||
_iconImage.enabled = data != null && data.Icon != null;
|
||||
}
|
||||
if (_nameText != null)
|
||||
_nameText.text = data != null ? data.EntryName : "";
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
eventData.pointerDrag = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_dragTransform = GameManager.Instance.InGameUI.DragCanvas;
|
||||
_originalParent = transform.parent;
|
||||
_originalLocalPos = transform.localPosition;
|
||||
|
||||
transform.SetParent(_dragTransform);
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
transform.position = eventData.position;
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
_canvasGroup.blocksRaycasts = true;
|
||||
|
||||
// 드롭된 오브젝트 판정 — 퀵슬롯이면 등록
|
||||
GameObject hovered = eventData.pointerEnter;
|
||||
if (hovered != null)
|
||||
{
|
||||
QuickSlot slot = hovered.GetComponentInParent<QuickSlot>();
|
||||
if (slot != null && Data != null)
|
||||
{
|
||||
slot.SetEntry(Data);
|
||||
}
|
||||
}
|
||||
|
||||
// 엔트리는 항상 제자리로 복귀 (원본은 목록에 남아있어야 함)
|
||||
transform.SetParent(_originalParent);
|
||||
transform.localPosition = _originalLocalPos;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/SkillWindow/SkillEntry.cs.meta
Normal file
2
Assets/02_Scripts/UI/SkillWindow/SkillEntry.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58eac31de8e96ed4c9a5fa7206bd63f3
|
||||
43
Assets/02_Scripts/UI/SkillWindow/SkillWindowUI.cs
Normal file
43
Assets/02_Scripts/UI/SkillWindow/SkillWindowUI.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class SkillWindowUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform _listContentRoot;
|
||||
[SerializeField] private GameObject _skillEntryPrefab;
|
||||
|
||||
private readonly List<SkillEntry> _entries = new List<SkillEntry>();
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
bool willOpen = !gameObject.activeSelf;
|
||||
gameObject.SetActive(willOpen);
|
||||
if (willOpen) Refresh();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
// 기존 엔트리 정리
|
||||
foreach (Transform child in _listContentRoot)
|
||||
Destroy(child.gameObject);
|
||||
_entries.Clear();
|
||||
|
||||
var character = GameManager.Instance.Level.CurrentCharacter;
|
||||
if (character == null) return;
|
||||
if (!character.TryGetComponent<SkillModule>(out var skillModule)) return;
|
||||
|
||||
var skills = skillModule.GetEquippedSkillDatas();
|
||||
for (int i = 0; i < skills.Count; i++)
|
||||
{
|
||||
if (skills[i] == null) continue;
|
||||
|
||||
GameObject entryObj = Instantiate(_skillEntryPrefab, _listContentRoot);
|
||||
SkillEntry entry = entryObj.GetComponent<SkillEntry>();
|
||||
if (entry != null)
|
||||
{
|
||||
entry.SetData(skills[i]);
|
||||
_entries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/SkillWindow/SkillWindowUI.cs.meta
Normal file
2
Assets/02_Scripts/UI/SkillWindow/SkillWindowUI.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0abbd5b063416be4c97a8429d13b4b53
|
||||
BIN
Assets/06_Skills/SkillEntry.prefab
LFS
Normal file
BIN
Assets/06_Skills/SkillEntry.prefab
LFS
Normal file
Binary file not shown.
7
Assets/06_Skills/SkillEntry.prefab.meta
Normal file
7
Assets/06_Skills/SkillEntry.prefab.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a57c19cd9e3ecf74896f7b8acecb397e
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
8
Assets/09_UI/QuickSlot.meta
Normal file
8
Assets/09_UI/QuickSlot.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21ebb67e7c3b2f048a5c7a9e7ce1f316
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/09_UI/QuickSlot/Textures.meta
Normal file
8
Assets/09_UI/QuickSlot/Textures.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2460735a2f917b4ea9e8fabf3c13c11
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/09_UI/QuickSlot/Textures/QuickSlotFrame.png
LFS
Normal file
BIN
Assets/09_UI/QuickSlot/Textures/QuickSlotFrame.png
LFS
Normal file
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03ab8426faa46574d9c12062b3d31346
|
||||
guid: cd91f749ff3102a47b2298fcc94842ee
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
@@ -37,13 +37,13 @@ TextureImporter:
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
@@ -52,9 +52,9 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
@@ -126,7 +126,7 @@ TextureImporter:
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
8
Assets/09_UI/USS.meta
Normal file
8
Assets/09_UI/USS.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76fe533d2d7faaf4da7df2938cfe6082
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1
Assets/09_UI/USS/dumy.txt
Normal file
1
Assets/09_UI/USS/dumy.txt
Normal file
@@ -0,0 +1 @@
|
||||
dumy
|
||||
7
Assets/09_UI/USS/dumy.txt.meta
Normal file
7
Assets/09_UI/USS/dumy.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81e06520af5e25d429159f94be80f4e0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -195,6 +195,15 @@
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
},
|
||||
{
|
||||
"name": "OnkeyDown_KKey",
|
||||
"type": "Button",
|
||||
"id": "a6472b0c-d4c7-4803-9552-fecd3943fd76",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
@@ -483,6 +492,17 @@
|
||||
"action": "AreaConfirm",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "b09d5552-ab4c-4419-84e7-9c43e4257882",
|
||||
"path": "<Keyboard>/k",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": ";Keyboard&Mouse",
|
||||
"action": "OnkeyDown_KKey",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -575,6 +595,15 @@
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
},
|
||||
{
|
||||
"name": "OnkeyDown_KKey",
|
||||
"type": "Button",
|
||||
"id": "f7547fe4-a5b0-4ce1-80f0-4e7566d0d63d",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
@@ -599,6 +628,17 @@
|
||||
"action": "OnkeyDown_IKey",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "1269f2a1-c0c7-448a-b86d-dfe9eaff82be",
|
||||
"path": "<Keyboard>/k",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": ";Keyboard&Mouse",
|
||||
"action": "OnkeyDown_KKey",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,20 +2,25 @@
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: LiberationSans SDF - Outline
|
||||
m_Shader: {fileID: 4800000, guid: fe393ace9b354375a9cb14cdbbc28be4, type: 3}
|
||||
m_ShaderKeywords: OUTLINE_ON
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- OUTLINE_ON
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 5
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
@@ -32,14 +37,14 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 28684132378477856, guid: 8f586378b4e144a9851e7b34d9b748ee,
|
||||
type: 2}
|
||||
m_Texture: {fileID: 28684132378477856, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OutlineTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _Ambient: 0.5
|
||||
- _Bevel: 0.5
|
||||
@@ -50,6 +55,7 @@ Material:
|
||||
- _BumpFace: 0
|
||||
- _BumpOutline: 0
|
||||
- _ColorMask: 15
|
||||
- _CullMode: 0
|
||||
- _Diffuse: 0.5
|
||||
- _FaceDilate: 0.1
|
||||
- _FaceUVSpeedX: 0
|
||||
@@ -65,7 +71,7 @@ Material:
|
||||
- _OutlineSoftness: 0
|
||||
- _OutlineUVSpeedX: 0
|
||||
- _OutlineUVSpeedY: 0
|
||||
- _OutlineWidth: 0.1
|
||||
- _OutlineWidth: 0.2
|
||||
- _PerspectiveFilter: 0.875
|
||||
- _Reflectivity: 10
|
||||
- _ScaleRatioA: 0.9
|
||||
@@ -102,3 +108,5 @@ Material:
|
||||
- _ReflectOutlineColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _UnderlayColor: {r: 0, g: 0, b: 0, a: 0.5}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
|
||||
8
Assets/UI Toolkit.meta
Normal file
8
Assets/UI Toolkit.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8316ebf745edbc94fae0adea13e80663
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/UI Toolkit/PanelSettings.asset
LFS
Normal file
BIN
Assets/UI Toolkit/PanelSettings.asset
LFS
Normal file
Binary file not shown.
8
Assets/UI Toolkit/PanelSettings.asset.meta
Normal file
8
Assets/UI Toolkit/PanelSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57de9cfa8416f2c4384c3df4f16e6842
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UI Toolkit/UnityThemes.meta
Normal file
8
Assets/UI Toolkit/UnityThemes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c46d93b9044f8147a6bb1354fc8bfb8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
@import url("unity-theme://default");
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a12877faeb0c804b920c4d5f71e466a
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
unsupportedSelectorAction: 0
|
||||
Reference in New Issue
Block a user