Get it on Google Play


Wm뮤 :: 'Unity' 카테고리의 글 목록 (22 Page)

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
전자과 게임프로그래머 (퇴사함)
2022.3.22f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2020. 6. 29. 10:11 Unity/shader

스프라이트 쉐이더 작성시에 볼수 있는 에러 문구이다

 

 

         _StencilComp ("Stencil Comparison", Float) = 8
         _Stencil ("Stencil ID", Float) = 0
         _StencilOp ("Stencil Operation", Float) = 0
         _StencilWriteMask ("Stencil Write Mask", Float) = 255
         _StencilReadMask ("Stencil Read Mask", Float) = 255
         _ColorMask ("Color Mask", Float) = 15

프로퍼티에 이걸 넣는다

 

 


		Stencil
		{
			Ref[_Stencil]
			Comp[_StencilComp]
			Pass[_StencilOp]
			ReadMask[_StencilReadMask]
			WriteMask[_StencilWriteMask]
		}
		ColorMask[_ColorMask]

에러를 지우는 것뿐만이 아닌, 스텐실 기능도 활성화 하려면 이 코드도 서브쉐이더에 넣는다

 

 

 

참조

https://answers.unity.com/questions/980924/ui-mask-with-shader.html

'Unity > shader' 카테고리의 다른 글

유니티 쉐이더 인스펙터  (0) 2021.02.21
스텐실  (0) 2021.01.20
자주쓰는 유니티 쉐이더 코드모음  (0) 2020.11.04
posted by 모카쨩
2020. 6. 25. 10:43 Unity

http://ko.esotericsoftware.com/spine-unity-download

위 링크에서 플러그인을 다운받는다

 

 

 

필요한파일

캐릭터.atlas.txt

캐릭터.json

캐릭터.png

 

없으면 기본랩터를 써도 전혀 문제없다

더보기

랩터위치

 

 

 

마테리얼을 먼저 만든다

 

그다음 우클릭해서 두개를 만든다

스파인 아틀라스는 아틀라스 파일과 방금 만든 매터리얼

 

 

스켈레톤 데이터는 json과 아틀라스를 넣는다

 

하이라키에서 스켈레톤 애니메이션을 넣는다

 

 

애니메이션 체크하고 루프를 넣는다

 

 

빌드해보면 잘된다

'Unity' 카테고리의 다른 글

유니티 로그캣  (0) 2020.06.29
인풋필드 엔터누르면 초기화  (0) 2020.05.31
SQLlite 브라우저 사용방법  (0) 2020.05.24
posted by 모카쨩
2020. 5. 31. 22:02 Unity

 

 

 

이렇게 하면 코드없이도 초기화된다 

'Unity' 카테고리의 다른 글

스파인 사용법  (0) 2020.06.25
SQLlite 브라우저 사용방법  (0) 2020.05.24
유용한 에셋 모음  (0) 2020.05.20
posted by 모카쨩
2020. 5. 24. 23:59 Unity/C#

 

https://www.sqlite.org/download.html

여기서 sqlite를 다운받는다

아래거 다운받으면 된다 32비트는 쓰이지 않으니까

 

C:\Program Files\Unity\Editor\Data\Mono\lib\mono\2.0

혹은

C:\Program Files\Unity\Hub\Editor\2019.4.1f1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit

여기에 있는 Mono.Data.Sqlite.dll을 Plugins 폴더에 집어넣고 (굵은 글씨는 현재 유니티 버전)

 

위에서 다운받은 sqlite3.def와 sqlite3.dll도 풀어서 넣는다

그리고 sqllite브라우저로 만든 DB파일도 넣어주면 최종적으로 아래처럼 된다

 

 

V2

 

 

v3

 

 

 

안드로이드도 사용할경우 아까 링크에서 하단의 것도 다운받는다

 

 

 

7-Zip으로 푼다

 

 

 

Android하위에 넣고 이름을 

상기와 같이 수정한다

 

SampleDB.db
0.01MB

그리고

 

 

 

기동시 메모리를 1.0~1.5GB정도 사용한다

 

그냥 이거 써라

SQLite3.unitypackage
1.85MB

 

 

 

 

그리고 옛날기술이라 이제는 더이상 쓰이지 않기는 한다

'Unity > C#' 카테고리의 다른 글

Parent of RectTransform is being set with parent property  (0) 2020.06.29
유니티 커스텀 인스펙터  (0) 2020.05.19
유니티 어트리뷰트  (0) 2020.05.19
posted by 모카쨩
2020. 5. 24. 22:39 Unity

 

 

 

 

 

SQLlite 다운로드 주소

https://www.sqlite.org/download.html

SQLlite 브라우저 다운로드 주소

https://sqlitebrowser.org/dl/#windows

 

'Unity' 카테고리의 다른 글

스파인 사용법  (0) 2020.06.25
인풋필드 엔터누르면 초기화  (0) 2020.05.31
유용한 에셋 모음  (0) 2020.05.20
posted by 모카쨩
2020. 5. 20. 14:41 Unity

 

 

