using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 using TMPro; // 텍스트메쉬프로를 사용할거에요 -> TMPro를 using UnityEngine.UI; // UI 기능을 사용할거에요 -> UnityEngine.UI를 using System.Collections.Generic; // 리스트를 사용할거에요 -> System.Collections.Generic을 public class CardUI : MonoBehaviour // 클래스를 선언할거에요 -> 카드 UI를 { [SerializeField] private TextMeshProUGUI effectText; // 변수를 선언할거에요 -> 효과 텍스트를 [SerializeField] private Image iconImage; // 변수를 선언할거에요 -> 아이콘 이미지를 [SerializeField] private Outline selectionOutline; // 변수를 선언할거에요 -> 선택 테두리를 private CardData cardData; // 변수를 선언할거에요 -> 카드 데이터를 private LevelUpUIManager uiManager; // 변수를 선언할거에요 -> UI 매니저를 // [FIX] 3개 능력치 저장용 리스트 private List rolledStats = new List(); // 리스트를 선언할거에요 -> 뽑힌 스탯 타입들을 private List rolledValues = new List(); // 리스트를 선언할거에요 -> 뽑힌 수치들을 private bool isRandomCard = false; // 변수를 초기화할거에요 -> 랜덤 카드 여부를 public void Setup(CardData data, LevelUpUIManager manager, StatType mainStat = StatType.Health) // 함수를 선언할거에요 -> 카드를 설정하는 Setup을 (mainStat = 이 카드의 메인 버프 스탯) { cardData = data; // 값을 저장할거에요 -> 카드 데이터를 uiManager = manager; // 값을 저장할거에요 -> 매니저를 if (selectionOutline != null) selectionOutline.enabled = false; // 꺼줄거에요 -> 테두리를 // 아이콘 설정 if (iconImage != null && cardData.icon != null) // 조건이 맞으면 실행할거에요 -> 아이콘이 있다면 iconImage.sprite = cardData.icon; // 설정할거에요 -> 아이콘을 RandomStatCardData randomData = cardData as RandomStatCardData; // 형변환할거에요 -> 랜덤 카드 데이터로 if (randomData != null) // 조건이 맞으면 실행할거에요 -> 랜덤 카드라면 { isRandomCard = true; // 상태를 바꿀거에요 -> 랜덤 카드로 RollAllStats(randomData, mainStat); // 실행할거에요 -> 메인 스탯 지정해서 3개 능력치 뽑기를 } else // 조건이 틀리면 실행할거에요 -> 일반 카드라면 { effectText.text = cardData.GetText(); // 텍스트를 설정할거에요 -> 기본 텍스트를 } } /// /// [FIX] possibleStats의 모든 스탯을 중복 없이 뽑아서 표시 /// 첫 번째 스탯은 양수(버프), 나머지는 음수(디버프) /// private void RollAllStats(RandomStatCardData randomData, StatType mainStat) // 함수를 선언할거에요 -> 메인 스탯 지정해서 3개 능력치를 뽑는 RollAllStats를 { rolledStats.Clear(); // 비울거에요 -> 이전 데이터를 rolledValues.Clear(); // 비울거에요 -> 이전 데이터를 // ① 메인 스탯 (버프) 먼저 고정 int mainValue = Random.Range( // 뽑을거에요 -> 양수 버프 수치를 Mathf.Max(1, randomData.minValue), // 최솟값을 1 이상으로 보장 Mathf.Max(2, randomData.maxValue) + 1 // 최댓값 + 1 (상한 미포함) ); rolledStats.Add(mainStat); // 추가할거에요 -> 메인 스탯을 첫 번째로 rolledValues.Add(mainValue); // 추가할거에요 -> 버프 수치를 // ② 나머지 스탯들 (디버프) — mainStat 제외하고 추가 List otherStats = new List(); // 리스트를 만들거에요 -> 나머지 스탯을 foreach (StatType s in System.Enum.GetValues(typeof(StatType))) // 반복할거에요 -> 모든 StatType을 { if (s != mainStat) otherStats.Add(s); // 추가할거에요 -> 메인 스탯이 아닌 것만 } ShuffleList(otherStats); // 섞을거에요 -> 디버프 순서를 랜덤으로 foreach (StatType s in otherStats) // 반복할거에요 -> 나머지 스탯들을 { int debuffValue = Random.Range( // 뽑을거에요 -> 음수 디버프 수치를 Mathf.Min(-1, -randomData.maxValue), // 최솟값 (음수) 0 // 상한 0 (미포함 → 항상 음수) ); rolledStats.Add(s); // 추가할거에요 -> 디버프 스탯을 rolledValues.Add(debuffValue); // 추가할거에요 -> 디버프 수치를 } // ③ 텍스트 조합 — 3줄 표시 string display = ""; // 초기화할거에요 -> 표시 텍스트를 for (int i = 0; i < rolledStats.Count; i++) // 반복할거에요 -> 모든 스탯에 대해 { int val = rolledValues[i]; // 가져올거에요 -> 수치를 string sign = val >= 0 ? "+" : ""; // 결정할거에요 -> 부호를 string colorTag = val >= 0 ? "" : ""; // 결정할거에요 -> 버프=초록, 디버프=빨강 string statName = GetStatDisplayName(rolledStats[i]); // 가져올거에요 -> 스탯 표시명을 display += $"{colorTag}{statName} {sign}{val}"; // 추가할거에요 -> 한 줄을 if (i < rolledStats.Count - 1) display += "\n"; // 추가할거에요 -> 줄바꿈을 (마지막 제외) } effectText.text = display; // 설정할거에요 -> 완성된 텍스트를 } /// /// 스탯 타입을 표시용 이름으로 변환 /// private string GetStatDisplayName(StatType stat) // 함수를 선언할거에요 -> 스탯 표시명을 반환하는 { switch (stat) // 분기할거에요 -> 스탯 타입에 따라 { case StatType.Health: return "Health"; // 반환할거에요 -> Health를 case StatType.Speed: return "Speed"; // 반환할거에요 -> Speed를 case StatType.Damage: return "Damage"; // 반환할거에요 -> Damage를 default: return stat.ToString(); // 반환할거에요 -> 기본 이름을 } } /// /// 리스트를 랜덤으로 섞기 (Fisher-Yates 셔플) /// private void ShuffleList(List list) // 함수를 선언할거에요 -> 리스트를 셔플하는 { for (int i = list.Count - 1; i > 0; i--) // 반복할거에요 -> 뒤에서부터 { int j = Random.Range(0, i + 1); // 뽑을거에요 -> 랜덤 인덱스를 T temp = list[i]; // 임시 저장할거에요 -> 현재 값을 list[i] = list[j]; // 교체할거에요 -> i와 j를 list[j] = temp; // 교체할거에요 -> j에 임시값을 } } // 카드 클릭 시 매니저에게 알림 public void OnClick() // 함수를 선언할거에요 -> 클릭 처리를 { uiManager.OnCardClick(this); // 알릴거에요 -> 매니저에게 } // 선택 시 하이라이트 public void SetSelected(bool isSelected) // 함수를 선언할거에요 -> 선택 상태를 { if (selectionOutline != null) selectionOutline.enabled = isSelected; // 설정할거에요 -> 테두리를 transform.localScale = isSelected ? Vector3.one * 1.05f : Vector3.one; // 크기를 조절할거에요 -> 선택되면 키우기 } // [FIX] APPLY 버튼 누를 때 3개 능력치 전부 적용 public void ApplyCurrentEffect() // 함수를 선언할거에요 -> 효과를 적용하는 ApplyCurrentEffect를 { if (isRandomCard) // 조건이 맞으면 실행할거에요 -> 랜덤 카드라면 { RandomStatCardData rd = cardData as RandomStatCardData; // 형변환할거에요 -> 랜덤 카드로 for (int i = 0; i < rolledStats.Count; i++) // 반복할거에요 -> 모든 뽑힌 스탯에 대해 { rd.ApplyToPlayer(rolledStats[i], rolledValues[i]); // 적용할거에요 -> 각 스탯과 수치를 } } else // 조건이 틀리면 실행할거에요 -> 일반 카드라면 { cardData.Execute(); // 실행할거에요 -> 기본 효과를 } FindObjectOfType()?.RefreshHealthUI(); // 실행할거에요 -> 체력 UI 갱신을 } }