diff --git a/Assets/Data/UI/ui_theme.csv b/Assets/Data/UI/ui_theme.csv index f8bf22da..3bef4ecf 100644 --- a/Assets/Data/UI/ui_theme.csv +++ b/Assets/Data/UI/ui_theme.csv @@ -300,7 +300,7 @@ icon,lv_badge_s,IconMisc/Icon_Badge03_Blue.png,,,,,,작은 레벨 배지(카드) color,band_top,,,,,,#5461FF,목록형 상단 띠(재화 바 뒤 · 설계서 §2-2 B) color,card_bottom,,,,,,#1B1A1FE6,영웅 카드 이름 띠 color,card_border,,,,,,#000000,영웅 카드 테두리 -color,card_empty,,,,,,#303146,빈·미보유 카드 +color,card_empty,,,,,,#2E2F43,빈·미보유 카드(레퍼런스 실측) color,card_empty_pattern,,,,,,#2D2F42,빈·미보유 카드 문양 color,card_empty_border,,,,,,#1A1B27,빈·미보유 카드 테두리 color,card_dim,,,,,,#000000A0,미보유 초상 어둡게 @@ -370,4 +370,11 @@ color,arena_2,,,,,,#F1424B,연무장 카드 투기장 color,arena_3,,,,,,#FF9712,연무장 카드 적장 토벌 color,arena_glow,,,,,,#FFFFFF59,연무장 카드 빛(흰 35 %) color,arena_inner,,,,,,#14182E8C,연무장 카드 글자 판(어둡게 55 %) +skin,oblique,Frame/PanelFrame03_Oblique.png,,1,,,,헤더 오른쪽 사선 칸(틴트) +icon,arrow_down,IconMisc/Icon_Arrow_Down.png,,,,,,드롭다운 화살표 +icon,lv_badge_max,IconMisc/Icon_Badge03_Yellow.png,,,,,,최고 레벨 배지(카드) +color,list_bg,,,,,,#34374F,목록 화면 바탕(영웅 목록 · 레퍼런스 = 팩 Collection 실측) +color,oblique,,,,,,#D8E8FF,헤더 사선 칸 +color,count_text,,,,,,#1E1E2A,사선 칸 수량 글자 +color,card_empty_face,,,,,,#262739,빈 카드 얼굴 실루엣 font,title,Assets/UI/GUIPro/ResourcesData/Fonts/Sen-ExtraBold.ttf,,,,,,제목·숫자(라틴 Sen · 한글 = 폴백 Malgun Gothic · PD 결정 전) diff --git a/Assets/Resources/UI/UITheme.asset b/Assets/Resources/UI/UITheme.asset index 183e1c60..de6c1d52 100644 --- a/Assets/Resources/UI/UITheme.asset +++ b/Assets/Resources/UI/UITheme.asset @@ -328,7 +328,7 @@ MonoBehaviour: - id: card_border color: {r: 0, g: 0, b: 0, a: 1} - id: card_empty - color: {r: 0.1882353, g: 0.19215687, b: 0.27450982, a: 1} + color: {r: 0.18039216, g: 0.18431373, b: 0.2627451, a: 1} - id: card_empty_pattern color: {r: 0.1764706, g: 0.18431373, b: 0.25882354, a: 1} - id: card_empty_border @@ -451,6 +451,14 @@ MonoBehaviour: color: {r: 1, g: 1, b: 1, a: 0.34901962} - id: arena_inner color: {r: 0.078431375, g: 0.09411765, b: 0.18039216, a: 0.54901963} + - id: list_bg + color: {r: 0.20392157, g: 0.21568628, b: 0.30980393, a: 1} + - id: oblique + color: {r: 0.84705883, g: 0.9098039, b: 1, a: 1} + - id: count_text + color: {r: 0.11764706, g: 0.11764706, b: 0.16470589, a: 1} + - id: card_empty_face + color: {r: 0.14901961, g: 0.15294118, b: 0.22352941, a: 1} skins: - id: card pack: {fileID: 21300000, guid: 3070a6f23e6ca4273897acf1b7e8c5ce, type: 3} @@ -1005,6 +1013,13 @@ MonoBehaviour: ppu: 1.7 inset: {x: 0, y: 0, z: 0, w: 0} overlayAlpha: 1 + - id: oblique + pack: {fileID: 21300000, guid: ab3a1764a033d4c09a5892a64ddc8c78, type: 3} + samguk: {fileID: 0} + overlay: {fileID: 0} + ppu: 1 + inset: {x: 0, y: 0, z: 0, w: 0} + overlayAlpha: 1 icons: - id: cur_gold pack: {fileID: 21300000, guid: 6d5687fb0dd3a428d9cd26a6f36c6d78, type: 3} @@ -1298,6 +1313,14 @@ MonoBehaviour: pack: {fileID: 21300000, guid: 64a42696c813049fd9c00923ae5842df, type: 3} samguk: {fileID: 0} tint: {r: 1, g: 1, b: 1, a: 1} + - id: arrow_down + pack: {fileID: 21300000, guid: 9987152c36a3b4365ba46f7be2a44777, type: 3} + samguk: {fileID: 0} + tint: {r: 1, g: 1, b: 1, a: 1} + - id: lv_badge_max + pack: {fileID: 21300000, guid: 30dce27e256a74aa797da5e70d1c9a08, type: 3} + samguk: {fileID: 0} + tint: {r: 1, g: 1, b: 1, a: 1} - id: tile_bridge pack: {fileID: 0} samguk: {fileID: 21300000, guid: 8e5bf7eb1e300474785ff2781eeb5093, type: 3} diff --git a/Assets/Scripts/OutGame/UI/HeroScreens.cs b/Assets/Scripts/OutGame/UI/HeroScreens.cs index f3da2ccb..b1957532 100644 --- a/Assets/Scripts/OutGame/UI/HeroScreens.cs +++ b/Assets/Scripts/OutGame/UI/HeroScreens.cs @@ -76,14 +76,104 @@ namespace TKS.OutGame } } - /// 영웅 탭 = 보유 영웅·병사 목록(장수|병사 · 2줄 카드) → 탭 = 영웅 상세 · 도감. + /// + /// 영웅 목록 세로 카드(PD 2026-11-09 레퍼런스 = 팩 데모 Collection_List · 칸 320×431) — 등급색 바탕(마스크) · 그라데이션 · 일러 뒤 빛 · 일러 · 아래 어두운 띠 · 테두리 · + /// 이름(왼쪽 위) · 병종 원 · 레벨 배지(왼쪽 아래 · 최고 = 노랑) · ★(오른쪽 아래) · 미보유 = 빈 카드(문양 + 얼굴 실루엣). 수치 = 팩 프리팹 RectTransform 그대로. + /// + public static class CollectionCards + { + public static readonly Vector2 CellSize = new Vector2(320f, 431f); + public static readonly Vector2 Spacing = new Vector2(22f, 20f); + + public static Image Card(Transform content, OutGameSession s, HeroDb.Hero h, System.Action onTap) + { + var cell = UiKit.Cell(content, "Card_" + h.id, Color.clear, onTap); + cell.sprite = null; // 바닥 = 클릭 판(투명) · 그림은 층으로 + var t = cell.transform; + var lv = s.Save.Level(h.id); + var hs = s.Save.Hero(h.id); + string g = h.isSoldier || hs == null || string.IsNullOrEmpty(hs.grade) ? "white" : hs.grade; + string G = "grade_" + g + "_"; + + // 바탕(마스크) 안 = 그라데이션 · 빛 · 일러 · 아래 띠(카드 둥근 모양으로 잘림) + var bg = UiKit.Layer(t, "Bg", "card_bg", UiKit.Col(G + "card_bg", UiKit.Paper), 2f, 2f, 2f, 2f); + bg.gameObject.AddComponent().showMaskGraphic = true; + var b = bg.transform; + UiKit.Layer(b, "Gradient", "card_grad", UiKit.Col(G + "card_grad", UiKit.White), 0f, 0f, 0f, 44.6f); + UiKit.Skin(UiKit.Rect("Glow", b, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(226f, 226f)), "card_glow", UiKit.Col(G + "card_glow", UiKit.White)).enabled = UISkin.Has("card_glow"); + var sp = UiKit.ArtSprite(h.art); + if (sp != null) + { + // 우리 일러 = 전신 SD → 상반신이 카드를 채우게 키우고 아래로(다리는 아래 띠 뒤 · 레퍼런스 흉상 느낌) + var art = UiKit.Rect("Character", b, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -56f), new Vector2(470f, 460f)).gameObject.AddComponent(); + art.sprite = sp; + art.preserveAspect = true; + art.raycastTarget = false; + } + else + { + var dot = UiKit.Dot("Shape", b, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -10f), 200f, UiKit.TypeColor(h.type)); + UiKit.Title(UiKit.FillLabel(dot.transform, UnitTypeInfo.Mark(h.type), 100, UiKit.White), true); + } + var bottom = UiKit.Rect("Bottom", b, new Vector2(0.5f, 0f), new Vector2(0.5f, 0.5f), new Vector2(0f, 21.7f), new Vector2(0f, 91.5f)); + bottom.anchorMin = new Vector2(0f, 0f); + bottom.anchorMax = new Vector2(1f, 0f); + bottom.sizeDelta = new Vector2(52.6f, 91.5f); + UiKit.Skin(bottom, "card_bottom", UiKit.Col("card_bottom", UiKit.Dark)).enabled = UISkin.Has("card_bottom"); + UiKit.Layer(t, "Border", "card_border", UiKit.Col("card_border", UiKit.Line)); + + // ★(오른쪽 아래 · 42×45 · 28 간격 겹침) + int star = hs != null ? hs.star : h.rarity; + for (int i = star - 1; i >= 0; i--) + UiKit.Icon(t, "star_on", new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-15.5f - i * 28f, 64.8f), 44f); + // 레벨 배지(왼쪽 아래 · 최고 레벨 = 노랑) + int lvn = lv != null ? lv.lv : 1; + bool maxLv = s.Db.Levels != null && lvn >= s.Db.Levels.MaxLevel; + var badge = UiKit.Icon(t, maxLv ? "lv_badge_max" : "lv_badge_s", new Vector2(0f, 0f), new Vector2(0.5f, 0.5f), new Vector2(33.9f, 36.7f), 79f); + if (badge != null) + { + var bt = UiKit.Title(UiKit.Label(badge.transform, lvn.ToString(), 30, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(1f, -3f), new Vector2(74f, 50f)), true); + bt.horizontalOverflow = HorizontalWrapMode.Overflow; + } + // 이름(왼쪽 위 · 45) · 병종 원(#35374E 58×60) + var name = UiKit.Title(UiKit.Label(t, h.nameKo, 45, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2(24f, -40.5f), new Vector2(280f, 66f)), true); + name.horizontalOverflow = HorizontalWrapMode.Overflow; + var role = UiKit.Skin(UiKit.Rect("Role", t, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(46f, -100.9f), new Vector2(58f, 60f)), "dot", UiKit.Col("circle_inner", UiKit.Dark)); + role.preserveAspect = true; + if (UiKit.Icon(role.transform, UiKit.TypeIconId(h.type), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 40f) == null) + UiKit.Title(UiKit.FillLabel(role.transform, UnitTypeInfo.Mark(h.type), 28, UiKit.White), true); + if (s.CanGrowAny(h.id)) UiKit.Icon(t, "new_dot", new Vector2(1f, 1f), new Vector2(0.5f, 0.5f), new Vector2(-14f, -14f), 36f); + return cell; + } + + /// 빈 카드(미보유 자리) = 어두운 바탕 + 문양 + 테두리 + 오른쪽 아래 얼굴 실루엣(팩 CardFrame01_Empty). + public static Image Empty(Transform content) + { + var cell = UiKit.Cell(content, "Empty", Color.clear, null); + cell.sprite = null; + var t = cell.transform; + UiKit.Layer(t, "Bg", "card_bg", UiKit.Col("card_empty", UiKit.Slot), 2f, 2f, 2f, 2f); + var pat = UiKit.Layer(t, "Pattern", "card_empty_pattern", UiKit.Col("card_empty_pattern", UiKit.Slot), 8f, 8f, 8f, 8f); + pat.type = Image.Type.Tiled; + UiKit.Layer(t, "Border", "card_border", UiKit.Col("card_empty_border", UiKit.Line)); + var face = UiKit.Icon(t, "face", new Vector2(1f, 0f), new Vector2(0.5f, 0.5f), new Vector2(-87f, 90.8f), 127f); + if (face != null) face.color = UiKit.Col("card_empty_face", UiKit.Dark); + return cell; + } + } + + /// + /// 영웅 탭 = 영웅 목록(PD 2026-11-09 레퍼런스 = 팩 Collection_List) — 헤더(제목 · 장수/병사 고르기 ▼ · 사선 칸 「보유 / 전체」) · + /// 3열 세로 카드(보유 = 레벨 높은 순) + 미보유 자리 = 빈 카드 → 탭 = 영웅 상세. + /// public class HeroListScreen : OutGameScreen { bool soldiers; RectTransform content; ScrollRect scroll; - Button tabHero; - Button tabSoldier; + Text filterText; + Text countText; + int ownedCards; public bool ShowingSoldiers { @@ -93,12 +183,29 @@ namespace TKS.OutGame public override void Build() { Tab = 0; - Header("영웅", "", true); // 부제 삭제(설계서 §2-5) + // 바탕 = 진남(레퍼런스 실측) + 재화 바 뒤 띠 + UiKit.Paint(UiKit.Fill("ListBg", Rt), UiKit.Col("list_bg", UiKit.Bg), false); + UiKit.Paint(UiKit.TopBand("ListTop", Rt, 0f, OutGameRoot.TopBarH), UiKit.Col("band_top", UiKit.Bg), false); + var head = Header("영웅", "", true); + + // 오른쪽 사선 칸(보유 / 전체) — 팩 PanelFrame03_Oblique #D8E8FF 239 폭 + var ob = UiKit.Rect("Oblique", head, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, new Vector2(239f, OutGameRoot.HeaderH - 7f)); + UiKit.Skin(ob, "oblique", UiKit.Col("oblique", UiKit.White)); + countText = UiKit.Title(UiKit.Label(ob, "", 52, UiKit.Col("count_text", UiKit.Dark), TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(12f, 0f), new Vector2(220f, 80f))); + countText.horizontalOverflow = HorizontalWrapMode.Overflow; + + // 장수 / 병사 고르기(팩 「Property ▼」 자리 · 탭 = 전환) + var pick = UiKit.Rect("Filter", head, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-252f, 0f), new Vector2(240f, 90f)); + var hit = pick.gameObject.AddComponent(); + hit.color = Color.clear; + pick.gameObject.AddComponent