Virtual Plug and Play Joystick

스마트폰에서 가상 조이스틱을 사용할때 넣는다.

사용하기 간편함

단점은 사이즈 조절을 일일히 해줘야하고 고정방식쓰려면 스크립트를 직접 짜야함

'Unity' 카테고리의 다른 글

스파인 사용법  (0) 2020.06.25
인풋필드 엔터누르면 초기화  (0) 2020.05.31
SQLlite 브라우저 사용방법  (0) 2020.05.24
posted by 모카쨩
2020. 5. 19. 21:48 Unity/C#

//손이 많이가지만 많은 기능을 쓸수 있습니다.

 

 

 

 

기본형

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(RoomGoto))]
public class RoomGoto_Inspector : Editor
{
    public override void OnInspectorGUI()
    {
        EditorGUILayout.LabelField("버튼조작을 위한 컴포넌트");
    }
}
#endif

public class RoomGoto : MonoBehaviour
{
    public void room_goto(string room_name)
    {
        SceneManager.LoadScene(room_name);
    }
    public void game_quit()
    {
        Application.Quit();
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

기존 인스펙터 호출

public override void OnInspectorGUI()
{
    DrawDefaultInspector();
}

혹은

public override void OnInspectorGUI()
{
    base.OnInspectorGUI();
}

 

 

 

 

버튼 조작시

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();//기본 인스펙터를 받아올때
        serializedObject.Update();
        {
            if (GUILayout.Button("실행"))
            {
                ((SampleClass)target).PressInspecterButton();
            }
            EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(SampleClass.notice)), GUIContent.none);

        }
        serializedObject.ApplyModifiedProperties();


    }
}

#endif
public class SampleClass : MonoBehaviour
{
    [HideInInspector]
    [Header("주석")]
    public string notice;
    
    
    public void PressInspecterButton()
    {
        //버튼을 누를시 활성화될 코드
        if (Application.isPlaying)
        {
            //게임중일때 실행될 코드
        }
        else
        {
            //인스펙터에서 수정중일때 실행될 코드
        }
    }
}

 

 

슬라이더 조작시

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();//기본 인스펙터를 받아올때
        serializedObject.Update();
        {
        
            EditorGUI.BeginChangeCheck();
            {
            	EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(SampleClass.border)));
            }
            if (EditorGUI.EndChangeCheck())
            {
                ((AccountSelect)target).SelectInspecterSlider();
            }
            EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(SampleClass.border)), GUIContent.none);
        }
        serializedObject.ApplyModifiedProperties();


    }
}

#endif
public class SampleClass : MonoBehaviour
{
    [HideInInspector]
    [Header("주석")]
    public string notice;
    
    
    [HideInInspector]
    [Range(0,6)]
    public float border;
    
    public void SelectInspecterSlider()
    {
    	//값변경시 활성화될 코드
    	if (Application.isPlaying)
        {
        	게임중일때 실행될 코드
        }
        else
        {
        	인스펙터에서 수정중일때 실행될 코드
        }
    }
}

 

 

라벨필드

public override void OnInspectorGUI()
{
    EditorGUILayout.LabelField("일반라벨");
    EditorGUILayout.LabelField("굵은글씨", EditorStyles.boldLabel);
}

 

 

 

 

 

메뉴를 만들어야 할때

#if UNITY_EDITOR
using UnityEditor;

public class CustomMenuEditor : Editor
{
    [MenuItem("MyMenu/Run")]
    static void Run()
    {
        //실행되는 코드
    }
}

#endif

 

 

 

 

 

커스텀 윈도우 프로퍼티 필드(수동 serializedObject)

public Object folder;
SerializedObject serializedObject;
void OnGUI()
{
    if (serializedObject == null)
    {
        serializedObject = new SerializedObject(this);
    }
    serializedObject.Update();
    {
        EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(folder)));
    }
    serializedObject.ApplyModifiedProperties();
}

 

 

 

 

비활성필드

GUI.enabled = false;
{
    EditorGUILayout.TextField("Name", "value");
}
GUI.enabled = true;

 

