대화중 표정 수정
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
// 선택한 AnimatorController에 대화용 슬롯 state(DlgSlotA / DlgSlotB)와 플레이스홀더 클립을 심는다.
|
||||
// 슬롯 2개 = 부드러운 블렌드(핑퐁). 이후 ExpressionData / GestureData의 AnimClip만 채우면
|
||||
// 컨트롤러를 다시 열 필요 없이 그 클립이 해당 레이어의 슬롯에서 재생된다. (DialogPlayer 참고)
|
||||
//
|
||||
// Setup은 매번 기존 Dlg 슬롯을 싹 지우고 새로 만든다 → 몇 번을 돌려도 정확히 (레이어당 2개)만 남는다.
|
||||
// 사용법: 프로젝트 창에서 .controller를 하나 이상 선택 → Tools/Dialog/Setup ....
|
||||
public static class DialogAnimSlotSetup
|
||||
{
|
||||
private const string SlotStatePrefix = "DlgSlot"; // 슬롯 state 이름: DlgSlotA / DlgSlotB
|
||||
private const string ClipPrefix = "__DlgSlot_"; // 플레이스홀더 클립 이름 접두사
|
||||
private static string SlotClipName(int layer, char slot) => $"{ClipPrefix}{layer}_{slot}";
|
||||
|
||||
// 슬롯을 심을 레이어: 0(Body/제스처), 1(Face/표정). 레이어가 없으면 건너뜀.
|
||||
private static readonly int[] TargetLayers = { 0, 1 };
|
||||
private static readonly char[] Slots = { 'A', 'B' }; // 2개 = 블렌드(핑퐁)
|
||||
|
||||
[MenuItem("Tools/Dialog/Setup Expression·Gesture Slots (Selected Controllers)")]
|
||||
private static void SetupSelected()
|
||||
{
|
||||
var controllers = Selection.GetFiltered<AnimatorController>(SelectionMode.Assets);
|
||||
if (controllers.Length == 0)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Dialog Slots",
|
||||
"프로젝트 창에서 AnimatorController(.controller)를 하나 이상 선택한 뒤 실행하세요.", "확인");
|
||||
return;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
foreach (var ac in controllers)
|
||||
{
|
||||
RemoveSlots(ac); // 기존 슬롯/고아 클립 정리
|
||||
total += CreateSlots(ac); // 새로 생성
|
||||
EditorUtility.SetDirty(ac);
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
EditorUtility.DisplayDialog("Dialog Slots",
|
||||
$"{controllers.Length}개 컨트롤러 정리 후 재생성 — 슬롯 state {total}개.", "확인");
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Dialog/Remove Expression·Gesture Slots (Selected Controllers)")]
|
||||
private static void RemoveSelected()
|
||||
{
|
||||
var controllers = Selection.GetFiltered<AnimatorController>(SelectionMode.Assets);
|
||||
if (controllers.Length == 0) return;
|
||||
|
||||
foreach (var ac in controllers)
|
||||
{
|
||||
RemoveSlots(ac);
|
||||
EditorUtility.SetDirty(ac);
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
EditorUtility.DisplayDialog("Dialog Slots", $"{controllers.Length}개 컨트롤러에서 Dlg 슬롯 제거 완료.", "확인");
|
||||
}
|
||||
|
||||
// Dlg 슬롯 state(모든 레이어)와 __DlgSlot_* 플레이스홀더 클립(중복·고아 포함)을 전부 제거
|
||||
private static void RemoveSlots(AnimatorController ac)
|
||||
{
|
||||
foreach (var layer in ac.layers)
|
||||
{
|
||||
var sm = layer.stateMachine;
|
||||
if (sm == null) continue;
|
||||
foreach (var cs in sm.states) // sm.states는 복사본 → 순회 중 제거 안전
|
||||
{
|
||||
if (cs.state != null && cs.state.name.StartsWith(SlotStatePrefix))
|
||||
sm.RemoveState(cs.state);
|
||||
}
|
||||
}
|
||||
|
||||
string path = AssetDatabase.GetAssetPath(ac);
|
||||
foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(path))
|
||||
{
|
||||
if (obj is AnimationClip clip && clip.name.StartsWith(ClipPrefix))
|
||||
{
|
||||
AssetDatabase.RemoveObjectFromAsset(clip);
|
||||
Object.DestroyImmediate(clip, allowDestroyingAssets: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int CreateSlots(AnimatorController ac)
|
||||
{
|
||||
int added = 0;
|
||||
var layers = ac.layers;
|
||||
foreach (int layer in TargetLayers)
|
||||
{
|
||||
if (layer >= layers.Length) continue;
|
||||
var sm = layers[layer].stateMachine;
|
||||
|
||||
// 레이어의 WriteDefaultValues 관습을 그대로 따라간다 (한 레이어에서 WD 혼용 시 경고 방지)
|
||||
bool wd = sm.states.Length == 0 || sm.states[0].state.writeDefaultValues;
|
||||
|
||||
foreach (char slot in Slots)
|
||||
{
|
||||
// 슬롯마다 고유한 빈 클립을 물려야 개별적으로 오버라이드된다 (컨트롤러의 서브 에셋으로 저장)
|
||||
var clip = new AnimationClip { name = SlotClipName(layer, slot) };
|
||||
AssetDatabase.AddObjectToAsset(clip, ac);
|
||||
|
||||
var st = sm.AddState(SlotStatePrefix + slot);
|
||||
st.motion = clip;
|
||||
st.writeDefaultValues = wd;
|
||||
added++;
|
||||
}
|
||||
}
|
||||
return added;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecafb1ca75b469f4cae493c26c20a725
|
||||
Reference in New Issue
Block a user