[UI] 스킬 퀵슬롯 UI 구현
- SkillSlotUI: 개별 슬롯 (아이콘, 쿨다운 오버레이, 텍스트) - SkillQuickSlotUI: 6개 슬롯 관리 및 PlayerSkillInput 연동 - Animator 제어 문제 해결: 수동 SetActive로 쿨다운 표시 - UI_Bar에 PlayerHUD, StatBar 컴포넌트 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
175
Assets/Scripts/UI/SkillSlotUI.cs
Normal file
175
Assets/Scripts/UI/SkillSlotUI.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using Colosseum.Skills;
|
||||
|
||||
namespace Colosseum.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 개별 스킬 슬롯 UI
|
||||
/// </summary>
|
||||
public class SkillSlotUI : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Image iconImage;
|
||||
[SerializeField] private Image cooldownOverlay;
|
||||
[SerializeField] private TMP_Text cooldownText;
|
||||
[SerializeField] private TMP_Text keybindText;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private Color availableColor = Color.white;
|
||||
[SerializeField] private Color cooldownColor = new Color(0.2f, 0.2f, 0.2f, 0.9f);
|
||||
[SerializeField] private Color noManaColor = new Color(0.5f, 0.2f, 0.2f, 0.8f);
|
||||
|
||||
private SkillData skill;
|
||||
private int slotIndex;
|
||||
private bool useIconForCooldown = false;
|
||||
private Animator cooldownAnimator; // 쿨다운 오버레이를 제어하는 Animator
|
||||
private GameObject cooldownContainer; // 쿨다운 오버레이의 부모 GameObject (Cooldown)
|
||||
|
||||
public int SlotIndex => slotIndex;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (cooldownOverlay == null)
|
||||
{
|
||||
useIconForCooldown = true;
|
||||
}
|
||||
else if (cooldownOverlay.type != Image.Type.Filled)
|
||||
{
|
||||
useIconForCooldown = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 쿨다운 오버레이의 상위 GameObject에 있는 Animator 찾기
|
||||
// 구조: CooldownItem (Animator) -> Cooldown -> SPR_Cooldown (Image)
|
||||
cooldownAnimator = cooldownOverlay.GetComponentInParent<Animator>();
|
||||
|
||||
// Animator가 Cooldown GameObject를 제어하므로
|
||||
// 쿨다운 표시를 위해 Animator를 비활성화하고 수동으로 제어
|
||||
if (cooldownAnimator != null)
|
||||
{
|
||||
cooldownAnimator.enabled = false;
|
||||
|
||||
// Animator가 제어하던 Cooldown GameObject 찾기
|
||||
// SPR_Cooldown의 부모가 Cooldown
|
||||
cooldownContainer = cooldownOverlay.transform.parent?.gameObject;
|
||||
}
|
||||
|
||||
// 쿨다운 오버레이 초기화
|
||||
cooldownOverlay.fillAmount = 0f;
|
||||
cooldownOverlay.enabled = false;
|
||||
|
||||
// Cooldown 컨테이너 비활성화
|
||||
if (cooldownContainer != null)
|
||||
{
|
||||
cooldownContainer.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(int index, SkillData skillData, string keyLabel)
|
||||
{
|
||||
slotIndex = index;
|
||||
skill = skillData;
|
||||
|
||||
if (keybindText != null)
|
||||
keybindText.text = keyLabel;
|
||||
|
||||
if (skill != null && iconImage != null)
|
||||
{
|
||||
iconImage.sprite = skill.Icon;
|
||||
iconImage.enabled = true;
|
||||
iconImage.color = availableColor;
|
||||
}
|
||||
else if (iconImage != null)
|
||||
{
|
||||
iconImage.enabled = false;
|
||||
}
|
||||
|
||||
Debug.Log($"[SkillSlotUI] Init slot {index}: skill={skillData?.SkillName}, useIcon={useIconForCooldown}");
|
||||
}
|
||||
|
||||
public void UpdateState(float cooldownRemaining, float cooldownTotal, bool hasEnoughMana)
|
||||
{
|
||||
if (skill == null)
|
||||
{
|
||||
if (cooldownContainer != null) cooldownContainer.SetActive(false);
|
||||
if (cooldownOverlay != null) cooldownOverlay.enabled = false;
|
||||
if (cooldownText != null) cooldownText.text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (cooldownRemaining > 0f)
|
||||
{
|
||||
float ratio = cooldownRemaining / cooldownTotal;
|
||||
|
||||
if (useIconForCooldown && iconImage != null)
|
||||
{
|
||||
// 아이콘 색상으로 쿨다운 표시
|
||||
float brightness = Mathf.Lerp(0.3f, 1f, 1f - ratio);
|
||||
iconImage.color = new Color(brightness, brightness, brightness, 1f);
|
||||
}
|
||||
else if (cooldownOverlay != null)
|
||||
{
|
||||
// Cooldown 컨테이너 활성화
|
||||
if (cooldownContainer != null && !cooldownContainer.activeSelf)
|
||||
{
|
||||
cooldownContainer.SetActive(true);
|
||||
}
|
||||
|
||||
// Image 컴포넌트 활성화
|
||||
cooldownOverlay.enabled = true;
|
||||
cooldownOverlay.fillAmount = ratio;
|
||||
}
|
||||
|
||||
if (cooldownText != null)
|
||||
{
|
||||
cooldownText.text = cooldownRemaining < 1f
|
||||
? $"{cooldownRemaining:F1}"
|
||||
: $"{Mathf.CeilToInt(cooldownRemaining)}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 쿨다운 완료
|
||||
if (useIconForCooldown && iconImage != null)
|
||||
{
|
||||
iconImage.color = hasEnoughMana ? availableColor : noManaColor;
|
||||
}
|
||||
else if (cooldownOverlay != null)
|
||||
{
|
||||
// Image 컴포넌트 비활성화
|
||||
cooldownOverlay.enabled = false;
|
||||
|
||||
// Cooldown 컨테이너 비활성화
|
||||
if (cooldownContainer != null)
|
||||
{
|
||||
cooldownContainer.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (cooldownText != null)
|
||||
{
|
||||
cooldownText.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSkill(SkillData skillData)
|
||||
{
|
||||
skill = skillData;
|
||||
|
||||
if (skill != null && iconImage != null)
|
||||
{
|
||||
iconImage.sprite = skill.Icon;
|
||||
iconImage.enabled = true;
|
||||
iconImage.color = availableColor;
|
||||
}
|
||||
else if (iconImage != null)
|
||||
{
|
||||
iconImage.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user