2026-09-08 15:17:58 +00:00
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
// WLBattlePadLayout.cs — 전투 패드(우하단 엄지 부채꼴) 배치 드라이버 (WL-813c · #813)
|
|
|
|
|
|
//
|
|
|
|
|
|
// 기준서 v1 §F-1 권고: 오른손 엄지 부채꼴 **4슬롯** + 물약 1 + 회피 1 · 좌우 미러 옵션.
|
|
|
|
|
|
// §B 요소 3: 버튼 지름 132~150 px · 중심 간격 ≥16 px · 요소 7: Safe Area 안 · 한 손 도달.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ■ 설계
|
|
|
|
|
|
// · 원본 BattleUI.prefab 의 **배열을 줄이지 않는다**(skillCards 6 그대로 · 원복 가능).
|
|
|
|
|
|
// 활성 슬롯 수만 설정으로 정하고, 남는 슬롯은 물약/회피(813j/813r) 자리로 **비활성**으로 둔다.
|
|
|
|
|
|
// · 값은 전부 WLHudLayoutSettings(에셋). 이 파일에 좌표·지름·각도 상수는 없다(C45).
|
|
|
|
|
|
// · 배치는 런타임에만 한다([ExecuteAlways] 아님) — 프리팹 YAML 에 좌표를 굽지 않아
|
|
|
|
|
|
// NewGameUI.prefab diff 를 "노드/컴포넌트 추가"로만 유지한다(발주서 ⓓ).
|
|
|
|
|
|
// · 이 컴포넌트는 **NewGameUI 안 IngameUIs/BattleUI 인스턴스에만** 붙인다.
|
|
|
|
|
|
// 같은 BattleUI.prefab 을 쓰는 SkillUI/SkillEquipUI 인스턴스는 손대지 않는다(회귀 0).
|
|
|
|
|
|
//
|
|
|
|
|
|
// ■ Safe Area
|
|
|
|
|
|
// 같은 오브젝트의 SafeAreaFitter(802b)가 루트를 안전 영역에 맞춘다. 이 스크립트는 루트 rect 를
|
|
|
|
|
|
// 건드리지 않고(피터가 주인) 자식만 **우하단(미러 시 좌하단) 모서리 앵커**로 배치한다.
|
|
|
|
|
|
// 피터가 없으면(단독 테스트) 루트를 스트레치로 정규화한다.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ■ 롤백(C8)
|
|
|
|
|
|
// 설정 에셋이 없거나 battlePadEnabled=false 면 아무 것도 만지지 않는다 = 원본 배치 그대로.
|
|
|
|
|
|
//
|
|
|
|
|
|
// 🔴 어셈블리 주의: Assets/WL/UI/ 에 .asmdef 를 만들지 말 것(Assembly-CSharp 단일).
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace WL.UI
|
|
|
|
|
|
{
|
|
|
|
|
|
[DisallowMultipleComponent]
|
|
|
|
|
|
[RequireComponent(typeof(RectTransform))]
|
|
|
|
|
|
public class WLBattlePadLayout : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
[Tooltip("배치 대상 — 비우면 같은 오브젝트의 BattleUI 를 찾는다")]
|
|
|
|
|
|
[SerializeField] private BattleUI target;
|
|
|
|
|
|
|
|
|
|
|
|
[Tooltip("자동전투 토글 오브젝트 이름(BattleUI 자식) — 못 찾으면 건너뛴다")]
|
|
|
|
|
|
[SerializeField] private string autoButtonName = "btn_auto";
|
|
|
|
|
|
|
|
|
|
|
|
[Tooltip("공격 버튼 오브젝트 이름(BattleUI 자식) — 못 찾으면 건너뛴다")]
|
|
|
|
|
|
[SerializeField] private string attackButtonName = "Attack";
|
|
|
|
|
|
|
|
|
|
|
|
private RectTransform _rt;
|
|
|
|
|
|
private Canvas _canvas;
|
|
|
|
|
|
private bool _lastMirror;
|
|
|
|
|
|
private Vector2Int _lastScreen;
|
|
|
|
|
|
|
|
|
|
|
|
// 마지막 적용 결과 — 프로브(에디터)가 읽는 진단 값. 실측 외에는 채우지 않는다.
|
|
|
|
|
|
public float LastUnitsPerPx { get; private set; }
|
|
|
|
|
|
public float LastMaxReachPx { get; private set; }
|
|
|
|
|
|
public float LastMinGapPx { get; private set; }
|
|
|
|
|
|
public int LastActiveSlots { get; private set; }
|
|
|
|
|
|
public int LastReserveSlots { get; private set; }
|
2026-09-08 22:58:46 +00:00
|
|
|
|
/// <summary>전투 액션 버튼(스킬 4 + 공격 + 물약)만의 도달 반경 — 자동전투 토글 제외(WL-813y).</summary>
|
|
|
|
|
|
public float LastActionReachPx { get; private set; }
|
|
|
|
|
|
/// <summary>마지막 배치 때의 하단 메뉴 상태(true = 메뉴 보임 → 패드가 idle 자리로 올라감).</summary>
|
|
|
|
|
|
public bool LastBottomMenuVisible { get; private set; }
|
2026-09-08 15:17:58 +00:00
|
|
|
|
|
|
|
|
|
|
private void Awake() { _rt = GetComponent<RectTransform>(); }
|
|
|
|
|
|
private void OnEnable() { Apply(); }
|
|
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 해상도 전환·설정 토글에만 다시 배치한다(매 프레임 계산 없음).
|
|
|
|
|
|
var s = WLHudLayoutSettings.Instance;
|
|
|
|
|
|
if (s == null) return;
|
|
|
|
|
|
if (Screen.width != _lastScreen.x || Screen.height != _lastScreen.y || s.mirrorLeftHanded != _lastMirror)
|
|
|
|
|
|
Apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>BattleUI.Set() 직후 훅 — 서버 프리셋이 슬롯을 다시 채운 뒤 배치를 되살린다.</summary>
|
|
|
|
|
|
public static void NotifySet(BattleUI ui)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ui == null) return;
|
|
|
|
|
|
var layout = ui.GetComponent<WLBattlePadLayout>();
|
|
|
|
|
|
if (layout != null && layout.isActiveAndEnabled) layout.Apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>설정 값대로 슬롯·공격·자동 버튼을 재배치한다. 설정이 없으면 아무 것도 하지 않는다.</summary>
|
|
|
|
|
|
public string Apply()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_rt == null) _rt = GetComponent<RectTransform>();
|
|
|
|
|
|
if (target == null) target = GetComponent<BattleUI>();
|
|
|
|
|
|
|
|
|
|
|
|
var s = WLHudLayoutSettings.Instance;
|
|
|
|
|
|
if (s == null) return "WLHudLayoutSettings 에셋 없음 — 배치 건너뜀(원본 유지)";
|
|
|
|
|
|
if (!s.battlePadEnabled) return "battlePadEnabled=false — 배치 건너뜀(원본 유지)";
|
|
|
|
|
|
if (target == null) return "BattleUI 없음 — 배치 건너뜀";
|
|
|
|
|
|
|
|
|
|
|
|
_lastScreen = new Vector2Int(Screen.width, Screen.height);
|
|
|
|
|
|
_lastMirror = s.mirrorLeftHanded;
|
|
|
|
|
|
|
|
|
|
|
|
// Safe Area 는 SafeAreaFitter 가 주인 — 없을 때만 루트를 스트레치로 정규화한다.
|
|
|
|
|
|
if (GetComponent<SafeAreaFitter>() == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_rt.anchorMin = Vector2.zero; _rt.anchorMax = Vector2.one;
|
|
|
|
|
|
_rt.offsetMin = Vector2.zero; _rt.offsetMax = Vector2.zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float u = ComputeUnitsPerPx(s);
|
|
|
|
|
|
LastUnitsPerPx = u;
|
|
|
|
|
|
|
|
|
|
|
|
var cards = target.skillCards;
|
|
|
|
|
|
int total = cards != null ? cards.Length : 0;
|
2026-09-15 04:49:23 +00:00
|
|
|
|
// 🔴 WL-816u ③ — PD 「우선 엑티브 스킬은 사용 Off 해줘」. 잠금이 걸려 있으면 활성 슬롯 0
|
|
|
|
|
|
// = 스킬 버튼 4칸이 전부 비활성(아래 SetActive(isSkill)). 되돌리기는 설정 값 하나.
|
|
|
|
|
|
int want = WL.Combat.Auto.ActiveSkillLock.Locked ? 0 : s.activeSkillSlots;
|
|
|
|
|
|
int active = Mathf.Clamp(want, 0, total);
|
2026-09-08 15:17:58 +00:00
|
|
|
|
LastActiveSlots = active;
|
|
|
|
|
|
LastReserveSlots = Mathf.Max(0, total - active);
|
|
|
|
|
|
|
2026-09-08 22:58:46 +00:00
|
|
|
|
float maxReach = 0f, actionReach = 0f;
|
2026-09-08 15:17:58 +00:00
|
|
|
|
var centers = new Vector2[total];
|
|
|
|
|
|
|
2026-09-08 22:58:46 +00:00
|
|
|
|
// WL-813y — 하단 메뉴가 보이는 동안만 패드를 위로 올린다(전투 중에는 모서리 원점).
|
|
|
|
|
|
bool menuVisible = HudCombatVisibility.BottomMenuVisible;
|
|
|
|
|
|
LastBottomMenuVisible = menuVisible;
|
|
|
|
|
|
|
2026-09-08 15:17:58 +00:00
|
|
|
|
for (int i = 0; i < total; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var card = cards[i];
|
|
|
|
|
|
if (card == null) continue;
|
|
|
|
|
|
var crt = card.transform as RectTransform;
|
|
|
|
|
|
if (crt == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
bool isSkill = i < active;
|
2026-09-08 22:58:46 +00:00
|
|
|
|
Vector2 px = isSkill ? s.FanSlotPx(i, menuVisible) : s.ReserveSlotPx(i - active, menuVisible);
|
2026-09-08 15:17:58 +00:00
|
|
|
|
float dia = isSkill ? s.slotDiameterPx : s.reserveDiameterPx;
|
|
|
|
|
|
|
|
|
|
|
|
PlaceFromCorner(crt, px, dia, u, s.mirrorLeftHanded);
|
|
|
|
|
|
centers[i] = px;
|
|
|
|
|
|
maxReach = Mathf.Max(maxReach, px.magnitude + dia * 0.5f);
|
2026-09-08 22:58:46 +00:00
|
|
|
|
if (isSkill) actionReach = Mathf.Max(actionReach, px.magnitude + dia * 0.5f);
|
2026-09-08 15:17:58 +00:00
|
|
|
|
|
|
|
|
|
|
// 4 활성 · 나머지는 물약/회피(813j/813r) 예약 자리 = 비활성
|
|
|
|
|
|
if (card.gameObject.activeSelf != isSkill) card.gameObject.SetActive(isSkill);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 공격 버튼 · 자동전투 토글
|
|
|
|
|
|
var attack = FindChild(attackButtonName);
|
|
|
|
|
|
if (attack != null)
|
|
|
|
|
|
{
|
2026-09-08 22:58:46 +00:00
|
|
|
|
Vector2 apx = s.AttackCenterPxFor(menuVisible);
|
|
|
|
|
|
PlaceFromCorner(attack, apx, s.attackDiameterPx, u, s.mirrorLeftHanded);
|
|
|
|
|
|
maxReach = Mathf.Max(maxReach, apx.magnitude + s.attackDiameterPx * 0.5f);
|
|
|
|
|
|
actionReach = Mathf.Max(actionReach, apx.magnitude + s.attackDiameterPx * 0.5f);
|
2026-09-08 15:17:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
var auto = FindChild(autoButtonName);
|
|
|
|
|
|
if (auto != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
PlaceFromCorner(auto, s.autoButtonCenterPx, s.autoButtonDiameterPx, u, s.mirrorLeftHanded);
|
|
|
|
|
|
maxReach = Mathf.Max(maxReach, s.autoButtonCenterPx.magnitude + s.autoButtonDiameterPx * 0.5f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LastMaxReachPx = maxReach;
|
|
|
|
|
|
LastMinGapPx = MinGapPx(s, centers, active, total);
|
|
|
|
|
|
|
2026-09-08 17:13:35 +00:00
|
|
|
|
// 813tj 물약 버튼 — 예약 슬롯 자리에 있으므로 미러·해상도가 바뀌면 같이 다시 앉힌다.
|
|
|
|
|
|
var potion = GetComponentInChildren<PotionButton>(true);
|
2026-09-08 22:58:46 +00:00
|
|
|
|
if (potion != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
potion.ApplyLayout();
|
|
|
|
|
|
Vector2 ppx = s.ReserveSlotPx(Mathf.Max(0, PotionSlotIndex()), menuVisible);
|
|
|
|
|
|
actionReach = Mathf.Max(actionReach, ppx.magnitude + s.reserveDiameterPx * 0.5f);
|
|
|
|
|
|
}
|
|
|
|
|
|
LastActionReachPx = actionReach;
|
2026-09-08 17:13:35 +00:00
|
|
|
|
|
2026-09-08 15:17:58 +00:00
|
|
|
|
return "applied slots=" + active + "/" + total + " unitsPerPx=" + u.ToString("F4") +
|
2026-09-08 22:58:46 +00:00
|
|
|
|
" maxReachPx=" + maxReach.ToString("F1") +
|
|
|
|
|
|
" actionReachPx=" + actionReach.ToString("F1") + "(스킬+공격+물약 · 자동토글 제외)" +
|
|
|
|
|
|
" minGapPx=" + LastMinGapPx.ToString("F1") +
|
|
|
|
|
|
" menuVisible=" + menuVisible + " fanOrigin=" + s.FanOriginPxFor(menuVisible) +
|
2026-09-08 15:17:58 +00:00
|
|
|
|
" mirror=" + s.mirrorLeftHanded;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 22:58:46 +00:00
|
|
|
|
private static int PotionSlotIndex()
|
|
|
|
|
|
{
|
|
|
|
|
|
var su = WLSurvivalUiSettings.Instance;
|
|
|
|
|
|
return su != null ? su.potionReserveSlotIndex : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 17:13:35 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 모서리(우하단 · 미러면 좌하단) 기준 (dx, dy) px 로 배치한다.
|
|
|
|
|
|
/// 813tj 물약 버튼(PotionButton)이 예약 슬롯 자리에 앉을 때 **같은 산식**을 쓰도록 public 이다.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void PlaceFromCorner(RectTransform rt, Vector2 px, float diameterPx, float unitsPerPx, bool mirror)
|
2026-09-08 15:17:58 +00:00
|
|
|
|
{
|
|
|
|
|
|
Vector2 anchor = new Vector2(mirror ? 0f : 1f, 0f);
|
|
|
|
|
|
rt.anchorMin = anchor;
|
|
|
|
|
|
rt.anchorMax = anchor;
|
|
|
|
|
|
rt.pivot = new Vector2(0.5f, 0.5f);
|
|
|
|
|
|
float sx = mirror ? px.x : -px.x;
|
|
|
|
|
|
rt.anchoredPosition = new Vector2(sx * unitsPerPx, px.y * unitsPerPx);
|
|
|
|
|
|
rt.sizeDelta = new Vector2(diameterPx * unitsPerPx, diameterPx * unitsPerPx);
|
|
|
|
|
|
rt.localScale = Vector3.one;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>이웃 슬롯 중심 거리 − 지름 = 실제 여백(px). 기준서 §B 요소3 ≥16 검증용.</summary>
|
|
|
|
|
|
private static float MinGapPx(WLHudLayoutSettings s, Vector2[] centers, int active, int total)
|
|
|
|
|
|
{
|
|
|
|
|
|
float min = float.MaxValue;
|
|
|
|
|
|
for (int i = 0; i < total; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int j = i + 1; j < total; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
float ri = (i < active ? s.slotDiameterPx : s.reserveDiameterPx) * 0.5f;
|
|
|
|
|
|
float rj = (j < active ? s.slotDiameterPx : s.reserveDiameterPx) * 0.5f;
|
|
|
|
|
|
float gap = Vector2.Distance(centers[i], centers[j]) - ri - rj;
|
|
|
|
|
|
if (gap < min) min = gap;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return min == float.MaxValue ? 0f : min;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>px → 캔버스 유닛 계수. 산식은 WLHudLayoutSettings 가 갖는다(보스 바와 같은 것을 쓴다).</summary>
|
|
|
|
|
|
public float ComputeUnitsPerPx(WLHudLayoutSettings s)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_canvas == null) _canvas = GetComponentInParent<Canvas>(true);
|
|
|
|
|
|
return s.UnitsPerPx(_canvas);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private RectTransform FindChild(string childName)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(childName)) return null;
|
|
|
|
|
|
for (int i = 0; i < transform.childCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var c = transform.GetChild(i);
|
|
|
|
|
|
if (c.name == childName) return c as RectTransform;
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── 검증·디버그 전용 ──────────────────────────────────────────────────
|
|
|
|
|
|
/// <summary>런타임 미러 토글(로드된 설정 인스턴스만 바꾼다 — .asset 파일은 건드리지 않는다).</summary>
|
|
|
|
|
|
public string SetMirror(bool mirror)
|
|
|
|
|
|
{
|
|
|
|
|
|
var s = WLHudLayoutSettings.Instance;
|
|
|
|
|
|
if (s == null) return "WLHudLayoutSettings 에셋 없음";
|
|
|
|
|
|
s.mirrorLeftHanded = mirror;
|
|
|
|
|
|
return Apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>현재 배치 덤프(슬롯별 앵커·좌표·크기 · px 환산). 발주서 ⓑ 증거용.</summary>
|
|
|
|
|
|
public string Dump()
|
|
|
|
|
|
{
|
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
var s = WLHudLayoutSettings.Instance;
|
|
|
|
|
|
float u = LastUnitsPerPx > 0f ? LastUnitsPerPx : (s != null ? ComputeUnitsPerPx(s) : 1f);
|
|
|
|
|
|
sb.AppendLine("[WLBattlePadLayout] unitsPerPx=" + u.ToString("F4") +
|
|
|
|
|
|
" mirror=" + (s != null ? s.mirrorLeftHanded.ToString() : "?") +
|
|
|
|
|
|
" activeSlots=" + LastActiveSlots + "/" + (LastActiveSlots + LastReserveSlots) +
|
|
|
|
|
|
" maxReachPx=" + LastMaxReachPx.ToString("F1") +
|
|
|
|
|
|
" (목표 " + (s != null ? s.thumbReachRadiusPx.ToString("F0") : "?") + ")" +
|
2026-09-08 22:58:46 +00:00
|
|
|
|
" actionReachPx=" + LastActionReachPx.ToString("F1") + "(자동토글 제외)" +
|
|
|
|
|
|
" menuVisible=" + LastBottomMenuVisible +
|
|
|
|
|
|
" fanOrigin=" + (s != null ? s.FanOriginPxFor(LastBottomMenuVisible).ToString() : "?") +
|
|
|
|
|
|
" attackCenter=" + (s != null ? s.AttackCenterPxFor(LastBottomMenuVisible).ToString() : "?") +
|
2026-09-08 15:17:58 +00:00
|
|
|
|
" minGapPx=" + LastMinGapPx.ToString("F1"));
|
|
|
|
|
|
sb.AppendLine(" root " + RectLine(_rt != null ? _rt : GetComponent<RectTransform>()) +
|
|
|
|
|
|
" safeAreaFitter=" + (GetComponent<SafeAreaFitter>() != null));
|
|
|
|
|
|
|
|
|
|
|
|
var ui = target != null ? target : GetComponent<BattleUI>();
|
|
|
|
|
|
if (ui != null && ui.skillCards != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < ui.skillCards.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var c = ui.skillCards[i];
|
|
|
|
|
|
if (c == null) { sb.AppendLine(" slot" + i + " : null"); continue; }
|
|
|
|
|
|
var crt = c.transform as RectTransform;
|
|
|
|
|
|
sb.AppendLine(" slot" + i + " " + c.name + " active=" + c.gameObject.activeSelf +
|
|
|
|
|
|
" " + RectLine(crt) + " " + PxLine(crt, u));
|
|
|
|
|
|
sb.AppendLine(" 쿨링 " + CoolRingLine(c));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var n in new[] { attackButtonName, autoButtonName, "Avoid", "Equip" })
|
|
|
|
|
|
{
|
|
|
|
|
|
var t = FindChild(n);
|
|
|
|
|
|
sb.AppendLine(" " + n + (t == null ? " : 없음"
|
|
|
|
|
|
: " active=" + t.gameObject.activeSelf + " " + RectLine(t) + " " + PxLine(t, u)));
|
|
|
|
|
|
}
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>쿨 링 실측 — SkillCard 원본의 i_cooltime(Filled/Radial360)이 배치 뒤에도 유효한지(발주서 ⓑ "쿨 링").</summary>
|
|
|
|
|
|
private static string CoolRingLine(SkillCard card)
|
|
|
|
|
|
{
|
|
|
|
|
|
var img = card != null ? card.sprite_cooltime : null;
|
|
|
|
|
|
if (img == null) return "sprite_cooltime 없음";
|
|
|
|
|
|
var irt = img.rectTransform;
|
|
|
|
|
|
return img.gameObject.name + " type=" + img.type + " fillMethod=" + img.fillMethod +
|
|
|
|
|
|
" origin=" + img.fillOrigin + " cw=" + img.fillClockwise + " amount=" + img.fillAmount.ToString("F3") +
|
|
|
|
|
|
" active=" + img.gameObject.activeInHierarchy +
|
|
|
|
|
|
" aMin" + irt.anchorMin + " aMax" + irt.anchorMax + " size" + irt.sizeDelta +
|
|
|
|
|
|
" · 구동 = PCActor.cs:91 Set_CoolTime → CardCoolTimeBase.Set_CoolTimeText";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string RectLine(RectTransform rt)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (rt == null) return "(rt 없음)";
|
|
|
|
|
|
return "aMin" + rt.anchorMin + " aMax" + rt.anchorMax + " pos" + rt.anchoredPosition +
|
|
|
|
|
|
" size" + rt.sizeDelta + " piv" + rt.pivot + " scl" + (Vector2)(Vector3)rt.localScale;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string PxLine(RectTransform rt, float u)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (rt == null || u <= 0f) return "";
|
|
|
|
|
|
return "→ px(dx=" + Mathf.Abs(rt.anchoredPosition.x / u).ToString("F1") +
|
|
|
|
|
|
", dy=" + (rt.anchoredPosition.y / u).ToString("F1") +
|
|
|
|
|
|
", d=" + (rt.sizeDelta.x / u).ToString("F1") + ")";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|