ThreeKingdomsSlingshot/Assets/Scripts/Runtime/UI/UITheme.cs

155 lines
5.2 KiB
C#
Raw Permalink Normal View History

UI 리뉴얼 A-2~A-4 화면 적용(PD #1100) — 팩 부품 + UI 테마(id 치환) · 화면 10종 · 인박스 ui kind - 테마: SOT Assets/Data/UI/ui_theme.csv(색 57 · 스킨 32 · 아이콘 63 · 제목 폰트) → 메뉴 TKS/Import UI Theme → Resources/UI/UITheme.asset (Runtime/UI/UITheme · UISkin · Editor/UIThemeImporter · ProjectSetup 에서도 임포트) · 화면 코드는 id 로만 묻는다(스프라이트 경로 0) - 신규 제작(B) 치환: Assets/UI/Samguk/**/<id>.png → 임포트 시 같은 id 스킨·아이콘 자동 치환(팩 보존 · 새 id = 아이콘 추가) · Tools/apply_delivery.py ui kind(md5 → Samguk/<group> · gim_* → Resources/Gimmicks/Art · ui_delivered.csv) - 공통: UiKit(카드 = BorderFrame_Round20 틴트 · 버튼 = Button01_s + 광택 · 원 · 진행 바 = Slider_Basic01 · 초상 틀 · 등급 칸 ItemFrame02 · 별 줄 · 병종 배지) · 재화 바(ResourceBar + cur_* 아이콘) · 하단 탭(선택 판 + PictoIcon) · 제목 띠 · 팝업(Popup Topber + 닫기 X) · 토스트 - 화면: 로비(키아트 04 배경 위쪽 ×1.22 · 출정·편성·연무장 아이콘) · 영웅(등급 칸 + 장비 아이콘 · 체크/알림 점 · 별 아이콘) · 편성 · 거래(배너 · 상자 아이콘) · 보물(상자 아이콘 · 포인트 배지) · 내정(보상 줄 · 도면·골드 아이콘) · 연무장 · 결과(리본 · 별) · 월드맵 스테이지 팝업만 팩(거점 kit 유지) - 전투: HUD 칩 · 턴 띠 · 원형 스킬 버튼 + 쿨 라디얼 · 유닛 체력 바 · 기믹 내구 핍 = 팩 슬라이더(월드 9-slice 사본 · 가운데 2 px) · 조준선 색 유지 - 3:4(1536×2048): 본문 비율 축소(UiFitHeight · 1080×1920 = 그대로) - 검증: 플레이모드 116/116(기존 115 + UIThemeTests 1) · 컴파일 0 · error 0 · 캡처 = DataImporter.CaptureUI(UICaptureDriver · 15장) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:20:57 +00:00
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TKS
{
/// <summary>
/// UI 테마(PD #1100 UI 리뉴얼 · 2026-11-06) — 색 팔레트 · 9-slice 부품(스킨) · 아이콘 id → 스프라이트 치환 테이블 · 제목 폰트.
/// SOT = Assets/Data/UI/ui_theme.csv → 메뉴 TKS/Import UI Theme → Resources/UI/UITheme.asset(에디터 UIThemeImporter).
/// 스킨·아이콘은 팩(Layer Lab GUI Pro-SuperCasual · Assets/UI/GUIPro) 기본 + 신규 제작 납품(Assets/UI/Samguk/**/&lt;id&gt;.png)이 있으면 그것으로 치환.
/// 화면 코드는 id 로만 묻는다(스프라이트 경로를 코드에 쓰지 않는다 · C45).
/// </summary>
[CreateAssetMenu(menuName = "TKS/UI Theme")]
public class UITheme : ScriptableObject
{
public const string ResourcePath = "UI/UITheme";
[Serializable]
public class ColorEntry
{
public string id;
public Color color = Color.white;
}
[Serializable]
public class SkinEntry
{
public string id;
/// <summary>팩 바탕(흰 계열 = 호출 색으로 틴트).</summary>
public Sprite pack;
/// <summary>신규 제작 치환(있으면 pack 대신).</summary>
public Sprite samguk;
/// <summary>위 덮개(광택·글리프 · 틴트 안 함).</summary>
public Sprite overlay;
/// <summary>9-slice 배율(Image.pixelsPerUnitMultiplier · 클수록 테두리가 얇다).</summary>
public float ppu = 1f;
/// <summary>덮개 안쪽 여백(px · 왼 · 위 · 오 · 아래).</summary>
public Vector4 inset;
/// <summary>덮개 불투명도.</summary>
public float overlayAlpha = 1f;
public Sprite Sprite
{
get { return samguk != null ? samguk : pack; }
}
}
[Serializable]
public class IconEntry
{
public string id;
public Sprite pack;
public Sprite samguk;
/// <summary>표시 색(흰 실루엣 아이콘용 · 기본 흰색 = 원색 그대로).</summary>
public Color tint = Color.white;
public Sprite Sprite
{
get { return samguk != null ? samguk : pack; }
}
}
public List<ColorEntry> colors = new List<ColorEntry>();
public List<SkinEntry> skins = new List<SkinEntry>();
public List<IconEntry> icons = new List<IconEntry>();
/// <summary>제목·숫자 강조(Sen-ExtraBold · 한글 = 임포터 폴백 Malgun Gothic · PD 결정 전).</summary>
public Font titleFont;
Dictionary<string, ColorEntry> colorMap;
Dictionary<string, SkinEntry> skinMap;
Dictionary<string, IconEntry> iconMap;
static UITheme current;
static bool tried;
/// <summary>Resources/UI/UITheme(없으면 null = 기존 도형 UI 로 동작).</summary>
public static UITheme Current
{
get
{
if (current == null && !tried)
{
tried = true;
current = Resources.Load<UITheme>(ResourcePath);
}
return current;
}
}
/// <summary>테마 교체(임포트 뒤 · 테스트) — null = 다시 Resources 에서 읽음.</summary>
public static void Use(UITheme t)
{
current = t;
tried = t != null;
if (t != null) t.Rebuild();
}
public void Rebuild()
{
colorMap = new Dictionary<string, ColorEntry>();
foreach (var c in colors)
if (c != null && !string.IsNullOrEmpty(c.id)) colorMap[c.id] = c;
skinMap = new Dictionary<string, SkinEntry>();
foreach (var s in skins)
if (s != null && !string.IsNullOrEmpty(s.id)) skinMap[s.id] = s;
iconMap = new Dictionary<string, IconEntry>();
foreach (var i in icons)
if (i != null && !string.IsNullOrEmpty(i.id)) iconMap[i.id] = i;
}
void OnEnable()
{
colorMap = null;
}
void Ensure()
{
if (colorMap == null || skinMap == null || iconMap == null) Rebuild();
}
public bool TryColor(string id, out Color c)
{
Ensure();
ColorEntry e;
if (id != null && colorMap.TryGetValue(id, out e))
{
c = e.color;
return true;
}
c = Color.white;
return false;
}
public SkinEntry Skin(string id)
{
Ensure();
SkinEntry e;
return id != null && skinMap.TryGetValue(id, out e) && e.Sprite != null ? e : null;
}
public IconEntry IconEntryOf(string id)
{
Ensure();
IconEntry e;
return id != null && iconMap.TryGetValue(id, out e) && e.Sprite != null ? e : null;
}
public Sprite Icon(string id)
{
var e = IconEntryOf(id);
return e != null ? e.Sprite : null;
}
}
}