목차
1. 필드(변수) 위에 붙는 어트리뷰트
Header
인스펙터에 표시되는 변수 위에 붙일 시, 변수 위에 타이틀이 생긴다.
인스펙터를 타이틀별로 정리하여 가독성을 높일 수 있다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[Header("public 변수")]
public int publicHeader;
[Header("private 변수")]
private int privateHeader;
}
Space
변수와 변수 사이에 간격을 줄 수 있다.
인스펙터를 정리하여 가독성을 높일 수 있다.
SpaceAttribute의 생성자는 오버로드 되어있기에, [Space], [Space(높이)] 두 형태로 받을 수 있다.
- SpaceAttribute(): 기본 8의 간격이 벌려진다.
- SpaceAttribute(float height): 매개인자로 변수 사이의 간격을 넣을 수 있다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public int firstSpace;
[Space]
public int secondSpace;
[Space(8)]
public int thirdSpace;
}
SerializeField
public을 제외한 private, protected, internal 변수도 인스펙터에 표시를 가능하게 해 주는데, 이를 직렬화라고 부른다.
※ 인스펙터에 보이는 변수들은 다 직렬화 되어있다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[SerializeField] private int privateSerialize;
[SerializeField] protected int protectedSerialize;
[SerializeField] internal int internalSerialize;
}
HideInInspector
변수를 인스펙터에서 숨긴다.
하지만, 변수의 직렬화가 풀리는 것은 아니므로, 수정되있던 값은 유지된다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[HideInInspector] public int publicVariable = 5;
}
Range
Int 나 float 과 같은 숫자 자료형에 최소, 최대 범위를 지정해 줄 수 있다.
이렇게 지정된 변수는 인스펙터에 슬라이더 바 형태로 표시된다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[Range(0, 100)]
public int intPercent;
[Range(0f, 100f)]
public float floatPercent;
}
TextArea
문자열 변수를 멀티라인 텍스트 에디터로 표시되어 여러 줄의 텍스트를 입력하고 편집할 수 있다.
만약 범위를 벗어난다면, 스크롤 바가 생기며 확장된다.
TextAreaAttribute의 생성자는 오버로드 되어있기에 [TextArea], [TextArea(최소 라인, 최대 라인)] 두 형태로 받을 수 있다.
여기서 "최소 라인"과 "최대 라인"은 글을 쓸 수 있는 최대 길이가 아닌, 스크롤 바 없이 확장되는 라인 수이다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[TextArea]
public string description;
[TextArea(5, 10)]
public string setDescription;
}
Multiline
문자열 변수를 멀티라인 텍스트 에디터로 표시되어 여러 줄의 텍스트를 입력하고 편집할 수 있다.
범위를 벗어나도 스크롤 바가 생기지 않는다.
MultilineAttribute의 생성자는 오버로드 되어있기에 [Multiline], [Multiline(라인 수)] 두 형태로 받을 수 있다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[Multiline]
public string description;
[Multiline(5)]
public string setDescription;
}
Tooltip
인스펙터에서 변수에 대한 추가 정보를 나타내주는 툴팁을 표시한다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[Tooltip("주제 적는 칸")]
public string title;
[Tooltip("설명 적는 칸"), TextArea]
public string description;
}
ColorUsage
Color 변수에 대한 속성을 지정할 때 사용된다.
ColorUsage에는 [ColorUsage(투명도 사용 여부)], [ColorUsage(투명도 사용 여부, HDR 사용 여부)] 형태로 받을 수 있도록
오버로딩된 두 개의 사용가능한 생성자가 존재한다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[ColorUsage(false, true)]
public Color color;
}
// ※ 아래 생성자는 사용되지 않는다. (오버로드는 되어있음)
// public ColorUsageAttribute(bool showAlpha, bool hdr, float minBrightness, float maxBrightness, float minExposureValue, float maxExposureValue)
NonReorderable
NonReorderable은 ReorderableList의 기능들을 사용하지 않는다고 설정해 주는 기능이다.
ReorderableList란 Unity 에디터에서 배열이나 리스트와 같이 순서가 있는 컬렉션의 순서를 변경하거나 요소를 추가/삭제 하는 작업을 편리하게 할 수 있도록 지원해 주는 에디터 확장 클래스이다.
※ 이름을 외우기 어렵다면.. Re/Order/Able 로 끊어서 외우면 잘 외워질지도..?
using System.Collections.Generic;
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public int[] reorderableArray;
[NonReorderable]
public int[] nonReorderableArray;
public List<int> reordarableList = new List<int>();
[NonReorderable]
public List<int> nonReordarableList = new List<int>();
}
SearchContext
SearchContext 어트리뷰트를 사용하면 Unity 에디터의 검색 시스템을 활용하여
필드에 특정 내용을 한정하거나 정렬하는 등의 작업을 편리하게 수행할 수 있다.
쿼리는 다음의 문서를 참고하자.
Unity - Manual: Search expressions
Additional Search filters Search expressions Search expressions allow you to add to the search query language to express complex queries that cross-reference multiple providers, for example, to search for all objects in a sceneA Scene contains the environm
docs.unity3d.com
다음은 skin 이란 이름을 가진 텍스쳐를 이름 순으로 오름차순하여 검색해 보았다.
using UnityEngine;
using UnityEngine.Search;
public class TistoryAttribute : MonoBehaviour
{
[SearchContext("sort{t:texture2D skin, @name}")]
public Object skinObject;
// 실제 Sprite로의 캐스팅은 이 메서드에서 수행
public Sprite GetSkinSprite()
{
// 참조 타입 간의 캐스트를 수행하므로 성능이랑 관계X
return skinObject as Sprite;
}
}
Flags
열거형(enum)에 여러 개의 요소가 조합되어 사용될 수 있음을 나타내준다.
원래 열거형 요소의 값은 순서대로 0부터 1씩 증가하지만,
Flags 어트리뷰트를 사용하면 중복되지 않도록 하기 위해 열거형 요소를 비트 플래그로 설정한다.
using System;
using UnityEngine;
[Flags]
public enum ETargetType
{
None = 0,
Zombie = 1 << 0,
LizardMan = 1 << 1,
Dragon = 1 << 2,
}
public class TistoryAttribute : MonoBehaviour
{
public ETargetType currentTargetType;
void Start()
{
// 두 요소를 한 번에 넣기
currentTargetType = ETargetType.Zombie | ETargetType.LizardMan;
}
public void AddTargetType(ETargetType type)
{
// 특정 요소를 추가
currentTargetType |= type;
}
public void RemoveTargetType(ETargetType type)
{
// 특정 요소를 제거
currentTargetType &= ~type;
}
public bool ContainsTarget()
{
// 특정 요소가 존재하는지 확인
if ((currentTargetType & ETargetType.Dragon) != 0)
{
Debug.Log("드래곤이 있습니다. 공격이 불가능합니다.");
return false;
}
Debug.Log("공격이 가능합니다.");
return true;
}
}
커스텀 에디터를 위한 추가 코드
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(TistoryAttribute))]
public class TistoryAttributeEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var tistoryAttribute = (TistoryAttribute)target;
var lastRect = GUILayoutUtility.GetLastRect();
var rect = new Rect(lastRect.x, lastRect.y + EditorGUIUtility.singleLineHeight + 2, lastRect.width, EditorGUIUtility.singleLineHeight);
var halfWidth = rect.width * 0.5f;
Rect addRect = new Rect(rect.x, rect.y, halfWidth, 30);
Rect removeRect = new Rect(rect.x + halfWidth, rect.y, halfWidth, 30);
if (GUI.Button(addRect, "좀비 추가"))
{
tistoryAttribute.AddTargetType(ETargetType.Zombie);
}
if (GUI.Button(removeRect, "좀비 삭제"))
{
tistoryAttribute.RemoveTargetType(ETargetType.Zombie);
}
addRect.y += 30;
removeRect.y += 30;
if (GUI.Button(addRect, "리자드맨 추가"))
{
tistoryAttribute.AddTargetType(ETargetType.LizardMan);
}
if (GUI.Button(removeRect, "리자드맨 삭제"))
{
tistoryAttribute.RemoveTargetType(ETargetType.LizardMan);
}
addRect.y += 30;
removeRect.y += 30;
if (GUI.Button(addRect, "드래곤 추가"))
{
tistoryAttribute.AddTargetType(ETargetType.Dragon);
}
if (GUI.Button(removeRect, "드래곤 삭제"))
{
tistoryAttribute.RemoveTargetType(ETargetType.Dragon);
}
var getRect = addRect;
getRect.y += 30;
getRect.width = rect.width;
if (GUI.Button(getRect, "공격 가능 여부 체크"))
{
tistoryAttribute.ContainsTarget();
}
EditorGUILayout.Space(10 + getRect.y);
}
}
ContextMenuItem
특정 메서드를 인스펙트에서 실행할 수 있게 도와준다.
필드를 우클릭하면 나오는 메뉴에 생성된 버튼을 눌러 실행시킬 수 있다.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[ContextMenuItem("랜덤한 값 반환", "GetRandomValue")]
public float randomValue;
private void GetRandomValue()
{
randomValue = Random.value;
}
}
2. 메서드(함수) 위에 붙는 어트리뷰트
ContextMenu
특정 메서드를 인스펙터에서 실행할 수 있게 도와준다.
컴포넌트의 이름 부분을 우클릭하면 나오는 컨텍스트 메뉴가 나오게 되는데, 설정한 버튼을 클릭하면 실행시킬 수 있다.
ContextMenu의 생성자는 오버로드 되어 있기에
1. [ContextMenu("버튼 이름")],
2. [ContextMenu("버튼 이름", 유효성 검사 여부)],
3. [ContextMenu("버튼 이름", 유효성 검사 여부, 우선순위)]
세 가지 형태로 받을 수 있다.
1.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public float randomValue;
[ContextMenu("랜덤한 값 반환")]
private void GetRandomValue()
{
randomValue = Random.value;
}
}
2.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public float randomValue;
[ContextMenu("랜덤한 값 반환")]
private void GetRandomValue()
{
randomValue = Random.value;
}
// 유효성 검사 메서드
[ContextMenu("랜덤한 값 반환", true)]
private bool ValidatePrintHello()
{
// 어떤 조건에 따라서 유효성을 판단하고 반환
if (randomValue != 0)
{
return false;
}
return true;
}
}
3.
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public float randomValue;
[ContextMenu("랜덤한 값 반환", false, 1)]
private void GetRandomValue()
{
randomValue = Random.value;
}
[ContextMenu("1 ~ 99 랜덤한 값 반환", false, 0)]
private void GetRandomRange()
{
randomValue = Random.Range(1, 100);
}
}
MenuItem
유니티에서 메뉴 항목을 추가하고, 해당 항목을 클릭했을 때 특정 메서드를 실행할 수 있다.
해당 어트리뷰트의 대상이 되는 메서드는 static 이여야 한다.
유니티 에디터를 수정하는 것이므로 "using UnityEditor" 코드가 필요하다.
MenuItem의 생성자는 오버로드 되어 있기에
1. [MenuItem ("버튼 이름")],
2. [MenuItem ("버튼 이름", 유효성 검사 여부)],
3. [MenuItem ("버튼 이름", 유효성 검사 여부, 우선순위)]
세가지 형태로 받을 수 있다.
사용법은 ContextMenu와 동일하므로 생략하였다.
using UnityEditor;
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
public static float randomValue;
[MenuItem("Random/Value")]
private static void GetRandomValue()
{
randomValue = Random.value;
Debug.Log(randomValue);
}
}
3. 클래스 위에 붙는 어트리뷰트
Serializable
클래스나 구조체 등의 형식을 직렬화할 수 있게 해주는 어트리뷰트이다.
직렬화하면 클래스나 구조체 변수들을 인스펙터에 표시할 수 있게 된다.
using System;
using UnityEngine;
[Serializable]
public class SerializableTistoryClass
{
public string title;
public string desc;
public string writer;
}
public class NonSerializableTistoryClass
{
public string title;
public string desc;
public string writer;
}
public class TistoryAttribute : MonoBehaviour
{
public SerializableTistoryClass serializableTistoryClass;
public NonSerializableTistoryClass nonSerializableTistoryClass;
}
RequireComponent
Monobehaviour에서 필요로 하는 다른 컴포넌트들을 자동으로 추가되도록 할 수 있다.
필요로 하는 다른 컴포넌트는 Type형태로 받을 수 있기 때문에 typeof로 리플렉션 해준다.
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class TistoryAttribute : MonoBehaviour
{
}
AddComponentMenu
Unity 에디터에서 Add Component 메뉴에 노출되는 위치를 지정하거나 표시되는 이름을 변경하는데 사용된다.
이를 통해 스크립트를 더 쉽게 찾고 추가할 수 있게 된다.
using UnityEngine;
[AddComponentMenu("Tistory/Attribute")]
public class TistoryAttribute : MonoBehaviour
{
}
DisallowMultipleComponent
한 게임 오브젝트에 동일한 타입의 컴포넌트를 여러 개 추가하는 것을 막아준다.
using UnityEngine;
[DisallowMultipleComponent]
public class TistoryAttribute : MonoBehaviour
{
}
ExcuteInAlways/ExcuteInEditMode
런타임(플레이 모드)이 아닐 때, 에디터에서 스크립트를 실행시킬 수 있다.
ExcuteInAlways는 빌드 시에도 사용이 가능하며,
ExcuteInEditMode는 빌드 시에는 사용이 불가능하다는 차이가 있다.
using UnityEngine;
[ExecuteAlways]
public class TistoryAttribute : MonoBehaviour
{
[Range(0, 10)] public int original;
public float percent;
void Update()
{
percent = original * 0.01f;
}
}
CreateAssetMenu
Assets 메뉴나 Project뷰를 우클릭하면 나오는 Create 메뉴에서 ScriptableObject를 쉽게 만들 수 있게 된다.
using UnityEngine;
[CreateAssetMenu(fileName = "Attribute", menuName = "Tistory/Create Attribute", order = 0)]
public class TistoryAttribute : ScriptableObject
{
}
4. 플레이 모드 진입 시 호출되는 어트리뷰트
InitializeOnLoad
InitializeOnLoad가 사용된 정적 생성자 내부의 로직이 컴파일 할 때나 런타임 시, Awake 메서드 이전에 실행된다.
에디터에서만 실행되며, 빌드 된 파일에서는 실행되지 않는다.
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class TistoryAttribute : MonoBehaviour
{
// 정적 생성자
static TistoryAttribute()
{
// 생성자 내부의 로직만 실행됨
Debug.Log("Script Load");
}
}
InitializeOnLoadMethod
InitializeOnLoadMethod가 사용된 정적 메서드 내부의 로직이 컴파일 할 때나 런타임 시, Awake 메서드 이전에 실행된다.
에디터에서만 실행되며, 빌드 된 파일에서는 실행되지 않는다.
using UnityEditor;
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[InitializeOnLoadMethod]
static void OnLoad()
{
Debug.Log("OnLoad Method Load");
}
}
InitializeOnEnterPlayMode
InitializeOnEnterPlayMode가 사용된 정적 메서드 내부의 로직이 Awake 메서드 이전에 실행된다.
런타임 시, InitializeOnLoad 이전에 실행된다.
에디터에서만 실행되며, 빌드 된 파일에서는 실행되지 않는다.
using UnityEditor;
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[InitializeOnEnterPlayMode]
static void OnEnterPlayMode()
{
Debug.Log("OnEnterPlayMode Method Load");
}
}
RuntimeInitializeOnLoadMethod
게임 실행 시 특정한 정적 메서드를 자동으로 호출하도록 하는데 사용된다.
빌드 시에도 실행되기 때문에, 초기화에 필요한 작업들을 효과적으로 처리할 수 있다.
나는 주로 어느 씬에서나 사용되야 하지만,
씬이 많아 모든 씬에 올리기 부담스럽고 전역으로 사용하지 않아도 될 때 사용한다.
실행 순서는 RuntimeInitializeLoadType타입의 매개인자로 정할 수 있다.
순서 | 타입 | 설명 |
1 | SubsystemRegistration | 서브시스템이 등록되는 시점에 호출된다. |
2 | AfterAssembliesLoaded | 모든 어셈블리가 로드되고 사전 로드된 에셋이 초기화 된 후에 호출된다 |
3 | BeforeSplashScreen | 스플래시 화면이 표시되기 바로 직전에 메서드가 호출된다. 스플래시 화면이란 게임을 시작할 때 나타나는 로딩화면으로, 빌드 시에 기본적으로 Unity 로고가 스플래시 화면으로 표시된다. |
4 | BeforeSceneLoad | 씬이 로드되기 전에 메서드가 호출된다. |
5 | AfterSceneLoad | 씬이 로드된 후에 메서드가 호출된다. |
using UnityEngine;
public class TistoryAttribute : MonoBehaviour
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void OnSubsystemRegistrationLoaded()
{
Debug.Log("OnSubsystemRegistrationLoaded Method Load");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void OnAfterAssembliesLoaded()
{
Debug.Log("OnAfterAssembliesLoaded Method Load");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
static void OnBeforeSplashScreenLoaded()
{
Debug.Log("OnBeforeSplashScreenLoaded Method Load");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void OnBeforeSceneLoad()
{
Debug.Log("OnBeforeSceneLoad Method Load");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void OnAfterSceneLoad()
{
Debug.Log("OnAfterSceneLoad Method Load");
}
}
'공부 > 유니티' 카테고리의 다른 글
[Unity] Custom Editor - ReorderableList (0) | 2024.06.11 |
---|---|
[Unity] 유니티 어트리뷰트 만들기 (0) | 2024.02.24 |
[Unity] 스레드와 비동기 (0) | 2024.02.07 |
[Unity] Addressable Asset System (0) | 2024.02.06 |
[Unity] 제네릭 클래스를 상속받아 싱글톤 구현하기 (0) | 2024.01.31 |