NonSerialized 및 정적필드뷰어

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public void DrawHiddenInspectors()
    {
        serializedObject.Update();
        {
            var fields = target.GetType().GetFields();
            GUI.enabled = false;
            {
                foreach (var field in fields)
                {
                    if ((field.IsStatic) || (field.IsNotSerialized))
                    {

                        var fieldName = field.Name;
                        if (field.IsStatic)
                        {
                            fieldName += " (static)";
                        }
                        var fieldType = field.FieldType;
                        if ((fieldType.IsArray) || ((fieldType.IsGenericType) && fieldType.GetGenericTypeDefinition() == typeof(List<>)))
                        {

                            EditorGUI.indentLevel--;
                            {
                                EditorGUILayout.LabelField($"▼{field.Name}");
                            }
                            EditorGUI.indentLevel++;
                            EditorGUI.indentLevel++;
                            {
                                var arrDatas = (System.Collections.IList)field.GetValue(target);
                                if (arrDatas == null)
                                {
                                    EditorGUILayout.LabelField("null");
                                }
                                else
                                {
                                    EditorGUILayout.TextField($"Size", arrDatas.Count.ToString());
                                    for (int i = 0; i < arrDatas.Count; i++)
                                    {
                                        EditorGUILayout.TextField($"Element {i}", arrDatas[i].ToString());
                                    }
                                }
                            }
                            EditorGUI.indentLevel--;

                        }
                        else if (fieldType.IsClass && (fieldType.IsArray == false) && (fieldType.Equals(typeof(string)) == false))
                        {
                            EditorGUI.indentLevel--;
                            {
                                EditorGUILayout.LabelField($"▼{field.Name}");
                            }
                            EditorGUI.indentLevel++;
                            EditorGUI.indentLevel++;
                            {
                                var fieldValue = field.GetValue(target);
                                var subFields = fieldType.GetFields();
                                foreach (var subField in subFields)
                                {
                                    //subField.GetValue(fieldValue).ToString()
                                    EditorGUILayout.LabelField(subField.Name);
                                }
                            }
                            EditorGUI.indentLevel--;
                        }
                        else
                        {
                            EditorGUILayout.TextField($"{field.Name}", field.GetValue(target).ToString());
                        }
                    }
                }
            }
            GUI.enabled = true;
        }
        serializedObject.ApplyModifiedProperties();
    }
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        DrawHiddenInspectors();

    }
}

#endif
public class SampleClass : MonoBehaviour
{
    public int number = 1;
    public int[] array = new int[] { 1, 2, 3 };
    public static float realStatic = 1.5f;
    public static int numberStatic = 2;
    public static int[] arrayStatic = new int[] { 1,2,3 };



    public static QuestionSelect questionSelect;
    [System.Serializable]
    public class QuestionSelect
    {
        public int number = 1;
        public float real = 2f;
    }
}

 

 

커스텀 readonly

더보기
#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public void BaseInspectorGUI(params string[] readOnlyPropertyNames)
    {
        serializedObject.Update();
        {
            var fields = target.GetType().GetFields();
            foreach (var field in fields)
            {
                if ((field.IsStatic) || (field.IsNotSerialized))
                {
                }
                else
                {
                    if (System.Array.FindIndex(readOnlyPropertyNames, x => x == field.Name) >= 0)
                    {
                        GUI.enabled = false;
                    }
                    EditorGUILayout.PropertyField(serializedObject.FindProperty(field.Name));
                    GUI.enabled = true;
                }
            }
        }
        serializedObject.ApplyModifiedProperties();
    }
    public override void OnInspectorGUI()
    {
        BaseInspectorGUI(nameof(SampleClass.SampleVariable));
    }
}
#endif

 

커스텀 readonly V2

더보기
#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public void BaseOnInspectorGUI(params string[] readOnlyPropertyNames)
    {
        DrawPropertiesExcluding(serializedObject, readOnlyPropertyNames);
        serializedObject.Update();
        {
            GUI.enabled = false;
            foreach (var readOnlyPropertyName in readOnlyPropertyNames)
            {
                EditorGUILayout.PropertyField(serializedObject.FindProperty(readOnlyPropertyName));
            }
            GUI.enabled = true;
        }
    }
    public override void OnInspectorGUI()
    {
        BaseOnInspectorGUI(nameof(SampleClass.SampleVariable));
    }
}
#endif

 

 

 

 

 

 

 

커스텀 히든(v3)

이걸써야 디버그모드에서도 보인다

v2에 비해서 코드는 길어졌지만 script를 숨겨놓게 했다 (m_Script가 표시숨김)

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public override void OnInspectorGUI()
    {
        GUI.enabled = false;
        {
            var script = MonoScript.FromMonoBehaviour((MonoBehaviour)target);
            EditorGUILayout.ObjectField("Script", script, typeof(MonoScript), false);
        }
        GUI.enabled = true;
        
        serializedObject.Update();
        {
        	DrawPropertiesExcluding(serializedObject, "m_Script",nameof(SampleClass.SampleVariable));
        }
        serializedObject.ApplyModifiedProperties();
    }
}
#endif
더보기

커스텀 히든(v1)

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public void BaseInspectorGUI(params string[] hiddenPropertyNames)
    {
        serializedObject.Update();
        {
            var fields = target.GetType().GetFields();
            foreach (var field in fields)
            {
                if ((field.IsStatic) || (field.IsNotSerialized))
                {
                }
                else
                {
                    if ((System.Array.FindIndex(hiddenPropertyNames, x => x == field.Name) >= 0)==false)
                    {
                        EditorGUILayout.PropertyField(serializedObject.FindProperty(field.Name));
                    }
                }
            }
        }
        serializedObject.ApplyModifiedProperties();
    }
    public override void OnInspectorGUI()
    {
        BaseInspectorGUI(nameof(SampleClass.SampleVariable));
    }
}
#endif

 

 

