DO-36 자식 요소 색상 설정 인스펙터 커스터마이징

- FioChildColorEditor
- 부모 요소에 스크립트 할당하여 자식 UI 요소 색상 인스펙터 원터지 변경 가능
This commit is contained in:
fiore 2025-03-14 16:04:06 +09:00
parent 848d92b263
commit 2a7b193cee
4 changed files with 417 additions and 6 deletions

View File

@ -58,7 +58,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 0} m_Material: {fileID: 0}
m_Color: {r: 0.17254902, g: 0.21568628, b: 0.34901962, a: 1} m_Color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1
@ -133,7 +133,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 0} m_Material: {fileID: 0}
m_Color: {r: 0.17254902, g: 0.21568628, b: 0.34901962, a: 1} m_Color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1
@ -160,6 +160,7 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 4060305112283542636} - component: {fileID: 4060305112283542636}
- component: {fileID: 8984618795075575334} - component: {fileID: 8984618795075575334}
- component: {fileID: 2222382815855860034}
m_Layer: 5 m_Layer: 5
m_Name: Timer m_Name: Timer
m_TagString: Untagged m_TagString: Untagged
@ -208,6 +209,45 @@ MonoBehaviour:
headCapImage: {fileID: 3995031286537022070} headCapImage: {fileID: 3995031286537022070}
tailCapImage: {fileID: 3282082939413405386} tailCapImage: {fileID: 3282082939413405386}
timeText: {fileID: 1414465240440161498} timeText: {fileID: 1414465240440161498}
--- !u!114 &2222382815855860034
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5197632138137602266}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2eb8d899eaaa7614cbb7b1fdb98d0dd7, type: 3}
m_Name:
m_EditorClassIdentifier:
colorSettings:
- targetObject: {fileID: 8836467620212376791}
componentType: Image
color: {r: 1, g: 1, b: 1, a: 1}
applyToChildren: 0
colorableComponent: {fileID: 4727671169278371324}
- targetObject: {fileID: 3197710723148271819}
componentType: Image
color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
applyToChildren: 0
colorableComponent: {fileID: 337344169386659086}
- targetObject: {fileID: 6184671321993608803}
componentType: TMP_Text
color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
applyToChildren: 0
colorableComponent: {fileID: 1414465240440161498}
- targetObject: {fileID: 880875562942959157}
componentType: Image
color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
applyToChildren: 0
colorableComponent: {fileID: 3995031286537022070}
- targetObject: {fileID: 8065228685685210519}
componentType: Image
color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
applyToChildren: 0
colorableComponent: {fileID: 3282082939413405386}
autoDetectChildren: 1
--- !u!1 &6184671321993608803 --- !u!1 &6184671321993608803
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -282,8 +322,8 @@ MonoBehaviour:
m_fontMaterials: [] m_fontMaterials: []
m_fontColor32: m_fontColor32:
serializedVersion: 2 serializedVersion: 2
rgba: 4284036908 rgba: 4289522718
m_fontColor: {r: 0.17254902, g: 0.21568628, b: 0.34901962, a: 1} m_fontColor: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
m_enableVertexGradient: 0 m_enableVertexGradient: 0
m_colorMode: 3 m_colorMode: 3
m_fontColorGradient: m_fontColorGradient:
@ -400,7 +440,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 0} m_Material: {fileID: 0}
m_Color: {r: 0.17254902, g: 0.21568628, b: 0.34901962, a: 1} m_Color: {r: 0.119200125, g: 0.9245283, b: 0.67288977, a: 1}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1
@ -475,7 +515,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 0} m_Material: {fileID: 0}
m_Color: {r: 0.9490196, g: 0.9490196, b: 0.9490196, a: 1} m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8268e93b195495ebd68dffa2b3b5aaa
timeCreated: 1741935635

View File

