Merge branch 'wl/ui/WL-814n-chibi-pc'
This commit is contained in:
commit
2d83d05a58
|
|
@ -0,0 +1,177 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WL814n_Build.cs — `Assets/Res_Addr/PC/LH_M05.prefab` 조립 (에디터 전용 · 발주서 WL-814n §1-2)
|
||||
//
|
||||
// M05(Little Heroes RedKnight) 모델을 본체로 하고 `Ai01` 의 컴포넌트 구성·직렬화 값을 그대로 이식한다.
|
||||
// 🔴 원본 `Ai01.prefab` 과 `Assets/Suriyun/**` 은 **읽기만** 한다(수정 0).
|
||||
//
|
||||
// 하는 일
|
||||
// 1. M05 프리팹을 인스턴스화 → 언팩(원본 연결 끊기) → 이름 LH_M05
|
||||
// 2. 레이어 3 전체 적용(Ai01 실측: 223 중 222 가 L3)
|
||||
// 3. Animator: 아바타 = M05 자신(Humanoid) · 컨트롤러·applyRootMotion·cullingMode 는 Ai01 과 동일 배선
|
||||
// (런타임에 `PCActor.Set_Obj()` 가 pcanim_* 로 갈아끼운다)
|
||||
// 4. Ai01 루트의 WizardActor · NavMeshAgent · Rigidbody · CapsuleCollider · SkinnedMeshAfterImage 를
|
||||
// ComponentUtility 로 값 복사
|
||||
// 5. 무기 소켓 7개를 Ai01 과 **같은 본 경로**에 같은 로컬 TRS 로 생성 → WizardActor.tfs_weapon 재배선
|
||||
// 6. WLPcScaleCompensator 부착(월드 높이 1.191 m 유지)
|
||||
// 7. 팩 기본 장착 검 `Sword_M05` 비활성(게임의 Change_Weapon 이 소켓에 무기를 꽂는다)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditorInternal;
|
||||
using WL.Character;
|
||||
|
||||
public static class WL814n_Build
|
||||
{
|
||||
const string AI01 = "Assets/Res_Addr/PC/Ai01.prefab";
|
||||
const string M05 = "Assets/Suriyun/Characters/RedKnight/Prefab/M05/M05.prefab";
|
||||
const string OUT = "Assets/Res_Addr/PC/LH_M05.prefab";
|
||||
|
||||
// Ai01 실측(PROBE1): 소켓 이름 · 부모 본 경로(루트 제외) · 로컬 TRS
|
||||
struct Socket { public string name, parentPath; public Vector3 pos, scale; public Quaternion rot; public int layer; }
|
||||
|
||||
static Transform FindPath(Transform root, string path)
|
||||
{
|
||||
var t = root;
|
||||
foreach (var seg in path.Split('/'))
|
||||
{
|
||||
t = t.Find(seg);
|
||||
if (t == null) return null;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static void SetLayerAll(GameObject go, int layer)
|
||||
{
|
||||
foreach (var t in go.GetComponentsInChildren<Transform>(true)) t.gameObject.layer = layer;
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var ai01Pf = AssetDatabase.LoadAssetAtPath<GameObject>(AI01);
|
||||
var m05Pf = AssetDatabase.LoadAssetAtPath<GameObject>(M05);
|
||||
if (ai01Pf == null || m05Pf == null) { Debug.LogError("[WL-814n] 원본 프리팹을 찾지 못함"); return; }
|
||||
|
||||
// ── 1) Ai01 을 읽기 전용으로 인스턴스화해 소켓 정보를 실측 채집
|
||||
var ai = (GameObject)PrefabUtility.InstantiatePrefab(ai01Pf);
|
||||
ai.transform.localScale = Vector3.one;
|
||||
var aiActor = ai.GetComponent<PCActor>();
|
||||
var socks = new List<Socket>();
|
||||
foreach (var tf in aiActor.tfs_weapon)
|
||||
{
|
||||
// 루트 이름을 뺀 부모 경로
|
||||
var parts = new List<string>();
|
||||
var p = tf.parent;
|
||||
while (p != null && p != ai.transform) { parts.Insert(0, p.name); p = p.parent; }
|
||||
socks.Add(new Socket
|
||||
{
|
||||
name = tf.name,
|
||||
parentPath = string.Join("/", parts.ToArray()),
|
||||
pos = tf.localPosition,
|
||||
rot = tf.localRotation,
|
||||
scale = tf.localScale,
|
||||
layer = tf.gameObject.layer
|
||||
});
|
||||
}
|
||||
sb.AppendLine("Ai01 소켓 채집 " + socks.Count + "/7");
|
||||
|
||||
// ── 2) M05 인스턴스화 + 언팩
|
||||
var go = (GameObject)PrefabUtility.InstantiatePrefab(m05Pf);
|
||||
PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
|
||||
go.name = "LH_M05";
|
||||
go.transform.position = Vector3.zero;
|
||||
go.transform.rotation = Quaternion.identity;
|
||||
go.transform.localScale = Vector3.one;
|
||||
SetLayerAll(go, ai.layer); // Ai01 = Layer 3
|
||||
go.tag = ai.tag; // Untagged
|
||||
|
||||
// ── 3) 팩 기본 장착 검 비활성(게임의 Change_Weapon 이 소켓에 꽂는다)
|
||||
var packSword = FindPath(go.transform, "Root_M/RootPart1_M/Spine1_M/Chest_M/Scapula_R/Shoulder_R/Elbow_R/Wrist_R/Sword_parentR/Sword_M05");
|
||||
if (packSword != null) { packSword.gameObject.SetActive(false); sb.AppendLine("팩 기본 검 Sword_M05 비활성"); }
|
||||
|
||||
// ── 4) 무기 소켓 7개를 같은 본 경로에 생성
|
||||
var newSockets = new Transform[socks.Count];
|
||||
for (int i = 0; i < socks.Count; i++)
|
||||
{
|
||||
var s = socks[i];
|
||||
var parent = FindPath(go.transform, s.parentPath);
|
||||
if (parent == null) { Debug.LogError("[WL-814n] M05 에 본 경로 없음: " + s.parentPath); sb.AppendLine("MISSING " + s.parentPath); continue; }
|
||||
var n = new GameObject(s.name);
|
||||
n.transform.SetParent(parent, false);
|
||||
n.transform.localPosition = s.pos;
|
||||
n.transform.localRotation = s.rot;
|
||||
n.transform.localScale = s.scale;
|
||||
n.layer = s.layer;
|
||||
newSockets[i] = n.transform;
|
||||
sb.AppendLine(string.Format("소켓 {0} {1} → {2}", i, s.name, s.parentPath));
|
||||
}
|
||||
|
||||
// ── 5) Animator 를 Ai01 과 같은 배선으로 (아바타만 M05 자신 것)
|
||||
var aiAnim = ai.GetComponent<Animator>();
|
||||
var anim = go.GetComponent<Animator>();
|
||||
anim.runtimeAnimatorController = aiAnim.runtimeAnimatorController; // 런타임에 pcanim_* 로 교체된다
|
||||
anim.applyRootMotion = aiAnim.applyRootMotion; // false
|
||||
anim.updateMode = aiAnim.updateMode;
|
||||
anim.cullingMode = aiAnim.cullingMode;
|
||||
sb.AppendLine("Animator avatar=" + anim.avatar.name + " isHuman=" + anim.avatar.isHuman
|
||||
+ " ctrl=" + (anim.runtimeAnimatorController ? anim.runtimeAnimatorController.name : "null")
|
||||
+ " rootMotion=" + anim.applyRootMotion);
|
||||
|
||||
// ── 6) Ai01 루트 컴포넌트 값 복사(Transform/Animator 제외)
|
||||
foreach (var c in ai.GetComponents<Component>())
|
||||
{
|
||||
if (c is Transform || c is Animator) continue;
|
||||
ComponentUtility.CopyComponent(c);
|
||||
var existing = go.GetComponent(c.GetType());
|
||||
if (existing != null) ComponentUtility.PasteComponentValues(existing);
|
||||
else ComponentUtility.PasteComponentAsNew(go);
|
||||
sb.AppendLine("컴포넌트 이식 " + c.GetType().Name);
|
||||
}
|
||||
|
||||
// ── 7) tfs_weapon 재배선 (복사된 참조는 Ai01 것이므로 반드시 덮어쓴다)
|
||||
var actor = go.GetComponent<PCActor>();
|
||||
actor.tfs_weapon = newSockets;
|
||||
int ok = 0;
|
||||
foreach (var t in actor.tfs_weapon) if (t != null && t.IsChildOf(go.transform)) ok++;
|
||||
sb.AppendLine("tfs_weapon 배선 " + ok + "/7 (전부 LH_M05 하위인가)");
|
||||
|
||||
// ── 8) 크기 보정 컴포넌트
|
||||
var comp = go.GetComponent<WLPcScaleCompensator>();
|
||||
if (comp == null) comp = go.AddComponent<WLPcScaleCompensator>();
|
||||
float kComp = comp.Compensation;
|
||||
sb.AppendLine("WLPcScaleCompensator 부착 (보정 " + kComp.ToString("F4") + ")");
|
||||
|
||||
// ── 8-b) 🔴 CapsuleCollider 재보정 (프로브 실측으로 발견)
|
||||
// 콜라이더는 루트에 붙어 있어 루트 스케일(0.7 × k)을 그대로 받는다.
|
||||
// Ai01 값을 그대로 쓰면 월드 크기가 k 배(=1.5배) 커진다 → 로컬 값을 k 로 나눠
|
||||
// 월드 크기를 Ai01(h 1.106 · r 0.385 · centerY 0.553)과 **동일**하게 맞춘다.
|
||||
// (NavMeshAgent 의 radius/height 는 트랜스폼 스케일을 받지 않으므로 Ai01 값 그대로 둔다.)
|
||||
var aiCc = ai.GetComponent<CapsuleCollider>();
|
||||
var cc = go.GetComponent<CapsuleCollider>();
|
||||
if (cc != null && aiCc != null && kComp > 0f)
|
||||
{
|
||||
cc.radius = aiCc.radius / kComp;
|
||||
cc.height = aiCc.height / kComp;
|
||||
cc.center = aiCc.center / kComp;
|
||||
sb.AppendLine(string.Format("CapsuleCollider 재보정 r {0:F4}→{1:F4} h {2:F4}→{3:F4} centerY {4:F4}→{5:F4} (월드는 Ai01 과 동일)",
|
||||
aiCc.radius, cc.radius, aiCc.height, cc.height, aiCc.center.y, cc.center.y));
|
||||
}
|
||||
|
||||
// ── 9) 저장
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(OUT));
|
||||
var saved = PrefabUtility.SaveAsPrefabAsset(go, OUT, out bool success);
|
||||
sb.AppendLine("저장 " + OUT + " success=" + success);
|
||||
|
||||
UnityEngine.Object.DestroyImmediate(go);
|
||||
UnityEngine.Object.DestroyImmediate(ai);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
System.IO.File.WriteAllText("AgentScripts/staging/WL814n/BUILD.txt", sb.ToString(), Encoding.UTF8);
|
||||
Debug.Log("[WL-814n] BUILD\n" + sb);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13b0aeca987980646af87711964339c8
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -13,7 +13,7 @@ public class PCInfo : MonoBehaviourSingletonTemplate<PCInfo>
|
|||
var pctable = table_classconfig.Ins.Get_Data_orNull(pcid);
|
||||
var costumeid = sdata.Get_EqiupmentEquip(eItem.PCCostume);
|
||||
var costumetable = table_costumelist.Ins.Get_Data_orNull(costumeid);
|
||||
AddrResourceMgr.Ins.LoadObject<GameObject>($"Assets/Res_Addr/PC/{costumetable.s_Prefab}.prefab", handle =>
|
||||
AddrResourceMgr.Ins.LoadObject<GameObject>($"Assets/Res_Addr/PC/{WL.Character.WLCharacterSwapSettings.Resolve(costumetable.s_Prefab)}.prefab", handle =>
|
||||
{
|
||||
if (handle.IsDone && handle.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bda3a1571b6bb244693953ba9f558dd3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLCharacterSwapSettings.cs — 플레이어 캐릭터(PC) 프리팹 교체의 단일 출처(SOT · C45)
|
||||
//
|
||||
// PD 결정 #814 (2026-09-12) 「1. 바꿔. 2. 붉은 기사 M05로 해」
|
||||
// 발주서 WL-814n · 조사서 `도트_아트풍_달성안_v1.md` §C① (실측 근거 전부)
|
||||
//
|
||||
// ■ 왜 (전부 실측 · `AgentScripts/staging/WL814n/PROBE1.txt`)
|
||||
// 현 PC `Ai01` = 높이 1.7017 m · 턱(Neck_M) 1.2783 → 머리 0.3098 m → **머리:키 5.49**
|
||||
// `M05`(RedKnight) = 높이 1.1316 m · 턱 0.6560 → 머리 0.4439 m → **머리:키 2.55**
|
||||
// 도트A(픽셀 높이 240)에서 머리 픽셀 **7.7 px → 16.5 px (+116 %)** = PD 참고(2D 도트 RPG)의 16~24 px 대역.
|
||||
//
|
||||
// ■ 어떻게 (원본 수정 = PCInfo.cs 1줄이 상한 · 조사서 §C① ⓒ안)
|
||||
// 인게임 PC 생성 지점은 단 한 곳 `Assets/Script/Info/PCInfo.cs:16`
|
||||
// LoadObject<GameObject>($"Assets/Res_Addr/PC/{costumetable.s_Prefab}.prefab", …)
|
||||
// 여기서 프리팹 **이름만** 이 클래스가 갈아끼운다. Addressables 그룹 `PC.asset` 엔트리가
|
||||
// 폴더 1개(주소 = 경로)라 같은 폴더에 프리팹을 두면 주소가 생긴다 → **Addressables 수정 0**.
|
||||
//
|
||||
// ■ 크기는 왜 테이블(ClassConfig.f_Scale)이 아니라 프리팹인가 — 🔴 되돌리기(C8) 때문이다
|
||||
// `PCActor.cs:324` 가 `transform.localScale = m_ClassData.f_Scale`(12행 전부 0.7)를 대입한다.
|
||||
// f_Scale 을 1.0525 로 바꾸면 M05 는 1.191 m 로 맞지만 **스위치를 꺼서 Ai01 로 돌아갔을 때
|
||||
// Ai01 이 1.79 m 가 되어 원본 100 % 가 깨진다**(그리고 테이블은 xlsm 재익스포트로 날아간다).
|
||||
// 그래서 보정은 **새 프리팹에만 붙는 `WLPcScaleCompensator`** 가 한다 → 테이블 수정 0 ·
|
||||
// 스위치를 끄면 Ai01 은 손도 대지 않은 원본 그대로다.
|
||||
//
|
||||
// 에셋 경로(고정): Assets/WL/Settings/Resources/WL/WLCharacterSwapSettings.asset
|
||||
// C8 롤백: 에셋이 없거나 enabled = false → `Resolve` 가 원본 문자열을 그대로 돌려준다 = 무동작.
|
||||
//
|
||||
// 🔴 원본 프리팹 `Ai01` · `Assets/Suriyun/**` 은 고치지 않는다(발주서 §2 금지 · 참조만).
|
||||
// 🔴 어셈블리 주의: Assets/WL/Character/ 에 .asmdef 를 만들지 말 것.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.Character
|
||||
{
|
||||
[CreateAssetMenu(fileName = "WLCharacterSwapSettings", menuName = "WL/Character Swap Settings", order = 331)]
|
||||
public sealed class WLCharacterSwapSettings : ScriptableObject
|
||||
{
|
||||
public const string ResourcesPath = "WL/WLCharacterSwapSettings";
|
||||
|
||||
static WLCharacterSwapSettings s_cached;
|
||||
static bool s_lookupDone;
|
||||
|
||||
/// <summary>설정 에셋(1회 로드 후 캐시). 없으면 null = 무동작.</summary>
|
||||
public static WLCharacterSwapSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!s_lookupDone) { s_cached = Resources.Load<WLCharacterSwapSettings>(ResourcesPath); s_lookupDone = true; }
|
||||
return s_cached;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>QA·A/B 전용 런타임 스위치. 0 = 에셋의 enabled · 1 = 강제 on · -1 = 강제 off.</summary>
|
||||
public static int RuntimeOverride;
|
||||
|
||||
/// <summary>교체가 살아 있는가. false 면 원본 프리팹 이름이 그대로 나간다(C8).</summary>
|
||||
public static bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
var i = Instance;
|
||||
if (i == null || RuntimeOverride < 0) return false;
|
||||
return RuntimeOverride > 0 || i.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>테스트용: 캐시를 비운다.</summary>
|
||||
public static void ClearCache() { s_cached = null; s_lookupDone = false; }
|
||||
|
||||
[Header("전체 스위치 (PD 되돌리기 1순위)")]
|
||||
[Tooltip("끄면 원본 코스튬 프리팹 이름이 그대로 나간다 = 원본 100 %. 에셋을 지워도 같다.")]
|
||||
public bool enabled = true;
|
||||
|
||||
[Tooltip("교체·보정이 일어날 때 Debug.Log 를 남긴다(A/B 확인용). 기본 끔.")]
|
||||
public bool verboseLog;
|
||||
|
||||
[Header("교체 대상")]
|
||||
[Tooltip("이 이름의 코스튬 프리팹만 교체한다. 비우면 모든 코스튬을 교체한다. 기본 코스튬 110001 = \"Ai01\".")]
|
||||
public string sourcePrefabName = "Ai01";
|
||||
|
||||
[Tooltip("대신 쓸 프리팹 이름(Assets/Res_Addr/PC/<이름>.prefab). 기본 \"LH_M05\"(Little Heroes RedKnight).")]
|
||||
public string pcPrefabName = "LH_M05";
|
||||
|
||||
[Header("크기 보정 (WLPcScaleCompensator 가 읽는다)")]
|
||||
[Tooltip("새 프리팹 루트 스케일에 곱하는 값. M05 원 높이 1.1316 m 를 Ai01 원 높이 1.7017 m 로 맞춘다 → 1.7017/1.1316 = 1.5038.\n" +
|
||||
"그러면 인게임(f_Scale 0.7) 1.1912 m · 로비(scale 1) 1.7017 m 로 Ai01 과 완전히 같아진다 = 카메라·콜라이더·NavMesh·도트 픽셀 수 전부 유지.")]
|
||||
public float heightCompensation = 1.5038f;
|
||||
|
||||
/// <summary>
|
||||
/// 인게임 PC 코스튬 프리팹 이름을 결정한다. 스위치가 꺼져 있으면 <paramref name="original"/> 를 그대로 돌려준다.
|
||||
/// 원본 `PCInfo.cs:16` 이 부르는 유일한 진입점.
|
||||
/// </summary>
|
||||
public static string Resolve(string original)
|
||||
{
|
||||
if (!Enabled) return original;
|
||||
var i = Instance;
|
||||
if (i == null || string.IsNullOrEmpty(i.pcPrefabName)) return original;
|
||||
if (!string.IsNullOrEmpty(i.sourcePrefabName) && original != i.sourcePrefabName) return original;
|
||||
if (i.verboseLog) Debug.Log("[WL-814n] PC 프리팹 교체: " + original + " → " + i.pcPrefabName);
|
||||
return i.pcPrefabName;
|
||||
}
|
||||
|
||||
/// <summary>크기 보정 배수(스위치가 꺼져 있으면 1 = 무보정).</summary>
|
||||
public static float HeightCompensation
|
||||
{
|
||||
get
|
||||
{
|
||||
var i = Instance;
|
||||
if (!Enabled || i == null || i.heightCompensation <= 0f) return 1f;
|
||||
return i.heightCompensation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb1f68cba364f334ba9a64e80163650d
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLPcScaleCompensator.cs — 치비 PC 프리팹의 월드 높이를 Ai01 과 똑같이 유지한다
|
||||
//
|
||||
// 발주서 WL-814n §1-4 「f_Scale 재계산으로 월드 높이 1.191 m 유지」
|
||||
//
|
||||
// ■ 문제
|
||||
// 원본 `PCActor.Set_Obj()` 가 루트 스케일을 **대입**한다(원본 `PCActor.cs:318-325` 실측):
|
||||
// 로비 : transform.localScale = Vector3.one → 1.0
|
||||
// 인게임 : transform.localScale = m_ClassData.f_Scale → 0.7 (ClassConfig 12행 전부)
|
||||
// M05 원 높이는 1.1316 m 라 그대로 두면 인게임 0.792 m · 로비 1.132 m 로 작아진다.
|
||||
//
|
||||
// ■ 왜 여기(프리팹 컴포넌트)에서 고치나 — 되돌리기(C8)와 원본 1줄 상한 때문이다
|
||||
// · 테이블 `ClassConfig.f_Scale` 을 바꾸면 스위치를 껐을 때 Ai01 까지 1.79 m 가 된다(원본 100 % 깨짐).
|
||||
// · `PCActor.cs:324` 에 훅을 하나 더 넣으면 원본 수정이 2줄이 되어 발주서 상한(1줄)을 넘는다.
|
||||
// · 이 컴포넌트는 **새 프리팹 `LH_M05` 에만** 붙는다 → Ai01 경로는 코드·데이터 모두 무변경.
|
||||
//
|
||||
// ■ 어떻게 (멱등 · 누적 곱 아님)
|
||||
// 원본이 루트 스케일에 새 값을 대입하면(로비 1.0 / 인게임 0.7) LateUpdate 가 그것을 **원 값**으로 보고
|
||||
// `원 값 × heightCompensation` 을 다시 대입한다. 자기가 쓴 값은 기억해 두고 건너뛰므로 매 프레임 곱해지지 않는다.
|
||||
// 스케일은 애니메이션이 건드리지 않으므로(Humanoid 는 위치·회전만 쓴다) LateUpdate 대입으로 충분하다.
|
||||
//
|
||||
// ■ 실측 결과 (AgentScripts/staging/WL814n/)
|
||||
// 1.1316 m × 1.5038 = 1.7017 m(= Ai01 원 높이) → × 0.7 = **1.1912 m**(811s 실측 PC 키와 동일)
|
||||
//
|
||||
// 🔴 루트 스케일을 쓰는 이유: Hips 가 `Root_M` = 루트의 직속 자식이라, Hips 이하를 스케일하면
|
||||
// Humanoid 리타깃이 매 프레임 쓰는 Hips 위치와 어긋나 발이 땅을 뚫는다(PROBE2 실측).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.Character
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class WLPcScaleCompensator : MonoBehaviour
|
||||
{
|
||||
[Tooltip("비워 두면 WLCharacterSwapSettings.heightCompensation 을 쓴다. 0 보다 크면 이 값이 우선(프리팹 단위 예외용).")]
|
||||
public float overrideCompensation;
|
||||
|
||||
float _lastWritten = float.NaN;
|
||||
|
||||
/// <summary>지금 적용 중인 보정 배수. 스위치가 꺼져 있으면 1.</summary>
|
||||
public float Compensation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (overrideCompensation > 0f) return overrideCompensation;
|
||||
return WLCharacterSwapSettings.HeightCompensation;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable() { _lastWritten = float.NaN; Apply(); }
|
||||
|
||||
void LateUpdate() { Apply(); }
|
||||
|
||||
void Apply()
|
||||
{
|
||||
float k = Compensation;
|
||||
if (k <= 0f) return;
|
||||
|
||||
float cur = transform.localScale.x;
|
||||
// 자기가 마지막으로 쓴 값이면 원본이 아직 안 건드린 것 = 할 일 없음(멱등).
|
||||
if (!float.IsNaN(_lastWritten) && Mathf.Abs(cur - _lastWritten) <= 1e-5f) return;
|
||||
|
||||
float target = cur * k;
|
||||
_lastWritten = target;
|
||||
transform.localScale = new Vector3(target, target, target);
|
||||
|
||||
var s = WLCharacterSwapSettings.Instance;
|
||||
if (s != null && s.verboseLog)
|
||||
Debug.Log(string.Format("[WL-814n] PC 크기 보정: {0:F4} × {1:F4} = {2:F4} ({3})", cur, k, target, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 79b4c36538bcbfd468d09fd300e9152a
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fb1f68cba364f334ba9a64e80163650d, type: 3}
|
||||
m_Name: WLCharacterSwapSettings
|
||||
m_EditorClassIdentifier: Assembly-CSharp::WL.Character.WLCharacterSwapSettings
|
||||
enabled: 1
|
||||
verboseLog: 0
|
||||
sourcePrefabName: Ai01
|
||||
pcPrefabName: LH_M05
|
||||
heightCompensation: 1.5038
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e89d89f71681bb54a84233c263acf2ce
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue