[Abnormality] 이상 상태 시스템 구현
- 이상 상태 데이터 (버프/디버프) ScriptableObject 정의 - 런타임임 활성 이상 상태 관리 (ActiveAbnormality) - 캐릭터터별 AbnormalityManager 컴포넌트로 이상 상태 적용/제거 - 스킬 효과(AbnormalityEffect)로 스킬에 이상 상태 연동 - UI 슬롯 및 목록 표시 구현 (버프/디버프 구분) - 테스트 코드 및 씬 설정 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
182
Assets/Scripts/UI/AbnormalitySlotUI.cs
Normal file
182
Assets/Scripts/UI/AbnormalitySlotUI.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using Colosseum.Abnormalities;
|
||||
|
||||
namespace Colosseum.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 개별 이상 상태 UI 슬롯
|
||||
/// 버프/디버프 아이콘, 지속 시간 등을 표시합니다.
|
||||
/// </summary>
|
||||
public class AbnormalitySlotUI : MonoBehaviour
|
||||
{
|
||||
[Header("UI References")]
|
||||
[Tooltip("이상 상태 아이콘")]
|
||||
[SerializeField] private Image iconImage;
|
||||
|
||||
[Tooltip("지속 시간 채우기 이미지 (시계 방향)")]
|
||||
[SerializeField] private Image durationFill;
|
||||
|
||||
[Tooltip("남은 시간 텍스트")]
|
||||
[SerializeField] private TMP_Text durationText;
|
||||
|
||||
[Tooltip("효과 이름 텍스트")]
|
||||
[SerializeField] private TMP_Text effectNameText;
|
||||
|
||||
[Tooltip("배경 이미지 (버프/디버프 구분용)")]
|
||||
[SerializeField] private Image backgroundImage;
|
||||
|
||||
[Header("Colors")]
|
||||
[Tooltip("버프 배경 색상")]
|
||||
[SerializeField] private Color buffColor = new Color(0.2f, 0.6f, 0.2f, 0.8f);
|
||||
|
||||
[Tooltip("디버프 배경 색상")]
|
||||
[SerializeField] private Color debuffColor = new Color(0.6f, 0.2f, 0.2f, 0.8f);
|
||||
|
||||
private ActiveAbnormality trackedAbnormality;
|
||||
|
||||
/// <summary>
|
||||
/// 추적 중인 활성 이상 상태
|
||||
/// </summary>
|
||||
public ActiveAbnormality TrackedAbnormality => trackedAbnormality;
|
||||
|
||||
/// <summary>
|
||||
/// UI 초기화
|
||||
/// </summary>
|
||||
/// <param name="abnormality">표시할 활성 이상 상태</param>
|
||||
public void Initialize(ActiveAbnormality abnormality)
|
||||
{
|
||||
trackedAbnormality = abnormality;
|
||||
|
||||
if (abnormality?.Data == null)
|
||||
{
|
||||
Debug.LogWarning("[AbnormalitySlotUI] Initialize called with null abnormality or data");
|
||||
return;
|
||||
}
|
||||
|
||||
// 아이콘 설정
|
||||
if (iconImage != null)
|
||||
{
|
||||
iconImage.sprite = abnormality.Data.icon;
|
||||
iconImage.enabled = abnormality.Data.icon != null;
|
||||
}
|
||||
|
||||
// 이름 설정
|
||||
if (effectNameText != null)
|
||||
{
|
||||
effectNameText.text = abnormality.Data.abnormalityName;
|
||||
}
|
||||
|
||||
// 배경 색상 설정 (버프/디버프 구분)
|
||||
if (backgroundImage != null)
|
||||
{
|
||||
backgroundImage.color = abnormality.Data.isDebuff ? debuffColor : buffColor;
|
||||
}
|
||||
|
||||
// 초기 상태 업데이트
|
||||
UpdateDisplay(abnormality.RemainingDuration, abnormality.Data.duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 화면 표시 업데이트
|
||||
/// </summary>
|
||||
/// <param name="remainingDuration">남은 시간</param>
|
||||
/// <param name="totalDuration">전체 시간</param>
|
||||
public void UpdateDisplay(float remainingDuration, float totalDuration)
|
||||
{
|
||||
// 지속 시간 채우기 업데이트
|
||||
if (durationFill != null)
|
||||
{
|
||||
if (totalDuration > 0f)
|
||||
{
|
||||
float fillAmount = Mathf.Clamp01(remainingDuration / totalDuration);
|
||||
durationFill.fillAmount = fillAmount;
|
||||
durationFill.enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 영구 효과
|
||||
durationFill.fillAmount = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
// 남은 시간 텍스트 업데이트
|
||||
if (durationText != null)
|
||||
{
|
||||
if (totalDuration > 0f)
|
||||
{
|
||||
if (remainingDuration >= 60f)
|
||||
{
|
||||
durationText.text = $"{remainingDuration / 60f:F0}m";
|
||||
}
|
||||
else if (remainingDuration >= 1f)
|
||||
{
|
||||
durationText.text = $"{remainingDuration:F0}s";
|
||||
}
|
||||
else
|
||||
{
|
||||
durationText.text = $"{remainingDuration:F1}s";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 영구 효과
|
||||
durationText.text = "∞";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 프레임마다 호출하여 추적 중인 효과 업데이트
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (trackedAbnormality == null)
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateDisplay(trackedAbnormality.RemainingDuration, trackedAbnormality.Data.duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 툴팁 표시용 정보 반환
|
||||
/// </summary>
|
||||
public string GetTooltipText()
|
||||
{
|
||||
if (trackedAbnormality?.Data == null) return string.Empty;
|
||||
|
||||
var data = trackedAbnormality.Data;
|
||||
string tooltip = $"<b>{data.abnormalityName}</b>\n";
|
||||
|
||||
if (!data.IsPermanent)
|
||||
{
|
||||
tooltip += $"지속 시간: {trackedAbnormality.RemainingDuration:F1}초\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltip += "영구 효과\n";
|
||||
}
|
||||
|
||||
if (data.HasPeriodicEffect)
|
||||
{
|
||||
tooltip += $"주기적 효과: {data.periodicValue:+0}/ {data.periodicInterval}초\n";
|
||||
}
|
||||
|
||||
if (data.HasControlEffect)
|
||||
{
|
||||
tooltip += $"제어 효과: {data.controlType}\n";
|
||||
}
|
||||
|
||||
foreach (var mod in data.statModifiers)
|
||||
{
|
||||
string sign = mod.value >= 0 ? "+" : "";
|
||||
tooltip += $"{mod.statType}: {sign}{mod.value}\n";
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user