@ -0,0 +1,357 @@
using UnityEngine;
using System.Collections.Generic;
using TMPro;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Linq;
#endif
// 하위 요소들의 색상을 인스펙터에서 수정할 수 있게 해주는 컴포넌트
public class FioChildColorEditor : MonoBehaviour
{
// 인스펙터에서 수정할 색상 정보
[System.Serializable]
public class ColorSettings
{
public GameObject targetObject; // 직접 오브젝트 참조
public string componentType; // 컴포넌트 타입 (읽기 전용)
public Color color = Color.white; // 적용할 색상
public bool applyToChildren = false; // 해당 요소의 모든 하위 요소에도 적용할지 여부
[HideInInspector]
public Component colorableComponent; // 색상을 적용할 컴포넌트 참조
}
// 인스펙터에서 편집할 색상 목록
public List<ColorSettings> colorSettings = new List<ColorSettings>();
// 자동 감지 옵션
public bool autoDetectChildren = true;
// 지원되는 컴포넌트 유형들
private static readonly System.Type[] supportedTypes = new System.Type[]
{
typeof(Renderer),
typeof(SpriteRenderer),
typeof(UnityEngine.UI.Image),
typeof(UnityEngine.UI.RawImage),
typeof(UnityEngine.UI.Text),
typeof(TMP_Text)
};
// 초기화 시 하위 요소 자동 감지
private void OnValidate()
{
if (autoDetectChildren)
{
DetectChildComponents();
}
// 모든 항목에 대해 컴포넌트 타입 업데이트
UpdateComponentTypes();
}
// 하위 요소 자동 감지
public void DetectChildComponents()
{
// 현재 목록을 유지할 오브젝트들
HashSet<GameObject> existingObjects = new HashSet<GameObject>();
foreach (var setting in colorSettings)
{
if (setting.targetObject != null)
{
existingObjects.Add(setting.targetObject);
}
}
// 모든 자식 오브젝트 검색
List<ColorSettings> newSettings = new List<ColorSettings>();
foreach (Transform child in transform)
{
// 이미 목록에 있는 오브젝트는 건너뛰기
if (existingObjects.Contains(child.gameObject))
{
continue;
}
// 지원되는 컴포넌트 찾기
Component colorableComponent = FindColorableComponent(child.gameObject);
if (colorableComponent != null)
{
ColorSettings setting = new ColorSettings
{
targetObject = child.gameObject,
colorableComponent = colorableComponent,
color = GetCurrentColor(colorableComponent)
};
newSettings.Add(setting);
}
}
// 새로운 항목 추가 (기존 항목은 유지)
colorSettings.AddRange(newSettings);
// 컴포넌트 타입 업데이트
UpdateComponentTypes();
}
// 컴포넌트 타입 문자열 업데이트
private void UpdateComponentTypes()
{
foreach (var setting in colorSettings)
{
if (setting.targetObject != null)
{
// 컴포넌트 찾기
Component comp = setting.colorableComponent;
if (comp == null)
{
comp = FindColorableComponent(setting.targetObject);
setting.colorableComponent = comp;
}
if (comp != null)
{
setting.componentType = GetComponentTypeName(comp);
}
else
{
setting.componentType = "지원되지 않음";
}
}
else
{
setting.componentType = "없음";
}
}
}
// 컴포넌트 타입 이름 얻기
private string GetComponentTypeName(Component component)
{
if (component is Renderer) return "Renderer";
if (component is SpriteRenderer) return "SpriteRenderer";
if (component is UnityEngine.UI.Image) return "Image";
if (component is UnityEngine.UI.RawImage) return "RawImage";
if (component is UnityEngine.UI.Text) return "Text";
if (component is TMP_Text) return "TMP_Text";
return component.GetType().Name;
}
// 색상을 적용할 수 있는 컴포넌트 찾기
private Component FindColorableComponent(GameObject obj)
{
foreach (var type in supportedTypes)
{
Component comp = obj.GetComponent(type);
if (comp != null)
{
return comp;
}
}
return null;
}
// 현재 색상 가져오기
private Color GetCurrentColor(Component component)
{
if (component is Renderer renderer)
{
return renderer.material.color;
}
else if (component is SpriteRenderer spriteRenderer)
{
return spriteRenderer.color;
}
else if (component is UnityEngine.UI.Graphic graphic)
{
return graphic.color;
}
else if (component is TMP_Text tmpText)
{
return tmpText.color;
}
return Color.white;
}
// 색상을 적용하는 함수
public void ApplyColors()
{
foreach (var setting in colorSettings)
{
if (setting.targetObject != null)
{
ApplyColorToObject(setting.targetObject, setting.color, setting.applyToChildren);
}
}
}
// 특정 오브젝트에 색상 적용
private void ApplyColorToObject(GameObject obj, Color color, bool applyToChildren)
{
// 렌더러
Renderer renderer = obj.GetComponent<Renderer>();
if (renderer != null)
{
renderer.material.color = color;
}
// 스프라이트 렌더러
SpriteRenderer spriteRenderer = obj.GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.color = color;
}
// UI 이미지
UnityEngine.UI.Image image = obj.GetComponent<UnityEngine.UI.Image>();
if (image != null)
{
image.color = color;
}
// UI 로우 이미지
UnityEngine.UI.RawImage rawImage = obj.GetComponent<UnityEngine.UI.RawImage>();
if (rawImage != null)
{
rawImage.color = color;
}
// UI 텍스트
UnityEngine.UI.Text text = obj.GetComponent<UnityEngine.UI.Text>();
if (text != null)
{
text.color = color;
}
// TextMeshPro 텍스트
TMP_Text tmpText = obj.GetComponent<TMP_Text>();
if (tmpText != null)
{
tmpText.color = color;
}
// 하위 요소에도 재귀적으로 색상 적용
if (applyToChildren)
{
foreach (Transform child in obj.transform)
{
ApplyColorToObject(child.gameObject, color, true);
}
}
}
}
#if UNITY_EDITOR
// 에디터 인스펙터 커스터마이징
[CustomEditor(typeof(FioChildColorEditor))]
public class ChildColorEditorInspector : Editor
{
private SerializedProperty colorSettingsProperty;
private SerializedProperty autoDetectChildrenProperty;
private void OnEnable()
{
colorSettingsProperty = serializedObject.FindProperty("colorSettings");
autoDetectChildrenProperty = serializedObject.FindProperty("autoDetectChildren");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
FioChildColorEditor colorEditor = (FioChildColorEditor)target;
// 자동 감지 옵션
EditorGUILayout.PropertyField(autoDetectChildrenProperty, new GUIContent("자동 하위 요소 감지"));
// 새로고침 버튼
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("하위 요소 새로 감지", GUILayout.Height(30)))
{
colorEditor.DetectChildComponents();
serializedObject.Update();
}
if (GUILayout.Button("목록 초기화", GUILayout.Height(30)))
{
colorSettingsProperty.ClearArray();
colorEditor.DetectChildComponents();
serializedObject.Update();
}
EditorGUILayout.EndHorizontal();
// 구분선 추가
EditorGUILayout.Space();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
// 목록 타이틀
EditorGUILayout.LabelField("하위 요소 색상 설정", EditorStyles.boldLabel);
// 각 항목 표시
for (int i = 0; i < colorSettingsProperty.arraySize; i++)
{
SerializedProperty itemProperty = colorSettingsProperty.GetArrayElementAtIndex(i);
SerializedProperty targetObjectProperty = itemProperty.FindPropertyRelative("targetObject");
SerializedProperty componentTypeProperty = itemProperty.FindPropertyRelative("componentType");
SerializedProperty colorProperty = itemProperty.FindPropertyRelative("color");
SerializedProperty applyToChildrenProperty = itemProperty.FindPropertyRelative("applyToChildren");
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// 왼쪽에 오브젝트 선택 필드, 오른쪽에 컴포넌트 타입 표시
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(targetObjectProperty, GUIContent.none, GUILayout.ExpandWidth(true));
GUI.enabled = false;
EditorGUILayout.TextField(componentTypeProperty.stringValue, GUILayout.Width(100));
GUI.enabled = true;
if (GUILayout.Button("✕", GUILayout.Width(20)))
{
colorSettingsProperty.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
break;
}
EditorGUILayout.EndHorizontal();
// 색상과 하위 요소 적용 옵션
EditorGUILayout.PropertyField(colorProperty);
EditorGUILayout.PropertyField(applyToChildrenProperty, new GUIContent("하위 요소에도 적용"));
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
// 항목 추가 버튼
if (GUILayout.Button("항목 추가"))
{
colorSettingsProperty.arraySize++;
serializedObject.ApplyModifiedProperties();
}
// 구분선 추가
EditorGUILayout.Space();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
EditorGUILayout.Space();
// 색상 적용 버튼 추가
if (GUILayout.Button("모든 색상 적용하기", GUILayout.Height(40)))
{
colorEditor.ApplyColors();
// 씬 변경 사항 저장
EditorUtility.SetDirty(target);
if (!Application.isPlaying)
{
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
}
serializedObject.ApplyModifiedProperties();
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2eb8d899eaaa7614cbb7b1fdb98d0dd7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: