diff --git a/Assets/Resources/Units/art_size.csv b/Assets/Resources/Units/art_size.csv index 8e63d6b7..7e33b88f 100644 --- a/Assets/Resources/Units/art_size.csv +++ b/Assets/Resources/Units/art_size.csv @@ -125,4 +125,4 @@ zhoucang,0,173.3,538.3,453,598.0,276.0,856,1091.8,,1.092, zhoutai,0,162.2,609.1,429,599.5,273.0,885,993.6,,1.026, zhugejin,0,160.2,562.8,372,501.0,270.0,870,954.7,,1.08, zhugeliang,0,140.2,529.3,336,469.0,264.0,886,962.8,,1.18, -zhurong,0,118.3,458.4,0,0,0,773,821.6,,1.18,눈 수동 실측 2026-11-10(눈 간격·눈 높이): 눈 덩어리 중심 x 524.4 · 642.7(짙은 피부 = 피부 판정 밖) +zhurong,0,118.6,458.1,261,524.0,258.0,773,758.1,,1.02,눈 수동 실측 2026-11-10(눈 간격·눈 높이): 눈 덩어리 중심 x 524.4 · 642.7(짙은 피부 = 피부 판정 밖) diff --git a/Assets/Resources/Units/zhurong/front_action/f000.png b/Assets/Resources/Units/zhurong/front_action/f000.png index c39af9e2..29288658 100644 Binary files a/Assets/Resources/Units/zhurong/front_action/f000.png and b/Assets/Resources/Units/zhurong/front_action/f000.png differ diff --git a/Assets/Resources/Units/zhurong/front_idle/f000.png b/Assets/Resources/Units/zhurong/front_idle/f000.png index b6aea447..d24b7318 100644 Binary files a/Assets/Resources/Units/zhurong/front_idle/f000.png and b/Assets/Resources/Units/zhurong/front_idle/f000.png differ diff --git a/Assets/Resources/Units/zhurong/front_ready/f000.png b/Assets/Resources/Units/zhurong/front_ready/f000.png index 0bd3b3e5..56e96b08 100644 Binary files a/Assets/Resources/Units/zhurong/front_ready/f000.png and b/Assets/Resources/Units/zhurong/front_ready/f000.png differ diff --git a/Assets/Scripts/OutGame/UI/LobbyScreen.cs b/Assets/Scripts/OutGame/UI/LobbyScreen.cs index b40ba2ce..26a8725e 100644 --- a/Assets/Scripts/OutGame/UI/LobbyScreen.cs +++ b/Assets/Scripts/OutGame/UI/LobbyScreen.cs @@ -16,6 +16,8 @@ namespace TKS.OutGame Text sortieSub; Text chestBadge; RectTransform field; + /// 로비 출전 영웅 표준 키(px · 크기 표 size_px 가 이 높이) — 유비가 예전 칸 맞춤 때와 같은 크기(797×826 틀 → 196 칸 = ×0.246 · size 837 × 0.246 ≈ 206). + const float LobbyUnitPx = 206f; static RectTransform At(Transform p, string name, float x, float y, float w, float h) { @@ -176,7 +178,9 @@ namespace TKS.OutGame { var h = S.Def(lineup[i].id); float x = (i - (n - 1) / 2f) * w; - UiKit.Portrait("Hero" + i, field, h, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(x, 20f), new Vector2(w, 340f), false, 1f, Color.clear); + // 크기 표 기준으로 발 맞춰 세움(PD 2026-11-10 「로비 관우만 작게 보임」 = 칸에 그림 틀을 맞추면 틀이 넓은 관우만 작아짐) · 일러 없으면 초상 + if (UiKit.UnitStand("Hero" + i, field, h, new Vector2(0.5f, 0f), new Vector2(x, 20f), LobbyUnitPx, cfg.mountedArtMaxTop) == null) + UiKit.Portrait("Hero" + i, field, h, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(x, 20f), new Vector2(w, 340f), false, 1f, Color.clear); } } } diff --git a/Assets/Scripts/OutGame/UI/OutGameRoot.cs b/Assets/Scripts/OutGame/UI/OutGameRoot.cs index e22fa0f5..434ce1e3 100644 --- a/Assets/Scripts/OutGame/UI/OutGameRoot.cs +++ b/Assets/Scripts/OutGame/UI/OutGameRoot.cs @@ -273,12 +273,17 @@ namespace TKS.OutGame if (UISkin.On) { tabImages[i].gameObject.SetActive(on); - tabTexts[i].gameObject.SetActive(on); + // 글자 = 선택 안 된 탭도 항상(PD 2026-11-10 「선택되지 않았을 때에도 글자가 보이게」) · 선택 = 흰 큰 글자 · 아니면 흐린 작은 글자(동맹 = 잠김 색 그대로) + var t = tabTexts[i]; + t.gameObject.SetActive(true); + t.color = on ? UiKit.White : tabOffText; + t.fontSize = on ? TabLabelOn : TabLabelOff; + t.rectTransform.anchoredPosition = new Vector2(0f, on ? TabLabelYOn : TabLabelYOff); var ic = i < tabIcons.Count ? tabIcons[i] : null; if (ic != null) { - ic.sizeDelta = Vector2.one * (on ? 118f : 104f); - ic.anchoredPosition = new Vector2(0f, on ? 48f : 30f); + ic.sizeDelta = Vector2.one * (on ? TabIconOn : TabIconOff); + ic.anchoredPosition = new Vector2(0f, on ? TabIconYOn : TabIconYOff); } } else tabImages[i].color = on ? UiKit.Red : UiKit.Dark; @@ -438,6 +443,24 @@ namespace TKS.OutGame // ---------- 하단 탭 ---------- + // 탭 배치(px · 탭 바 아래 기준) — 글자를 항상 보이게 바꾸며(PD 2026-11-10) 아이콘을 글자 위로 올림 · 선택 탭 = 솟음 판(168) 위로 크게 + const float TabIconOff = 96f, TabIconOn = 118f, TabIconYOff = 46f, TabIconYOn = 52f; + const int TabLabelOff = 30, TabLabelOn = 34; + const float TabLabelYOff = 24f, TabLabelYOn = 30f; + Color tabOffText = Color.gray; + + /// 글자가 켜진 하단 탭 수(테스트 · PD 2026-11-10 「선택되지 않은 탭도 글자」). + public int VisibleTabLabels + { + get + { + int n = 0; + foreach (var t in tabTexts) + if (t != null && t.gameObject.activeSelf) n++; + return n; + } + } + void BuildTabBar() { var bar = UiKit.Rect("TabBar", mainCanvas.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), Vector2.zero, new Vector2(Reference.x, TabBarH)); @@ -451,6 +474,7 @@ namespace TKS.OutGame string[] marks = { "영", "보", "내", "잠", "거" }; string[] icons = { "tab_hero", "tab_treasure", "tab_domestic", "tab_alliance", "tab_trade" }; Color off = UISkin.Col("bar_text_off", new Color(0.62f, 0.58f, 0.55f)); + tabOffText = off; for (int i = 0; i < names.Length; i++) { int k = i; @@ -470,7 +494,7 @@ namespace TKS.OutGame img = UiKit.Skin(focus, "tab_focus", UiKit.Col("tab_focus", UiKit.Red)); if (UISkin.Has("tab_focus_light")) UiKit.Skin(UiKit.Rect("Light", focus, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -6f), new Vector2(188f, 70f)), "tab_focus_light", UiKit.Col("tab_focus_light", UiKit.White)); - var ic = UiKit.Icon(cell, icons[i], new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 30f), 104f); + var ic = UiKit.Icon(cell, icons[i], new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, TabIconYOff), TabIconOff); if (ic != null) { if (i == 3) ic.color = UiKit.Col("tab_locked", off); @@ -489,7 +513,7 @@ namespace TKS.OutGame UiKit.FillLabel(dot.transform, marks[i], 32, i == 3 ? new Color(0.7f, 0.66f, 0.62f) : UiKit.White); } var t = UISkin.On - ? UiKit.Label(cell, names[i], 36, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0.5f), new Vector2(0f, 36f), new Vector2(204f, 50f)) + ? UiKit.Label(cell, names[i], TabLabelOff, off, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0.5f), new Vector2(0f, TabLabelYOff), new Vector2(204f, 50f)) : UiKit.Label(cell, names[i], 32, i == 3 ? off : UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 14f), new Vector2(200f, 48f)); if (UISkin.On) UiKit.Title(t, true); tabImages.Add(img); @@ -499,6 +523,12 @@ namespace TKS.OutGame public void OnTab(int i) { + // 선택된 탭을 다시 누르면 닫기 = 로비(PD 2026-11-10 「해당 메뉴가 선택된 상태일 경우 X(닫기 버튼)처럼 동작」) + if (current != null && current != Lobby && current.Tab == i) + { + ShowLobby(); + return; + } switch (i) { case 0: Show(HeroList); break; diff --git a/Assets/Scripts/OutGame/UI/UiKit.cs b/Assets/Scripts/OutGame/UI/UiKit.cs index 9319b5f8..67a2bbfb 100644 --- a/Assets/Scripts/OutGame/UI/UiKit.cs +++ b/Assets/Scripts/OutGame/UI/UiKit.cs @@ -768,6 +768,28 @@ namespace TKS.OutGame return sp; } + /// + /// 서 있는 유닛(발 = anchor + pos) — 크기 표 size_px 기준 배율(standardPx ÷ size_px = 머리 크기 통일 · 영웅 목록·전투와 같은 기준) · + /// 기마 = 머리 끝이 standardPx × mountedMaxTop 을 넘지 않게(전투 FrameAnimator 와 같은 상한) · 일러·피벗이 없으면 null(호출 쪽이 초상으로 대체). + /// PD 2026-11-10 「로비에 배치된 관우의 크기만 작게 보임」 — 칸에 그림 틀을 맞추면 틀이 넓은 유닛(관우 언월도)만 작아짐. + /// + public static RectTransform UnitStand(string name, Transform parent, HeroDb.Hero h, Vector2 anchor, Vector2 pos, float standardPx, float mountedMaxTop) + { + var sp = h != null ? ArtSprite(h.art) : null; + var a = h != null ? UnitArt.Load(h.art) : null; + if (sp == null || a == null || a.Meta.pivot == null || a.Meta.pivot.Length < 2) return null; + float size = a.SizePx > 0.5f ? a.SizePx : a.BodyPx; + if (size <= 0.5f) return null; + float k = standardPx / size; + float top = a.BodyPx * k; + if (a.Mounted && mountedMaxTop > 0.01f && top > standardPx * mountedMaxTop) k *= standardPx * mountedMaxTop / top; + var rt = Rect(name, parent, anchor, new Vector2(0.5f, a.Meta.pivot[1]), pos, sp.rect.size * k); + var img = rt.gameObject.AddComponent(); + img.sprite = sp; + img.raycastTarget = false; + return rt; + } + /// /// 초상(틀 안을 마스크) — 일러가 있으면 그 그림(zoom > 1 = 위쪽 얼굴 부분 확대) · 없으면 병종 색 원 + 병종 글자. /// circle = 원형 틀(편성 자리) · false = 둥근 사각. diff --git a/Assets/Tests/PlayMode/OutGameTests.cs b/Assets/Tests/PlayMode/OutGameTests.cs index 92f9fbac..772b831a 100644 --- a/Assets/Tests/PlayMode/OutGameTests.cs +++ b/Assets/Tests/PlayMode/OutGameTests.cs @@ -478,6 +478,14 @@ namespace TKS.Tests og.OnTab(0); Assert.AreEqual(og.HeroList, og.Current); yield return null; + // PD 2026-11-10: 하단 탭 글자 = 선택 안 된 탭도 · 선택된 탭 다시 누르면 닫기(로비) + Assert.AreEqual(5, og.VisibleTabLabels, "하단 탭 글자 5개 모두 보임"); + og.OnTab(0); + Assert.AreEqual(og.Lobby, og.Current, "선택된 탭 다시 = 닫기(로비)"); + Assert.AreEqual(5, og.VisibleTabLabels, "로비에서도 탭 글자 보임"); + og.OnTab(0); + Assert.AreEqual(og.HeroList, og.Current, "다시 열림"); + yield return null; Assert.AreEqual(og.Session.Owned(false).Count, og.HeroList.CardCount, "보유 장수 카드"); // 미보유 장수 = 빈 카드가 아니라 그 영웅 그림 카드(PD 2026-11-10 「유닛 목록에 장수들의 모습이 보이도록」) int heroTotal = 0; diff --git a/Assets/UI/Samguk/menu/tab_alliance.png b/Assets/UI/Samguk/menu/tab_alliance.png index a7c4ae31..7121676b 100644 Binary files a/Assets/UI/Samguk/menu/tab_alliance.png and b/Assets/UI/Samguk/menu/tab_alliance.png differ diff --git a/Assets/UI/Samguk/menu/tab_domestic.png b/Assets/UI/Samguk/menu/tab_domestic.png index 14f7609d..c2b4209b 100644 Binary files a/Assets/UI/Samguk/menu/tab_domestic.png and b/Assets/UI/Samguk/menu/tab_domestic.png differ diff --git a/Assets/UI/Samguk/menu/tab_hero.png b/Assets/UI/Samguk/menu/tab_hero.png index b167d046..930cd7e3 100644 Binary files a/Assets/UI/Samguk/menu/tab_hero.png and b/Assets/UI/Samguk/menu/tab_hero.png differ diff --git a/Assets/UI/Samguk/menu/tab_trade.png b/Assets/UI/Samguk/menu/tab_trade.png index 79701881..9af78bb1 100644 Binary files a/Assets/UI/Samguk/menu/tab_trade.png and b/Assets/UI/Samguk/menu/tab_trade.png differ diff --git a/Assets/UI/Samguk/menu/tab_treasure.png b/Assets/UI/Samguk/menu/tab_treasure.png index c08ff5b7..fb2072e6 100644 Binary files a/Assets/UI/Samguk/menu/tab_treasure.png and b/Assets/UI/Samguk/menu/tab_treasure.png differ diff --git a/Assets/UI/Samguk/ui_delivered.csv b/Assets/UI/Samguk/ui_delivered.csv index a3232d9d..4fdc71b3 100644 --- a/Assets/UI/Samguk/ui_delivered.csv +++ b/Assets/UI/Samguk/ui_delivered.csv @@ -70,11 +70,11 @@ skill_spear_a,logo_skill,Assets/UI/Samguk/logo_skill/skill_spear_a.png,1ee53fa18 skill_spear_p,logo_skill,Assets/UI/Samguk/logo_skill/skill_spear_p.png,1ea22555662c8c19934064e0d54a4076,ui_logo_skill skill_strategist_a,logo_skill,Assets/UI/Samguk/logo_skill/skill_strategist_a.png,1caceeaaa3e566e50ef9e80bdd3d30f7,ui_logo_skill skill_strategist_p,logo_skill,Assets/UI/Samguk/logo_skill/skill_strategist_p.png,67a37d7ef0e37f64169a7c3014aa937a,ui_logo_skill -tab_alliance,menu,Assets/UI/Samguk/menu/tab_alliance.png,b43aa0b723ce2953c5b1b179feae9969,ui_menu -tab_domestic,menu,Assets/UI/Samguk/menu/tab_domestic.png,3f9a7e8b0110ff3543b5d346618d639d,ui_menu -tab_hero,menu,Assets/UI/Samguk/menu/tab_hero.png,b552c5a1d72dc1e50381b665500dd41e,ui_menu -tab_trade,menu,Assets/UI/Samguk/menu/tab_trade.png,46c477c1f8defb62b16630045891ae99,ui_menu -tab_treasure,menu,Assets/UI/Samguk/menu/tab_treasure.png,a5b6125f6b46748a69b677a50bb01dc7,ui_menu +tab_alliance,menu,Assets/UI/Samguk/menu/tab_alliance.png,baef297a314e2848f0104a8930ac8426,ui_tab_casual_20261110 +tab_domestic,menu,Assets/UI/Samguk/menu/tab_domestic.png,e7df3d5127965baf0904d86356780b19,ui_tab_casual_20261110 +tab_hero,menu,Assets/UI/Samguk/menu/tab_hero.png,6e9a32f84d1e2221755e792decd002c7,ui_tab_casual_20261110 +tab_trade,menu,Assets/UI/Samguk/menu/tab_trade.png,aebe733f146eb20a22fd25ccfd4d0c81,ui_tab_casual_20261110 +tab_treasure,menu,Assets/UI/Samguk/menu/tab_treasure.png,f7dc5942a8caf78310541826105b477f,ui_tab_casual_20261110 tile_bridge,gimmick,Assets/UI/Samguk/gimmick/tile_bridge.png,80728d733f5477174a209c42feab1aba,ui_gimmick tile_burning,gimmick,Assets/UI/Samguk/gimmick/tile_burning.png,a49ab2ede2802a68b40f3410817f9bc6,ui_gimmick tile_fog,gimmick,Assets/UI/Samguk/gimmick/tile_fog.png,7b9ab096a721c3efcc229dabb53efb41,ui_gimmick