커스텀 히든(v2)

이걸써야 디버그모드에서도 보인다

[HideInInspector]는 여전히 안보임

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        {
        	DrawPropertiesExcluding(serializedObject,nameof(SampleClass.SampleVariable));
        }
        serializedObject.ApplyModifiedProperties();
    }
}
#endif

 

 

 

값변경 미리보기

미리보기수준에서 끝나는게 아니라 실제로 적용하려면 더티플래그를 박아라

#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        serializedObject.Update();
        {
            EditorGUI.BeginChangeCheck();
            {
                EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(SampleClass.SampleValue)));
            }
            if (EditorGUI.EndChangeCheck())
            {
                //변경되었을때 실행
            }
            else
            {
                //인스펙터를 벗어났을때 실행
            }

        }
        serializedObject.ApplyModifiedProperties();
    }
}
#endif

 

 

더티플래그를 이용한 프리팹상 저장



if (GUILayout.Button("Auto Setting"))
{
    AutoFind();
    EditorUtility.SetDirty(target); //이부분
}

 

 

 

 

 

 

ReorderableList 예제

튜토리얼 모드에서는 라이프 미표시하는 ReorderableList 예제

더보기

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{

    Hashtable reorderableListTable = new Hashtable();
    public void DrawStageDatas(string propertyPath)
    {

        var reorderableListProperty = serializedObject.FindProperty(propertyPath);

        if (reorderableListTable[propertyPath] == null)
        {
            reorderableListTable[propertyPath] = new ReorderableList(serializedObject, reorderableListProperty);
        }
        var reorderableList = (ReorderableList)reorderableListTable[propertyPath];

        serializedObject.Update();
        {

            //헤더명
            reorderableList.drawHeaderCallback = (rect) => EditorGUI.LabelField(rect, $"{propertyPath} ({reorderableListProperty.arraySize})");


            //요소

            var elementName = nameof(SampleClass.StageData.stageName);
            reorderableList.drawElementCallback =
            (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                EditorGUI.PropertyField(rect, reorderableListProperty.GetArrayElementAtIndex(index).FindPropertyRelative(elementName));
            };
            reorderableList.DoLayoutList();


            //선택된 필드
            if (reorderableList.index >= 0)
            {
                var index = reorderableList.index;
                if ((reorderableListProperty != null) && (reorderableListProperty.arraySize > 0) && (index < reorderableListProperty.arraySize))
                {
                    var elementAtIndex = reorderableListProperty.GetArrayElementAtIndex(index);

                    if (elementAtIndex.FindPropertyRelative(nameof(SampleClass.StageData.isTutorial)).boolValue)
                    {
                        //튜토리얼 모드라면 이름과 제한시간만 표시
                        EditorGUILayout.PropertyField(elementAtIndex.FindPropertyRelative(nameof(SampleClass.StageData.isTutorial)));
                        EditorGUILayout.PropertyField(elementAtIndex.FindPropertyRelative(nameof(SampleClass.StageData.timeLimit)));
                    }
                    else
                    {
                        //기본표시
                        foreach (var field in typeof(SampleClass.StageData).GetFields())
                        {
                            if ((field.IsStatic) || (field.IsNotSerialized))
                            {
                            }
                            else
                            {
                                if (field.Name != elementName)
                                {
                                    EditorGUILayout.PropertyField(elementAtIndex.FindPropertyRelative(field.Name));
                                }
                            }
                        }
                        
                        
                        
                        //life값은 0으로 초기화
                        {
                            var sampleClass = (SampleClass)target;
                            var field = sampleClass.GetType().GetField(propertyPath);
                            var datas = (SampleClass.StageData)field.GetValue(sampleClass);
                            datas[index].life = 0;
                            //구조체라면 field.SetValue(sampleClass, datas)를 사용한다
                        }
                    }
                }
            }

        }
        serializedObject.ApplyModifiedProperties();
    }





    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        DrawStageDatas(nameof(SampleClass.stageDatas));
        DrawStageDatas(nameof(SampleClass.stageDatas2));

    }
}
#endif
public class SampleClass : MonoBehaviour
{

    [HideInInspector]
    public StageData[] stageDatas;
    
    [HideInInspector]
    public StageData[] stageDatas2;

    [System.Serializable]
    public class StageData
    {
        public string stageName;
        public bool isTutorial;
        public int timeLimit;
        public int life;
    }


    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

 

 

 

한칸에 여러줄표시하는 ReorderableList 예제

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(SampleClass))]
public class SampleClassEditor : Editor
{

