// ───────────────────────────────────────────────────────────────────────────── // WLBossUiSettings.cs — 보스 등장 연출(배너 + 경고 비네트) 값의 단일 출처 (WL-813tj · 813t · #813) // // 기준서 v1 §D-1 813t 행: "Spawned(isBoss) → 상단 BOSS 배너 1.2 s + 화면 가장자리 붉은 UI 비네트 0.8 s // (포스트 프로세싱 금지 → UI 이미지) · 보스 이름은 MonsterList.n_MonsterName" // §B 요소 6 "등장 · 처치 연출": 등장 배너 + 카메라 오빗 1.2 s + 상단 HP 바. // // ■ 왜 이 에셋인가 (C45) // 시간·크기·색·문구를 코드 상수로 두지 않는다. 이 파일에는 "필드와 기본값"만 있고, // 게임이 실제로 읽는 값은 Resources/WL/WLBossUiSettings.asset 이다. // 에셋이 없으면 Instance == null → BossBanner 는 아무 것도 만들지 않는다(C8 롤백 1순위). // // ■ px → 캔버스 유닛 // 환산 계수를 여기에 두지 않는다. 813c 의 WLHudLayoutSettings.UnitsPerPx(canvas) 하나만 쓴다 // (802b·813c·813g 실측 1.7778 = 세로 1080 기준). 산식이 두 벌이 되면 값이 갈린다. // // 🔴 어셈블리 주의: Assets/WL/UI/ 에 .asmdef 를 만들지 말 것(Assembly-CSharp 단일). // ───────────────────────────────────────────────────────────────────────────── using UnityEngine; namespace WL.UI { [CreateAssetMenu(fileName = "WLBossUiSettings", menuName = "WL/Boss UI Settings", order = 31)] public sealed class WLBossUiSettings : ScriptableObject { /// Resources 경로 — 런타임 로드 키. public const string ResourcesPath = "WL/WLBossUiSettings"; private static WLBossUiSettings s_instance; private static bool s_tried; /// 에셋이 없으면 null(호출부는 null 이면 연출을 건너뛴다 = C8 롤백). public static WLBossUiSettings Instance { get { if (s_instance == null && !s_tried) { s_tried = true; s_instance = Resources.Load(ResourcesPath); } return s_instance; } } public static void ClearCache() { s_instance = null; s_tried = false; } // ── 공통 스위치 ─────────────────────────────────────────────────────── [Header("공통")] [Tooltip("끄면 BossBanner 가 구독조차 하지 않는다(원본 100% · C8 롤백)")] public bool bannerEnabled = true; [Tooltip("같은 보스가 다시 Spawned 를 내도 이 시간 안이면 배너를 다시 띄우지 않는다(중복 방지)")] public float retriggerGuardSeconds = 3f; [Tooltip("배너가 켜질 때 이미 살아 있는 보스가 있으면 즉시 배너를 띄운다(맵 로드 시 스폰 = Q3 결함 D-3 · WL-813y). 끄면 Spawned/BossPhase 이벤트만 본다.")] public bool bannerTriggerExisting = true; // ── 배너 ────────────────────────────────────────────────────────────── [Header("배너 (기준서 §D-1 813t · 1.2 s)")] [Tooltip("배너 총 표시 시간 — 기준서 1.2")] public float bannerSeconds = 1.2f; [Tooltip("등장 페이드 인")] public float bannerFadeInSeconds = 0.15f; [Tooltip("퇴장 페이드 아웃")] public float bannerFadeOutSeconds = 0.25f; [Tooltip("배너 등장 펀치 배율 (813g 텍스트 연출과 같은 계열)")] public float bannerPunchScale = 1.35f; [Tooltip("펀치가 원래 크기로 수렴하는 시간")] public float bannerPunchSeconds = 0.18f; [Tooltip("Safe Area 상단에서 배너 위 모서리까지 (px) — 813c 보스 HP 바(190~256 px)와 겹치지 않는 값")] public float bannerTopMarginPx = 300f; [Tooltip("배너 크기 (px · 세로 1080 기준)")] public Vector2 bannerSizePx = new Vector2(860f, 150f); [Tooltip("배너 뒷판 색 (알파 0 이면 뒷판을 만들지 않는다)")] public Color bannerBgColor = new Color(0f, 0f, 0f, 0.55f); [Tooltip("큰 글씨 — 문구도 값이다(로컬라이즈 전까지 여기서 바꾼다)")] public string bannerTitleText = "BOSS"; [Tooltip("큰 글씨 크기 (px)")] public float bannerTitleFontPx = 96f; [Tooltip("큰 글씨 색 — 기준서 §B 등급 5 빨강 팔레트")] public Color bannerTitleColor = new Color(1f, 0.271f, 0.278f, 1f); // #FD4547 [Tooltip("보스 이름 줄 크기 (px) · 이름은 MonsterList.n_MonsterName(localtext)에서 온다")] public float bannerNameFontPx = 56f; [Tooltip("보스 이름 줄 색")] public Color bannerNameColor = new Color(1f, 0.941f, 0.722f, 1f); // #FFF0B8 [Tooltip("이름을 못 구했을 때 이름 줄을 숨긴다(빈 줄 방지)")] public bool hideNameWhenUnknown = true; // ── 경고 비네트 (UI 이미지 · 포스트 프로세싱 금지) ──────────────────── [Header("경고 비네트 (기준서 §D-1 813t · 0.8 s · UI 이미지)")] [Tooltip("끄면 비네트를 만들지 않는다")] public bool warnVignetteEnabled = true; [Tooltip("비네트 총 표시 시간 — 기준서 0.8")] public float warnVignetteSeconds = 0.8f; [Tooltip("이 시간 안에 최고 밝기까지 올린다")] public float warnVignetteFadeInSeconds = 0.12f; [Tooltip("표시 시간 안에서 몇 번 맥동하는가 (1 = 한 번 밝아졌다 꺼짐)")] public int warnVignettePulses = 2; [Tooltip("가장자리 띠 두께 (px) — 9-슬라이스 테두리라 화면 중앙은 그리지 않는다(fillCenter=false)")] public float warnVignetteThicknessPx = 180f; [Tooltip("비네트 색(알파 = 최고 밝기)")] public Color warnVignetteColor = new Color(1f, 0.165f, 0.165f, 0.55f); // #FF2A2A · a 0.55 // ── 보스 HP 바 렌더 (WL-813c3 · Q7 결함 D-26 「계기는 맞고 화면은 틀리다」) ── // 813c2 로 fillAmount 는 정확해졌는데(0.541/0.368/0.01) 화면 바는 만피였다. // 실측 원인 = 바의 `Fill` Image 에 **스프라이트가 없다**(BossHpBar.cs:499 가 AddComponent 만 했다). // uGUI `Image.OnPopulateMesh` 는 `activeSprite == null` 이면 `Graphic.OnPopulateMesh`(사각형 전체)로 // 빠져 `type`/`fillAmount` 를 **아예 보지 않는다** → 계기 0.368 · 화면 100 %. // 배치·색은 813c 의 WLHudLayoutSettings 가 그대로 갖는다. 여기 있는 것은 **렌더 설정**뿐이다. [Header("보스 HP 바 렌더 (WL-813c3 · D-26)")] [Tooltip("바가 켜질 때마다 fill 의 type=Filled · fillMethod=Horizontal · fillOrigin=Left 와 스프라이트를 강제한다. 끄면 813c2 상태(화면 만피)로 돌아간다 = C8 롤백")] public bool bossBarForceFilledFill = true; [Tooltip("fill 이 쓸 스프라이트. 비워 두면 bossBarFillWhiteFallback 이 만든 흰 스프라이트를 쓴다(전용 아트가 생기면 여기에 물린다)")] public Sprite bossBarFillSprite; [Tooltip("bossBarFillSprite 가 비었을 때 엔진 내장 흰 텍스처로 스프라이트를 **1개만** 만들어 공유한다(정적 캐시 · 프레임당 할당 0). 끄면 스프라이트를 안 물려 D-26 이 그대로 남는다")] public bool bossBarFillWhiteFallback = true; [Tooltip("배경(Bg)·눈금(Tick_*)에도 같은 스프라이트를 물린다. 표시는 같고 머티리얼/배치만 통일된다(기본 꺼짐 = 원래 모습 유지)")] public bool bossBarSpriteOnBgAndTicks = false; [Tooltip("같은 캔버스 아래에 BossHpBar 가 2개 이상이면 첫 1개만 남기고 나머지는 숨긴다(중복 노드가 뒤에서 만피로 보이는 것을 막는다)")] public bool bossBarDedupInstances = true; [Tooltip("HP 가 0 이 되면 사망 판정 전이라도 바를 0 으로 내리고 숨김을 예약한다(WLHudLayoutSettings.bossBarHideDelaySec 뒤)")] public bool bossBarHideOnZeroHp = true; // ── 진단 ────────────────────────────────────────────────────────────── [Header("진단")] [Tooltip("배너·비네트 전이를 콘솔에 남긴다(Play 진단용 · 기본 꺼짐)")] public bool verboseLog = false; } }