2025-06-08 00:55:10 +09:00

292 lines
12 KiB
C#

#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
namespace Bitd
{
public class FunctionAdder : EditorWindow
{
AnimatorController animatorController;
string layerName = string.Empty;
string parameterName = string.Empty;
List<AnimationClip> animationClips = new List<AnimationClip>(); // List로 변경하여 동적으로 관리
AnimationClip onAnimationClip = null; // On 애니메이션
AnimationClip offAnimationClip = null; // Off 애니메이션
bool isOnOffMode = false; // 온오프 모드 여부를 결정하는 변수
private bool isHair = false;
private bool isClothes = false;
[MenuItem("Bitd/애니메이터 기능 등록", false, 51)]
public static void ShowWindow()
{
GetWindow<FunctionAdder>("뜌땨뜌~");
}
void OnGUI()
{
GUILayout.Label("기능 등록 툴", EditorStyles.boldLabel);
// 애니메이터 선택 필드
animatorController = (AnimatorController)EditorGUILayout.ObjectField("타겟 애니메이터", animatorController, typeof(AnimatorController), false);
isHair = EditorGUILayout.Toggle("헤어인가요?", isHair);
isClothes = EditorGUILayout.Toggle("옷인가요?", isClothes);
GUILayout.Space(5);
layerName = EditorGUILayout.TextField("레이어 이름", layerName);
parameterName = EditorGUILayout.TextField("파라미터 이름", parameterName);
GUILayout.Space(5);
if (isHair)
{
layerName = "Hair Change";
parameterName = "HairIndex";
}
else if (isClothes)
{
layerName = "Clothes Change";
parameterName = "ClothesIndex";
}
isOnOffMode = EditorGUILayout.Toggle("온오프인가요?", isOnOffMode);
// 온오프 모드에 따른 UI 처리
if (isOnOffMode)
{
// 온오프 모드일 때 On, Off 애니메이션 선택 영역
onAnimationClip = (AnimationClip)EditorGUILayout.ObjectField("On 애니메이션", onAnimationClip, typeof(AnimationClip), false);
offAnimationClip = (AnimationClip)EditorGUILayout.ObjectField("Off 애니메이션", offAnimationClip, typeof(AnimationClip), false);
}
else
{
// 드래그 앤 드롭 구역 생성
GUILayout.Space(10);
EditorGUILayout.HelpBox("애니메이션 클립을 드래그하여 추가하세요.", MessageType.Info);
Rect dropArea = GUILayoutUtility.GetRect(0, 50, GUILayout.ExpandWidth(true));
GUI.Box(dropArea, "여기에 넣어주세요", EditorStyles.helpBox);
HandleDragAndDrop(dropArea);
// 드래그된 애니메이션 클립 표시
GUILayout.Label("추가된 애니메이션 클립:", EditorStyles.boldLabel);
for (int i = 0; i < animationClips.Count; i++)
{
EditorGUILayout.ObjectField(animationClips[i], typeof(AnimationClip), false);
}
}
if (GUILayout.Button("적용"))
{
if (animatorController != null)
{
if (isOnOffMode && onAnimationClip != null && offAnimationClip != null)
{
AddLayerAndSetupOnOffAnimations(animatorController, layerName, onAnimationClip, offAnimationClip, parameterName);
}
else if (!isOnOffMode && animationClips.Count > 0)
{
AddLayerAndSetupAnimations(animatorController, layerName, animationClips.ToArray(), parameterName);
animationClips = new List<AnimationClip>();
}
else
{
Debug.LogWarning("애니메이터나 애니메이션 클립이 부족합니다.");
}
}
}
}
void HandleDragAndDrop(Rect dropArea)
{
Event evt = Event.current;
switch (evt.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!dropArea.Contains(evt.mousePosition))
return;
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
if (draggedObject is AnimationClip)
{
animationClips.Add((AnimationClip)draggedObject); // 애니메이션 클립 추가
}
}
evt.Use();
}
break;
}
}
// 온오프 애니메이션 설정
void AddLayerAndSetupOnOffAnimations(AnimatorController animatorController, string layerName, AnimationClip onClip, AnimationClip offClip, string parameterName)
{
// 레이어가 존재하는지 확인
AnimatorControllerLayer targetLayer = null;
foreach (var layer in animatorController.layers)
{
if (layer.name == layerName)
{
targetLayer = layer;
break;
}
}
// 레이어가 없으면 새로 생성
if (targetLayer == null)
{
targetLayer = new AnimatorControllerLayer
{
name = layerName,
stateMachine = new AnimatorStateMachine(),
defaultWeight = 1
};
animatorController.AddLayer(targetLayer);
targetLayer.stateMachine.name = $"{layerName}_StateMachine";
// 생성한 stateMachine을 애셋으로 저장
AssetDatabase.AddObjectToAsset(targetLayer.stateMachine, animatorController);
}
else if (targetLayer.stateMachine == null) // 기존 레이어가 있지만 stateMachine이 없으면 새로 생성
{
targetLayer.stateMachine = new AnimatorStateMachine();
targetLayer.stateMachine.name = $"{layerName}_StateMachine";
AssetDatabase.AddObjectToAsset(targetLayer.stateMachine, animatorController);
}
// 애셋을 저장하여 유니티 에디터가 변경사항을 잃지 않도록 보장
AssetDatabase.SaveAssets();
// StateMachine 참조
AnimatorStateMachine stateMachine = targetLayer.stateMachine;
// 파라미터가 있는지 확인하고 없으면 생성 (bool 타입)
if (!HasParameter(animatorController, parameterName))
{
animatorController.AddParameter(parameterName, AnimatorControllerParameterType.Bool);
}
// On 상태 추가
AnimatorState onState = stateMachine.AddState(onClip.name);
onState.motion = onClip;
// Off 상태 추가
AnimatorState offState = stateMachine.AddState(offClip.name);
offState.motion = offClip;
// On에서 Off로의 트랜지션 추가 (false일 때)
AnimatorStateTransition onToOffTransition = onState.AddTransition(offState);
onToOffTransition.exitTime = 0;
onToOffTransition.hasExitTime = false;
onToOffTransition.hasFixedDuration = false;
onToOffTransition.duration = 0;
onToOffTransition.AddCondition(AnimatorConditionMode.IfNot, 0, parameterName); // 파라미터가 false일 때
// Off에서 On으로의 트랜지션 추가 (true일 때)
AnimatorStateTransition offToOnTransition = offState.AddTransition(onState);
offToOnTransition.exitTime = 0;
offToOnTransition.hasExitTime = false;
offToOnTransition.hasFixedDuration = false;
offToOnTransition.duration = 0;
offToOnTransition.AddCondition(AnimatorConditionMode.If, 0, parameterName); // 파라미터가 true일 때
Debug.Log("On/Off 애니메이션 세팅 완료.");
}
void AddLayerAndSetupAnimations(AnimatorController animatorController, string layerName, AnimationClip[] animationClips, string parameterName)
{
// 레이어가 존재하는지 확인
AnimatorControllerLayer targetLayer = null;
foreach (var layer in animatorController.layers)
{
if (layer.name == layerName)
{
targetLayer = layer;
break;
}
}
// 레이어가 없으면 새로 생성
if (targetLayer == null)
{
targetLayer = new AnimatorControllerLayer
{
name = layerName,
stateMachine = new AnimatorStateMachine(),
defaultWeight = 1
};
animatorController.AddLayer(targetLayer);
targetLayer.stateMachine.name = $"{layerName}_StateMachine";
// 생성한 stateMachine을 애셋으로 저장
AssetDatabase.AddObjectToAsset(targetLayer.stateMachine, animatorController);
}
else if (targetLayer.stateMachine == null) // 기존 레이어가 있지만 stateMachine이 없으면 새로 생성
{
targetLayer.stateMachine = new AnimatorStateMachine();
targetLayer.stateMachine.name = $"{layerName}_StateMachine";
AssetDatabase.AddObjectToAsset(targetLayer.stateMachine, animatorController);
}
// 애셋을 저장하여 유니티 에디터가 변경사항을 잃지 않도록 보장
AssetDatabase.SaveAssets();
// Any State로부터의 전환을 위한 StateMachine 참조
AnimatorStateMachine stateMachine = targetLayer.stateMachine;
// 파라미터가 있는지 확인하고 없으면 생성
if (!HasParameter(animatorController, parameterName))
{
animatorController.AddParameter(parameterName, AnimatorControllerParameterType.Int);
}
// 기존 레이어의 애니메이션 상태 개수 확인
int existingStateCount = stateMachine.states.Length;
// 애니메이션 상태 생성 및 설정
for (int i = 0; i < animationClips.Length; i++)
{
AnimationClip clip = animationClips[i];
// 애니메이션 상태 추가
AnimatorState state = stateMachine.AddState(clip.name);
state.motion = clip;
// Any State에서 해당 애니메이션 상태로 전환 추가
AnimatorStateTransition transition = stateMachine.AddAnyStateTransition(state);
transition.exitTime = 0;
transition.hasExitTime = false;
transition.hasFixedDuration = false;
transition.duration = 0;
// 기존 상태 개수를 고려하여 인덱스를 설정
transition.AddCondition(AnimatorConditionMode.Equals, existingStateCount + i, parameterName);
}
Debug.Log("Layer and animations successfully set up.");
}
// 파라미터가 이미 있는지 확인하는 함수
bool HasParameter(AnimatorController animatorController, string paramName)
{
foreach (var param in animatorController.parameters)
{
if (param.name == paramName)
{
return true;
}
}
return false;
}
}
}
#endif