Project_WL/Assets/WL/Look/Toggle/WLLookModeSettings.cs

222 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ─────────────────────────────────────────────────────────────────────────────
// WLLookModeSettings.cs — 인게임 룩 토글(카메라 모드 · 배경 룩)의 값 단일 출처 (WL-814d · #814)
//
// PD 제안(2026-09-10) 「토글 형태로 카메라를 바꿔서 볼 수 있게」 · 발주서 WL-814d §1.
//
// ■ 왜 이 에셋인가 (C45)
// 프리셋 값(투영 · 궤도 각 · 거리 · 직교 반높이 · 픽셀 높이)과 버튼 좌표·문구를 코드 상수로 두지 않는다.
// 게임이 읽는 값은 `Resources/WL/WLLookModeSettings.asset` 이다(PD 가 인스펙터에서 바꾼다).
// 🔴 여기 있는 값은 **비교용 프리셋**이다. 확정 값은 814b `WLPixelCameraSettings`(직교·픽셀)와
// 811o `WLCameraFramingSettings`(구도)가 계속 소유한다 — 이 파일은 그 둘에 **런타임으로 얹기만** 한다.
//
// ■ 좌표계 (px)
// 813c/813q 와 같은 **세로 1080×1920 기준 화면 픽셀**. px → 캔버스 유닛 환산은
// `WLHudLayoutSettings.UnitsPerPx(canvas)` 하나만 쓴다(산식 중복 0).
//
// ■ C8 롤백
// `enabled_ = 0` → 버튼 0 · 모드 0 고정 · 814b/811o 신규 API 호출 0 = 두 기능 원래 동작 100 %.
//
// 🔴 어셈블리 주의: Assets/WL/Look/ 에 .asmdef 를 만들지 말 것(Assembly-CSharp 단일).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Look.Toggle
{
/// <summary>룩 모드 하나 = 카메라 프리셋 1줄(발주서 §1-1 표).</summary>
[System.Serializable]
public sealed class WLLookModePreset
{
[Tooltip("버튼에 찍히는 이름(예: 기본 · 도트A).")]
public string name = "기본";
[Tooltip("켜면 814b 픽셀 카메라 리그(직교 · 저해상도 RT)를 강제로 조립한다. 끄면 원근(리그 해제).")]
public bool pixelRig = false;
[Tooltip("켜면 아래 구도 3값을 쓰지 않고 811o WLCameraFramingSettings 의 SO 값을 그대로 쓴다(= 지금 구도). 0번 기본 모드용.")]
public bool useSoFraming = false;
[Tooltip("811o 궤도 파라미터 cameraHeight(도). 클수록 위에서 내려다본다.")]
public float cameraHeight = 74f;
[Tooltip("811o 궤도 거리(m) — min/max 에 같이 들어간다.")]
public float distance = 3.4f;
[Tooltip("811o 궤도 중심 높이 DistanceUp(m).")]
public float distanceUp = 2.2f;
[Tooltip("814b 직교 반높이 orthoSize(m). pixelRig 가 꺼져 있으면 쓰이지 않는다.")]
public float orthoSize = 3.8f;
[Tooltip("814b 저해상도 RT 세로 픽셀 수. pixelRig 가 꺼져 있으면 쓰이지 않는다.")]
public int pixelHeight = 480;
[Tooltip("envFollowsCameraMode 가 켜져 있을 때 이 모드에서 배경 룩(814c)을 켤지.")]
public bool envLookOn = false;
}
[CreateAssetMenu(fileName = "WLLookModeSettings", menuName = "WL/Look Mode Settings", order = 35)]
public sealed class WLLookModeSettings : ScriptableObject
{
/// <summary>Resources 경로 — 런타임 로드 키.</summary>
public const string ResourcesPath = "WL/WLLookModeSettings";
private static WLLookModeSettings s_instance;
private static bool s_tried;
/// <summary>에셋이 없으면 null(호출부는 null 이면 전부 건너뛴다 = C8 롤백).</summary>
public static WLLookModeSettings Instance
{
get
{
if (s_instance == null && !s_tried)
{
s_tried = true;
s_instance = Resources.Load<WLLookModeSettings>(ResourcesPath);
}
return s_instance;
}
}
/// <summary>에디터에서 에셋을 새로 만들거나 값을 바꾼 뒤 캐시를 버린다.</summary>
public static void ClearCache() { s_instance = null; s_tried = false; }
/// <summary>프로브·QA 용 런타임 스위치(에셋을 건드리지 않고 끈다).</summary>
public static bool RuntimeDisabled;
/// <summary>룩 토글 축이 살아 있는가 = 에셋 존재 · enabled_ · 런타임 스위치 off.</summary>
public static bool Enabled
{
get
{
if (RuntimeDisabled) return false;
var s = Instance;
return s != null && s.enabled_;
}
}
// ── 공통 ──────────────────────────────────────────────────────────────
[Header("공통 (C8 롤백)")]
[Tooltip("끄면 버튼 0 · 모드 0 고정 · 814b/811o 신규 API 호출 0 = 두 기능 원래 동작 100 %.")]
public bool enabled_ = true;
[Tooltip("켜면 모드 전환마다 Console 에 1줄 남긴다(문자열은 이 값으로 막고 만든다 · GC 주의).")]
public bool verboseLog = false;
// ── 모드 ──────────────────────────────────────────────────────────────
[Header("카메라 모드 (0 = 기본 원근 · 1~3 = 도트 프리셋)")]
[Tooltip("앱을 켰을 때 시작 모드. 0 = 지금과 같은 원근.")]
public int startMode = 0;
[Tooltip("맵을 다시 들어가도 같은 모드를 유지한다(앱 세션 동안).")]
public bool keepModeAcrossMaps = true;
[Tooltip("로비·타이틀에서는 카메라를 기본(0)으로 되돌리고, 인게임에 다시 들어가면 고른 모드를 복원한다.")]
public bool defaultInLobby = true;
[Tooltip("도트 모드로 바뀔 때 배경 룩(814c)을 프리셋의 envLookOn 값으로 함께 바꾼다.")]
public bool envFollowsCameraMode = true;
[Tooltip("배경 룩(814c) 시작 상태.")]
public bool envLookOnAtStart = false;
[Tooltip("모드 배열 — 버튼이 0 → 1 → 2 → … → 0 으로 순환한다. 0번은 기본(원근)이어야 한다.")]
public WLLookModePreset[] presets = new WLLookModePreset[]
{
// 0번은 「지금 화면 그대로」 = 811o SO 구도 · 리그 해제(useSoFraming 1 이라 아래 3값은 참고용).
new WLLookModePreset { name = "기본", pixelRig = false, useSoFraming = true, cameraHeight = 76f, distance = 3.0f, distanceUp = 2.4f, orthoSize = 3.8f, pixelHeight = 480, envLookOn = false },
new WLLookModePreset { name = "도트A", pixelRig = true, useSoFraming = false, cameraHeight = 74f, distance = 3.4f, distanceUp = 2.2f, orthoSize = 3.8f, pixelHeight = 480, envLookOn = true },
new WLLookModePreset { name = "도트B", pixelRig = true, useSoFraming = false, cameraHeight = 55f, distance = 4.5f, distanceUp = 1.8f, orthoSize = 4.2f, pixelHeight = 480, envLookOn = true },
new WLLookModePreset { name = "도트C", pixelRig = true, useSoFraming = false, cameraHeight = 45f, distance = 5.5f, distanceUp = 1.5f, orthoSize = 4.6f, pixelHeight = 480, envLookOn = true },
};
// ── HUD 버튼 ──────────────────────────────────────────────────────────
[Header("HUD 버튼 (813q RunHud 방식 · 프리팹 0 · Safe Area 안)")]
[Tooltip("끄면 버튼 노드를 만들지 않는다(시연이 끝나면 여기만 끈다 — 모드 전환은 코드/프로브로 계속 가능).")]
public bool showButtons = true;
[Tooltip("버튼을 붙일 부모 노드의 UI 루트 기준 경로(813y·813q 실측 = IngameUIs/WL_HUD · SafeAreaFitter 아래).")]
public string buttonParentPath = "IngameUIs/WL_HUD";
[Tooltip("전용 Canvas(overrideSorting)로 띄운다 — 813q 결과창(40)·813z 부활 팝업(60)보다 아래.")]
public bool ownCanvas = true;
[Tooltip("전용 Canvas 의 sortingOrder. 결과창 40 · 부활 60 보다 낮게 둔다.")]
public int sortingOrder = 10;
[Tooltip("Safe Area 상단에서 버튼 위쪽까지 여백(px). 813c 보스 바(190~256)·813q 런 HUD(272~394)·813tj 보스 배너(300~450) 아래.")]
public float topMarginPx = 470f;
[Tooltip("Safe Area 오른쪽에서 버튼 오른쪽 끝까지 여백(px).")]
public float rightMarginPx = 24f;
[Tooltip("버튼 하나의 크기(px · 발주서 하한 96×48). 폭 200 이면 런 HUD 폭 560(중앙 ±280) 오른쪽으로 36 px 비켜 있다.")]
public Vector2 buttonSizePx = new Vector2(200f, 64f);
[Tooltip("두 버튼 사이 세로 간격(px).")]
public float buttonGapPx = 12f;
[Tooltip("버튼 글자 크기(px).")]
public float buttonFontPx = 26f;
[Tooltip("버튼 배경색(꺼짐 상태).")]
public Color buttonBgColor = new Color(0.06f, 0.07f, 0.09f, 0.82f);
[Tooltip("버튼 배경색(켜짐 상태 = 도트 모드 · 배경 룩 ON).")]
public Color buttonBgOnColor = new Color(0.16f, 0.42f, 0.86f, 0.9f);
[Tooltip("버튼 글자색.")]
public Color buttonTextColor = new Color(0.95f, 0.96f, 0.98f, 1f);
[Tooltip("카메라 버튼 문구 — {0} 에 프리셋 이름이 들어간다.")]
public string cameraLabelFormat = "카메라: {0}";
[Tooltip("배경 버튼 문구 — {0} 에 아래 두 문구가 들어간다.")]
public string envLabelFormat = "배경: {0}";
[Tooltip("배경 룩 켜짐 문구.")]
public string envOnText = "ON";
[Tooltip("배경 룩 꺼짐 문구.")]
public string envOffText = "OFF";
[Tooltip("버튼 글자 테두리(813y WLTextFxUtil.ApplyEdge 재사용).")]
public WL.UI.WLTextEdge buttonEdge = new WL.UI.WLTextEdge
{
enabled = true,
outlineWidth = 0.24f,
outlineColor = new Color(0.05f, 0.03f, 0.02f, 1f),
shadowOffset = new Vector2(0.4f, -0.4f),
shadowColor = new Color(0f, 0f, 0f, 0.75f),
shadowSoftness = 0.18f,
faceDilate = 0.06f,
};
// ── 조회 ──────────────────────────────────────────────────────────────
/// <summary>모드 개수(배열이 비어 있으면 1 = 기본만).</summary>
public int ModeCount { get { return presets != null && presets.Length > 0 ? presets.Length : 1; } }
/// <summary>모드 번호를 배열 범위로 감싼다(0 → 1 → … → 0 순환).</summary>
public int Wrap(int mode)
{
int n = ModeCount;
int m = mode % n;
return m < 0 ? m + n : m;
}
/// <summary>모드 프리셋(없으면 null).</summary>
public WLLookModePreset Preset(int mode)
{
if (presets == null || presets.Length == 0) return null;
return presets[Wrap(mode)];
}
/// <summary>모드 이름(없으면 번호).</summary>
public string ModeName(int mode)
{
var p = Preset(mode);
return p != null && !string.IsNullOrEmpty(p.name) ? p.name : mode.ToString();
}
}
}