    Hashtable reorderableListTable = new Hashtable();
    public void DrawStageDatas(string propertyPath)
    {

        var reorderableListProperty = serializedObject.FindProperty(propertyPath);

        if (reorderableListTable[propertyPath] == null)
        {
            reorderableListTable[propertyPath] = new ReorderableList(serializedObject, reorderableListProperty);
        }
        var reorderableList = (ReorderableList)reorderableListTable[propertyPath];

        serializedObject.Update();
        {

            //헤더명
            reorderableList.drawHeaderCallback = (rect) => EditorGUI.LabelField(rect, $"{propertyPath} ({reorderableListProperty.arraySize})");

            //요소크기
            reorderableList.elementHeight = EditorGUIUtility.singleLineHeight * 4;
            
            reorderableList.drawElementCallback =
            (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                var elementProperty = reorderableListProperty.GetArrayElementAtIndex(index);

                var fieldRect = rect;
                fieldRect.height = EditorGUIUtility.singleLineHeight;
                EditorGUI.PropertyField(fieldRect, elementProperty.FindPropertyRelative(nameof(SampleClass.StageData.stageName)));
                fieldRect.y += EditorGUIUtility.singleLineHeight;
                EditorGUI.PropertyField(fieldRect, elementProperty.FindPropertyRelative(nameof(SampleClass.StageData.isTutorial)));
                fieldRect.y += EditorGUIUtility.singleLineHeight;
                EditorGUI.PropertyField(fieldRect, elementProperty.FindPropertyRelative(nameof(SampleClass.StageData.timeLimit)));
                fieldRect.y += EditorGUIUtility.singleLineHeight;
                EditorGUI.PropertyField(fieldRect, elementProperty.FindPropertyRelative(nameof(SampleClass.StageData.life)));
            };
            reorderableList.DoLayoutList();



        }
        serializedObject.ApplyModifiedProperties();
    }





    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        DrawStageDatas(nameof(SampleClass.stageDatas));
        DrawStageDatas(nameof(SampleClass.stageDatas2));

    }
}
#endif
public class SampleClass : MonoBehaviour
{

    [HideInInspector]
    public StageData[] stageDatas;

    [HideInInspector]
    public StageData[] stageDatas2;

    [System.Serializable]
    public class StageData
    {
        public string stageName;
        public bool isTutorial;
        public int timeLimit;
        public int life;
    }


    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

참고용 단순 예제

 

 

 

 

#if UNITY_EDITOR

using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(SampleClass))]
public class SampleClassEditor : Editor
{

    Hashtable reorderableListTable = new Hashtable();
    public static System.Type GetType(SerializedProperty property)
    {
        var parentType = property.serializedObject.targetObject.GetType();
        var fieldInfo = parentType.GetField(property.propertyPath);
        return fieldInfo.FieldType;
    }
    public void DrawReorderableList(string propertyPath)
    {

        var reorderableListProperty = serializedObject.FindProperty(propertyPath);

        if (reorderableListTable[propertyPath] == null)
        {
            reorderableListTable[propertyPath] = new ReorderableList(serializedObject, reorderableListProperty);
        }
        var reorderableList = (ReorderableList)reorderableListTable[propertyPath];

        serializedObject.Update();
        {

            //헤더명
            reorderableList.drawHeaderCallback = (rect) => EditorGUI.LabelField(rect, $"{propertyPath} ({reorderableListProperty.arraySize})");


            //요소
            var targetType = GetType(reorderableListProperty).GetElementType();

            reorderableList.elementHeight = EditorGUIUtility.singleLineHeight * Mathf.Max(1, targetType.GetFields().Length);

            reorderableList.drawElementCallback =
            (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                var elementProperty = reorderableListProperty.GetArrayElementAtIndex(index);

                var fieldRect = rect;
                fieldRect.height = EditorGUIUtility.singleLineHeight;


                fieldRect.y -= EditorGUIUtility.singleLineHeight;
                foreach (var fields in targetType.GetFields())
                {
                    fieldRect.y += EditorGUIUtility.singleLineHeight;
                    EditorGUI.PropertyField(fieldRect, elementProperty.FindPropertyRelative(fields.Name));
                }

            };
            reorderableList.DoLayoutList();



        }
        serializedObject.ApplyModifiedProperties();
    }





    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        DrawReorderableList(nameof(SampleClass.stageDatas));
        DrawReorderableList(nameof(SampleClass.stageDatas2));

    }
}
#endif


public class SampleClass : MonoBehaviour
{

    [HideInInspector]
    public StageData[] stageDatas;

    [HideInInspector]
    public StageData[] stageDatas2;

