using UnityEngine; using UnityEditor; using UnityEngine.UIElements; using UnityEditor.UIElements; [CustomEditor(typeof(FingerShapedController))] public class FingerShapedControllerEditor : Editor { private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss"; private static readonly string[] fingerPropNames = { "ThumbCurl", "IndexCurl", "MiddleCurl", "RingCurl", "PinkyCurl" }; private static readonly string[] fingerKoreanNames = { "엄지", "검지", "중지", "약지", "새끼" }; private FingerShapedController controller; public override VisualElement CreateInspectorGUI() { controller = target as FingerShapedController; if (controller == null) return new VisualElement(); var root = new VisualElement(); var commonUss = AssetDatabase.LoadAssetAtPath(CommonUssPath); if (commonUss != null) root.styleSheets.Add(commonUss); // 활성화 토글 var enabledProp = serializedObject.FindProperty("m_Enabled"); var enableToggle = new PropertyField(enabledProp, "손가락 제어 활성화"); root.Add(enableToggle); // 왼손 var leftFoldout = new Foldout { text = "왼손", value = true }; leftFoldout.Add(BuildHandControls("left")); root.Add(leftFoldout); // 오른손 var rightFoldout = new Foldout { text = "오른손", value = true }; rightFoldout.Add(BuildHandControls("right")); root.Add(rightFoldout); // 프리셋 버튼 root.Add(BuildPresetButtons()); return root; } private VisualElement BuildHandControls(string prefix) { var container = new VisualElement(); container.style.backgroundColor = new Color(0, 0, 0, 0.08f); container.style.borderTopLeftRadius = container.style.borderTopRightRadius = container.style.borderBottomLeftRadius = container.style.borderBottomRightRadius = 4; container.style.paddingTop = container.style.paddingBottom = container.style.paddingLeft = container.style.paddingRight = 6; // 헤더: 활성화 토글 + 초기화 버튼 var header = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center, marginBottom = 4 } }; var handEnabledProp = serializedObject.FindProperty($"{prefix}HandEnabled"); header.Add(new PropertyField(handEnabledProp, "제어 활성화") { style = { flexGrow = 1 } }); var resetBtn = new Button(() => ResetHandValues(prefix)) { text = "초기화" }; resetBtn.style.width = 60; header.Add(resetBtn); container.Add(header); // 손가락 슬라이더 (가로 배치) var slidersRow = new VisualElement { style = { flexDirection = FlexDirection.Row, justifyContent = Justify.Center, marginTop = 4 } }; for (int i = 0; i < fingerPropNames.Length; i++) { var fingerProp = serializedObject.FindProperty($"{prefix}{fingerPropNames[i]}"); slidersRow.Add(BuildVerticalSlider(fingerKoreanNames[i], fingerProp)); } container.Add(slidersRow); // 벌리기 슬라이더 var spreadProp = serializedObject.FindProperty($"{prefix}SpreadFingers"); var spreadSlider = new Slider("벌리기", -1f, 1f) { showInputField = true }; spreadSlider.BindProperty(spreadProp); spreadSlider.style.marginTop = 8; container.Add(spreadSlider); // 비활성 시 숨기기 container.TrackPropertyValue(handEnabledProp, prop => { slidersRow.style.display = prop.boolValue ? DisplayStyle.Flex : DisplayStyle.None; spreadSlider.style.display = prop.boolValue ? DisplayStyle.Flex : DisplayStyle.None; }); slidersRow.style.display = handEnabledProp.boolValue ? DisplayStyle.Flex : DisplayStyle.None; spreadSlider.style.display = handEnabledProp.boolValue ? DisplayStyle.Flex : DisplayStyle.None; return container; } private VisualElement BuildVerticalSlider(string label, SerializedProperty prop) { var column = new VisualElement { style = { alignItems = Align.Center, width = 45, marginLeft = 2, marginRight = 2 } }; column.Add(new Label(label) { style = { fontSize = 10, color = new Color(0.6f, 0.6f, 0.6f) } }); var valueLabel = new Label(prop.floatValue.ToString("F1")) { style = { fontSize = 10, color = new Color(0.6f, 0.6f, 0.6f) } }; column.Add(valueLabel); // UI Toolkit Slider in vertical mode (direction: Vertical 대신 세로용 Slider 사용) // SliderDirection.Vertical 사용 var slider = new Slider(-1f, 1f) { direction = SliderDirection.Vertical }; slider.style.height = 100; slider.style.width = 25; slider.BindProperty(prop); slider.RegisterValueChangedCallback(evt => valueLabel.text = evt.newValue.ToString("F1")); // 초기값 동기화 column.TrackPropertyValue(prop, p => valueLabel.text = p.floatValue.ToString("F1")); column.Add(slider); return column; } private VisualElement BuildPresetButtons() { var container = new VisualElement { style = { marginTop = 10 } }; container.Add(new Label("손 모양 프리셋") { style = { unityFontStyleAndWeight = FontStyle.Bold, marginBottom = 4 } }); string[,] presets = { { "가위", "바위", "보" }, { "브이", "검지", "초기화" } }; for (int row = 0; row < 2; row++) { var btnRow = new VisualElement { style = { flexDirection = FlexDirection.Row, justifyContent = Justify.Center, marginBottom = 4 } }; for (int col = 0; col < 3; col++) { string presetName = presets[row, col]; var btn = new Button(() => ApplyPreset(presetName)) { text = presetName }; btn.style.height = 30; btn.style.width = 100; btn.style.marginLeft = btn.style.marginRight = 4; btnRow.Add(btn); } container.Add(btnRow); } return container; } private void ResetHandValues(string prefix) { serializedObject.Update(); string[] props = { "ThumbCurl", "IndexCurl", "MiddleCurl", "RingCurl", "PinkyCurl", "SpreadFingers" }; foreach (var prop in props) serializedObject.FindProperty($"{prefix}{prop}").floatValue = 0f; serializedObject.ApplyModifiedProperties(); } private void ApplyPreset(string presetName) { if (!controller.enabled) controller.enabled = true; switch (presetName) { case "가위": SetPreset(1f, 1f, -1f, -1f, -1f, 0.3f); break; case "바위": SetPreset(-1f, -1f, -1f, -1f, -1f, 0f); break; case "보": SetPreset(1f, 1f, 1f, 1f, 1f, 1f); break; case "브이": SetPreset(-1f, 1f, 1f, -1f, -1f, 1f); break; case "검지": SetPreset(-1f, 1f, -1f, -1f, -1f, 0f); break; case "초기화": SetPreset(0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f); break; } } private void SetPreset(float thumb, float index, float middle, float ring, float pinky, float spread) { if (controller.leftHandEnabled) { controller.leftThumbCurl = thumb; controller.leftIndexCurl = index; controller.leftMiddleCurl = middle; controller.leftRingCurl = ring; controller.leftPinkyCurl = pinky; controller.leftSpreadFingers = spread; } if (controller.rightHandEnabled) { controller.rightThumbCurl = thumb; controller.rightIndexCurl = index; controller.rightMiddleCurl = middle; controller.rightRingCurl = ring; controller.rightPinkyCurl = pinky; controller.rightSpreadFingers = spread; } EditorUtility.SetDirty(controller); } }