    [System.Serializable]
    public class StageData
    {
        public string stageName;
        public bool isTutorial;
        public int timeLimit;
        public int life;
    }


    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

 

자동화 버전

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

배열길이 임의로 조정

var property=serializedObject.FindProperty(nameof(SampleClass.folders));
if(property.arraySize > 3)
{
    property.arraySize = 3;
}

 

다중배열 표시

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


#if UNITY_EDITOR
//Production Date 2022-10-10 from Ahzkwid
using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassInspecter : Editor
{
    public void Draw2DArray(string targetFieldName)
    {
        bool IsArrayCustom(System.Type type)
        {
            return (type.IsArray) || ((type.IsGenericType) && type.GetGenericTypeDefinition() == typeof(List<>));
        }
        void DrawElement(string label,object ilistObject)
        {
            var ilist = (System.Collections.IList)ilistObject;
            EditorGUI.indentLevel--;
            {
                EditorGUILayout.LabelField(label);
            }
            EditorGUI.indentLevel++;
            EditorGUI.indentLevel++;
            {
                if (ilist == null)
                {
                    EditorGUILayout.LabelField("null");
                }
                else
                {
                    EditorGUILayout.TextField($"Size", ilist.Count.ToString());
                    for (int i = 0; i < ilist.Count; i++)
                    {
                        if (ilist[i] == null)
                        {
                            EditorGUI.indentLevel++;
                            EditorGUILayout.LabelField("null");
                            EditorGUI.indentLevel--;
                            continue;
                        }
                        var elementType = ilist[i].GetType();
                        if (IsArrayCustom(elementType))
                        {
                            DrawElement($"▼Element {i}", ilist[i]);
                        }
                        else
                        {
                            EditorGUILayout.TextField($"Element {i}", ilist[i].ToString());
                        }
                    }
                }
            }
            EditorGUI.indentLevel--;
        }
        serializedObject.Update();
        {
            var fields = target.GetType().GetFields();
            GUI.enabled = false;
            {
                foreach (var field in fields)
                {
                    var fieldName = field.Name;
                    if (fieldName != targetFieldName)
                    {
                        continue;
                    }
                    if (field.IsStatic)
                    {
                        fieldName += " (static)";
                    }
                    var fieldType = field.FieldType;
                    if (IsArrayCustom(fieldType))
                    {
                        DrawElement($"▼{field.Name}", field.GetValue(target));
                    }
                }
            }
            GUI.enabled = true;
        }
        serializedObject.ApplyModifiedProperties();
    }
    public override void OnInspectorGUI()
    {

        base.OnInspectorGUI();
        Draw2DArray(nameof(SampleClass.sampleArray2));
        Draw2DArray(nameof(SampleClass.sampleArray3));
        Draw2DArray(nameof(SampleClass.sampleArray4));
    }
}
#endif

public class SampleClass : MonoBehaviour
{
    public string[] sampleArray;
    public string[][] sampleArray2;
    public string[][] sampleArray3 = new string[1][];
    public string[][][] sampleArray4 = new string[2][][] { new string[1][], new string[1][] };
    // Start is called before the first frame update
    void Start()
    {
        sampleArray2 = new string[8][];
        for (int i = 0; i < sampleArray.Length; i++)
        {
            sampleArray2[i] = new string[8];
        }



        sampleArray3 = new string[2][];
        for (int i = 0; i < sampleArray3.Length; i++)
        {
            sampleArray3[i] = new string[3];
            for (int j = 0; j < sampleArray3[i].Length; j++)
            {
                sampleArray3[i][j] = $"text[{i}][{j}]";
            }
        }


        sampleArray4 = new string[2][][];
        for (int i = 0; i < sampleArray4.Length; i++)
        {
            sampleArray4[i] = new string[2][];
            for (int j = 0; j < sampleArray4[i].Length; j++)
            {
                sampleArray4[i][j] = new string[2];
                for (int k = 0; k < sampleArray4[i][j].Length; k++)
                {
                    sampleArray4[i][j][k] = $"text[{i}][{j}][{k}]";
                }
            }
        }


    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

오른쪽으로 한칸 들여쓰기

EditorGUI.indentLevel++;
{
    //들어갈 내용
}
EditorGUI.indentLevel--;

 

 

박스 레이아웃 두르기

GUILayout.Space(50);
EditorGUILayout.LabelField("제목", EditorStyles.boldLabel);
GUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUI.indentLevel++;
{
    //들어갈 내용
}
EditorGUI.indentLevel--;
GUILayout.Space(20);
GUILayout.EndVertical();

 

 

 

 

 

자기 자신 스크립트를 표시

GUI.enabled = false;
{
    var script = MonoScript.FromMonoBehaviour((MonoBehaviour)target);
    EditorGUILayout.ObjectField("Script", script, typeof(MonoScript), false);
}
GUI.enabled = true;

 

 

SerializedProperty To Type

    public static System.Type GetType(SerializedProperty property)
    {
        var parentType = property.serializedObject.targetObject.GetType();
        var fieldInfo = parentType.GetField(property.propertyPath);
        return fieldInfo.FieldType;
    }

 

 

 

 

커스텀 드롭다운

하기는 레이어 드롭다운 예제이다.

var sampleClass = (SampleClass)target;

GUILayout.BeginHorizontal();
{
    GUILayout.Label("Layer");

    int layer = sampleClass.gameObject.layer;
    if (EditorGUILayout.DropdownButton(new GUIContent( LayerMask.LayerToName(layer)), FocusType.Passive))
    {
        GenericMenu menu = new GenericMenu();
        for (int i = 0; i < 32; i++)
        {
            var layerName = LayerMask.LayerToName(i);
            if (string.IsNullOrWhiteSpace(layerName))
            {
                continue;
            }
            menu.AddItem(new GUIContent($"{i}: {layerName}"), false, Callback, i);
        }
        menu.ShowAsContext();


        void Callback(object obj)
        {
            sampleClass.gameObject.layer = (int)obj;
        }
    }
}
GUILayout.EndHorizontal();

 

레이어마스크 드롭다운 예제

근데 내장변수 LayerMask 쓰면 된다 (뻘짓함)

인줄 알았는데 Unsupported type BitField버그때문에 다시 씀

더보기
#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(Crosshair))]
public class CrosshairEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();


        var targetClass = (Crosshair)target;

        serializedObject.Update();
        {
            GUILayout.BeginHorizontal();
            {
                GUILayout.Label("Layer Mask");

                var layerMask = targetClass.layerMask;

                var layerNames = new List<string>();
                for (int i = 0; i < 32; i++)
                {
                    if ((layerMask & (1<<i))==0) //해당 레이어마스크가 미체크면 스킵
                    {
                        continue;
                    }
                    var layerName = LayerMask.LayerToName(i);
                    if (string.IsNullOrWhiteSpace(layerName))
                    {
                        layerName = i.ToString();
                    }
                    layerNames.Add(layerName);
                }
                var name = "";
                switch (layerMask)
                {
                    case 0: //Nothing
                        name = "Nothing";
                        break;
                    case -1: //Everything (-1,~0)
                        name = "Everything";
                        break;
                    default:
                        if (layerNames.Count>3)
                        {
                            name = "Mixed...";
                        }
                        else
                        {
                            name = string.Join(", ", layerNames);
                        }
                        break;
                }
                if (EditorGUILayout.DropdownButton(new GUIContent(name), FocusType.Passive))
                {
                    var menu = new GenericMenu();

                    menu.AddItem(new GUIContent($"Nothing"), layerMask == 0, Callback, 0); //Nothing
                    menu.AddItem(new GUIContent($"Everything"), layerMask == -1, Callback, -1); //Everything
                    for (int i = 0; i < 32; i++)
                    {
                        var layerName = LayerMask.LayerToName(i);

                        var on = (layerMask & (1 << i)) != 0;
                        if (string.IsNullOrWhiteSpace(layerName))
                        {
                            continue;
                        }
                        menu.AddItem(new GUIContent($"{i}: {layerName}"), on, Callback, 1 << i);
                    }
                    menu.ShowAsContext();


                    void Callback(object obj)
                    {
                        switch ((int)obj)
                        {
                            case 0: //Nothing
                            case -1: //Everything (-1,~0)
                                targetClass.layerMask = (int)obj;
                                break;
                            default:
                                targetClass.layerMask ^= (int)obj;
                                break;
                        }
                    }
                }
            }
            GUILayout.EndHorizontal();

        }
        serializedObject.ApplyModifiedProperties();
    }
}
#endif

 

 

 

 

enum to dropdown 예제

아주 가끔 쓰인다

#if UNITY_EDITOR

    using UnityEditor;
    [CustomEditor(typeof(PickupSystem))]
    public class PickupSystemInspecter : Editor
    {
        public enum Piece
        {
            None, Pawn, Knight, Bishop, Rook, Queen, King
        }
        public override void OnInspectorGUI()
        {
            GUI.enabled = false;
            {
                var script = MonoScript.FromMonoBehaviour((MonoBehaviour)target);
                EditorGUILayout.ObjectField("Script", script, typeof(MonoScript), false);
            }
            GUI.enabled = true;


            serializedObject.Update();
            {
                DrawPropertiesExcluding(serializedObject, "m_Script", nameof(PickupSystem.piece));

                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label(nameof(PickupSystem.piece));
                    var pickupSystem = target as PickupSystem;
                    var names = System.Enum.GetNames(typeof(Piece));
                    if (EditorGUILayout.DropdownButton(new GUIContent(names[pickupSystem.piece]), FocusType.Passive))
                    {
                        var menu = new GenericMenu();
                        for (int i = 0; i < names.Length; i++)
                        {
                            if (string.IsNullOrWhiteSpace(names[i]))
                            {
                                continue;
                            }
                            menu.AddItem(new GUIContent($"{i}: {names[i]}"), false, Callback, i);
                        }
                        menu.ShowAsContext();


                        void Callback(object obj)
                        {
                            pickupSystem.piece = (int)obj;
                        }
                    }
                }
                GUILayout.EndHorizontal();


            }
            serializedObject.ApplyModifiedProperties();
        }
    }
#endif

 

 

 

 

 

 

텍스처 표시

        {
            var preview = AssetPreview.GetAssetPreview(loadComputeShader.renderTexture);
            GUILayout.Label(preview);
            EditorGUILayout.LabelField(nameof(LoadComputeShader.renderTexture));
        }

 

 

 

MinMax슬라이더

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


#if UNITY_EDITOR

using UnityEditor;
[CustomEditor(typeof(SampleClass))]
public class SampleClassEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();//기본 인스펙터
        serializedObject.Update();
        {
            var sampleClass = (SampleClass)target;
            var minLimit = sampleClass.minLimit;
            var maxLimit = sampleClass.maxLimit;
            EditorGUILayout.LabelField($"MinMaxSlider ({minLimit},{sampleClass.minVal},{sampleClass.maxVal},{maxLimit})");
            EditorGUILayout.MinMaxSlider(ref sampleClass.minVal, ref sampleClass.maxVal, minLimit, maxLimit);
        }
        serializedObject.ApplyModifiedProperties();


    }
}

#endif


public class SampleClass : MonoBehaviour
{
    public float minVal = -10;
    public float minLimit = -20;
    public float maxVal = 10;
    public float maxLimit = 20;
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

'Unity > C#' 카테고리의 다른 글

SQLite 유니티 사용방법  (0) 2020.05.24
유니티 어트리뷰트  (0) 2020.05.19
UGui 관련  (0) 2020.05.19
posted by 모카쨩
2020. 5. 19. 21:45 Unity/C#

 

인스펙터계열 어트리뷰트

//해당 변수가 어떤 역할인지 위에 굵은 글씨로 표시해줌
[Header("헤더이름")] 

//슬라이더로 표시해줌
[Range(0.5f,1.5f)] 


//슬라이더바가 있는 멀티라인
[TextArea(1,30)]
public string csvData;


//슬라이더바가 없는 고정된 멀티라인
[Mutiline]
public string text;

 

 

변수계열 어트리뷰트

//인스펙터의 변수1에 할당되어있던걸 변수2로 할당함
[UnityEngine.Serialization.FormerlySerializedAs("변수1")]
public int 변수2;

 

 

 

 

 

클래스계열 어트리뷰트

//해당 클래스의 인스펙터를 여러개 동시에 수정가능하도록 함
[CanEditMultipleObjects]


//항상 작동함
[ExecuteAlways]

//해당 클래스가 에디터상태에서도 동작함
[ExecuteInEditMode]

//에디터가 시작될때 호출됨
[UnityEditor.InitializeOnLoad]

//에디터가 시작될때 해당 메소드가 호출됨 static 메소드만 가능
[UnityEditor.InitializeOnLoadMethod]


//특정 컴포넌트를 강제로 추가시킴,클래스 위에 삽입함
[RequireComponent(typeof(Rigidbody))]

//없어질 함수라고 선언함, 클래스계열에도 사용가능하다
[System.Obsolete("미사용되는 함수입니다")]

//동일한 컴포넌트는 2개이상 적용 불가
[DisallowMultipleComponent]

 

 

함수계열 어트리뷰트

//이건 좀 특이하니 하단 참고
[ContextMenu("버튼명")]

 

 

 

 

 

-ContextMenu

public int motionCount;
#if UNITY_EDITOR
    [ContextMenu("함수명")]
    public void UpdateMotionCount()
    {
        motionCount = GetNumberMotionsInBlendTree(GetAnimator(),0,"Blend Tree");
    }
#endif

인스펙터의 컴포넌트 상단에 대고 우클릭하면 함수를 실행할수있는 메뉴가 나옴
프로퍼티 드로워 버튼 찾지 말고 이거 쓰자

 

 

 

 

 

 

 

 

 

미분류

//인스펙터에서 숨기고 지정된 값도 지움, 그리고 디버그모드에서는 보임
//json등에서 public인데 저장안되게 할때도 사용
[System.NonSerialized] 

//인스펙터에서 숨기고 지정된 값은 지우지 않음, 디버그모드에서도 안보임
[HideInInspector] 

//원래는 보이지 않아야할 클래스나 구조체등을 보이게 함
//클래스나 구조체형을 인스펙터에 표시할때 사용
[System.Serializable]

//private 필드를 보이게 함
//인스펙터에서 수정은 가능한데 스크립트로는 못하게 하는것
[SerializeField]

//선언된 Define이 있을때만 작동, #if와 조금 다른점은 define이 없을때 에러가 나지 않는다
[System.Diagnostics.Conditional("UNITY_EDITOR")]

 

 

이거랑 용법은 비슷한테 인스펙터를 제어하는건 프로퍼티 드로워를 참고

https://wmmu.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EB%93%9C%EB%A1%9C%EC%9B%8C

 

유니티 프로퍼티 드로워

2021. 12. 16. 16:39

wmmu.tistory.com

 

'Unity > C#' 카테고리의 다른 글

유니티 커스텀 인스펙터  (0) 2020.05.19
UGui 관련  (0) 2020.05.19
안드로이드에서 뒤로가기 버튼을 누르면 종료됨  (0) 2020.05.19
posted by 모카쨩

저사양 유저용 블로그 진입