Objet는 유니티의 베이스 클래스다. 이 Object를 상속받는 대표적인 클래스들은 다음과 같다.
- GameObject - 씬 내의 모든 엔티티.
- Component - GameObject에 기능 추가.
- MonoBehaviour - 사용자 정의 스크립트.
- ScriptableObject - 데이터 저장 및 관리.
- Texture, Material - 그래픽 렌더링 관련 클래스.
- AudioClip - 오디오 관리.
- AnimationClip - 애니메이션 데이터 관리.
- AssetBundle - 리소스 묶음 관리.
Object
Object 클래스는 모든 Unity 엔진 객체의 기본 클래스로 다음과 같은 기능들을 제공한다.
- 기본 기능 : 모든 엔진 객체를 참고하거나 관리하는 데 사용
- 객체 생성 및 복제: Instantiate 메서드를 통해 엔진 객체를 복제하거나 다양한 오버로드 메서드를 제공
- 객체 관리: Destroy 및 DestroyImmediate를 통한 객체 제거(혹은 즉시 삭제), DontDestroyOnLoad를 통해 새로운 씬
- 로드 이후에도 파괴되지 않도록 설정
- 객체 검색: FindObjectsOfType 및 FindFirstObjectByType, FindAnyObjectByType 를 통한 검색
- 기타 유용한 기능: name, hideflags, IsNativeObjectAlive
- 비동기 복제 및 매개변수화된 복제: InstantiateAsync 메서드를 통해 복제와 관련된 비동기 작업을 관리하고, InstantiateParameters를 사용하여 객체의 복제 설정을 '매개변수화'한다.
즉, Object는 Unity의 객체 생명 주기 관리, 복제, 검색, 삭제 등 엔진의 핵심 기능을 제공한다.
그리고 이를 통해 GameObject, MonoBehaviour, ScriptableObject와 같은 Unity 객체를 생성, 관리, 파괴하는 데 이 클래스를 활용한다.
내부적인 구현을 살펴보면 네이티브 Unity 엔진 코드와 상호작용하는 Internal_* 메서드로 객체를 생성, 복제 관리하며 네이티브 함수 호출은 Unity 엔진의 내부 기능을 처리한다.
Unity의 경우, 언리얼 엔진과는 다르게 네이티브 엔진 코드의 대부분을 공개하지 않는다. 즉, 언리얼 엔진처럼 엔진 자체의 동작을 수정하거나 커스터마이징 하는 작업은 불가능하다.
만일 내부 동작을 살펴보고 싶다면, dll 파일을 디컴파일 하거나, 유니티 C# 레퍼런스 (https://github.com/Unity-Technologies/UnityCsReference)를 참고하여 공부해 볼 수 있다. 또한 별도의 C++ 플러그인을 작성하고 Unity와 연동하여 필요한 네이티브 기능을 구현할 수 있다.
ScriptableObject
https://waterglass0105.tistory.com/113
[Unity] ScriptableObject
Unity를 이용한 카드게임 개발과정을 보면, 거의 대부분이 사용하는 것이 바로 'Scriptable Object'다. Scriptable Object는 게임 개발에서 데이터 중심 설계를 지원하기 위해 제공되는 특별한 유형의 객체
waterglass0105.tistory.com
Unity의 ScriptableObject 클래스는 GameObject와 독립적으로 존재하는 객체를 생성하기 위해 사용되는 기본 클래스다. 이 클래스는 주로 게임 데이터, 설정, 또는 런타임에서 공유될 수 있는 데이터를 저장하는 데 활용된다.
주요 기능을 살펴보면 다음과 같다.
ScriptableObject 생성자
- ScriptableObject.CreateScriptableObject(this)를 호출해 객체 생성.
인스턴스 생성 메서드
- CreateInstance<T>() - 제네릭 타입으로 ScriptableObject를 생성.
- CreateInstance(string className) - 클래스 이름을 이용해 ScriptableObject를 생성.
- CreateInstance(System.Type type) - 타입 정보를 이용해 ScriptableObject를 생성.
- 내부적으로 CreateScriptableObjectInstanceFromName와 CreateScriptableObjectInstanceFromType 메서드를 호출해 객체를 생성.
Dirty 상태 설정
- SetDirty()를 통해 ScriptableObject의 "더티 플래그"를 설정한다. 이 "더티 플래그"를 통해, 실행 중에 변경 시 디스크에 자동으로 저장된다.
기본값 리셋 및 적용
- ResetAndApplyDefaultInstances()는 객체의 초기값을 리셋하고 적용.
- 스크립터블 오브젝트 또한 Native 엔진 코드와 연동되어 작동된다. ([NativeHeader], [NativeMethod] 등).
- IntPtr와 같은 저수준 핸들링을 통해 Unity 엔진 내부 메모리 구조와 직접 상호작용한다. 또한 InternalCall, FreeFunction 을 활용해 엔진과 통합한다.
여기에서 IntPtr와 같은 저수준 핸들링을 사용함을 짐작해보면, 유니티는 C++ 기반의 엔진을 사용하며 C# 스크릅트 시스템 간의 상호 작용을 위해 여러 기술과 구조를 활용할 수 있음을 알 수 있다.
이를 바탕으로 추가적으로 조사해본 내용은 다음과 같다.
1. C++와 C#의 연동
Unity 엔진의 핵심은 C++로 작성되어 있다. 높은 성능과 메모리 제어가 필요한 게임 엔진의 특성상 C++이 적합하기 때문이다.
ScriptableObject 구현에 등장하는 **IntPtr**와 같은 포인터 기반 작업은 C++의 메모리 관리 구조와 C# 간의 다리 역할을 한다.
InternalCall, FreeFunction, NativeMethod와 같은 속성들은 Unity가 C++과 C#을 연결하는 인터페이스(바인딩) 역할을 한다.
2. Mono/.NET 기반의 C#
Unity는 C#을 사용해 스크립트를 작성하며, Mono 또는 IL2CPP를 통해 C# 코드를 컴파일하고 실행한다.
Unity의 API는 대부분 C++ 코드를 기반으로 하지만, C#으로 추상화되어 사용자가 접근할 수 있도록 설계되었다.
3. C++로 엔진 내부 처리
ScriptableObject.CreateScriptableObjectInstanceFromType 같은 메서드는 C++ 엔진에서 객체를 생성하고 메모리를 초기화한 뒤, C#에서 이를 사용하도록 반환한다.
C++의 고성능 메모리 관리 및 포인터를 활용해 엔진에서 빠른 처리와 메모리 접근이 가능하며, 이를 C#에 안전하게 노출하기 위해 런타임 바인딩을 제공한다.
4. Unity의 설계 철학
Unity는 C++의 성능과 C#의 사용 편의성을 결합하여 개발자가 쉽게 사용할 수 있는 환경을 제공한다.
이를 통해 복잡한 엔진의 내부 구현을 숨기고, C#을 사용하는 개발자가 높은 추상화 레벨에서 작업할 수 있도록 지원한다.
반면 언리얼 엔진의 경우, 블루프린트라는 비주얼 스크립팅을 지원하지만, 엔진 단위 소스코드를 제공하고 이를 통해 내부적인 엔진 프로그래밍도 가능하기 때문에 내부적인 구현도 C++를 그대로 사용함을 알 수 있다. (물론, 자체적인 자료구조나 데이터타입, 그리고 수많은 랩핑 클래스들을 제공하며 Native C++와는 사뭇 다른 모습을 보여주기도 한다.)
따라서, Unity는 "C++ 기반의 고성능 엔진"과 "C#의 편리한 개발 경험"을 조합한 효율적인 하이브리드 구조라고 볼 수 있다.
Component
Component 클래스는 모든 컴포넌트의 기본 클래스이며, GameObject에 첨부된 다양한 기능을 제공한다.
즉, GameObject에 연결된 모든 스크립트, 렌더러, 물리 컴포넌트 등이 이 클래스에서 파생된다.
Component 클래스의 주요 기능은 다음과 같다.
- Transform 및 GameObject 접근
- transform: 현재 컴포넌트가 속한 GameObject의 Transform을 반환.
- gameObject: 현재 컴포넌트가 속한 GameObject를 반환.
컴포넌트 검색
- GetComponent(Type): 현재 GameObject에서 특정 타입의 컴포넌트를 반환.
- GetComponent<T>(): 제네릭 버전의 GetComponent.
- GetComponentInChildren(Type, includeInactive): 자식 GameObject들에서 특정 타입의 컴포넌트를 검색.
- GetComponents(Type): 특정 타입의 컴포넌트를 배열로 반환.
- TryGetComponent<T>(out T component): 컴포넌트를 안전하게 검색하며 실패 시 null을 반환.
컴포넌트의 태그
- tag: 컴포넌트가 속한 GameObject의 태그를 가져오거나 설정.
- CompareTag(string tag): GameObject의 태그와 비교.
메시지 전달 기능
- SendMessage(string methodName): GameObject에 포함된 모든 MonoBehaviour에서 특정 메서드를 호출.
- BroadcastMessage(string methodName): GameObject 및 모든 자식 객체의 MonoBehaviour에서 특정 메서드를 호출.
- SendMessageUpwards: 부모 객체 방향으로 메서드 호출을 전달.
그리고 당연하게도, 이 또한 엔진 내부적으로 C++의 포인터와 유니티 메모리 구조를 사용해 성능을 최적화한다.
Behavior
앞선 Component 클래스를 상속받는 대표적인 클래스가 바로 Behaviour다.
Behaviour 클래스는 GameObject에 추가된 동작(Behavior)을 정의하고 관리하는 데 사용된다. 이 클래스는 MonoBehaviour와 같은 스크립트 기반 컴포넌트의 기본 클래스다.
Behavior의 주요 기능은 다음과 같다.
enabled 속성
- bool enabled: 이 속성을 통해 컴포넌트의 활성화 여부를 설정하거나 확인할 수 있다.
- 활성화된 컴포넌트는 업데이트 루프에서 호출되며, 비활성화된 컴포넌트는 호출되지 않는다.
component.enabled = true; // 활성화
component.enabled = false; // 비활성화
isActiveAndEnabled 속성
- bool isActiveAndEnabled
GameObject가 활성 상태이고, 이 Behaviour가 활성화된 경우 true를 반환한다.
반대로 GameObject가 비활성화되었거나, 컴포넌트가 비활성화된 경우 false를 반환한다.
if (component.isActiveAndEnabled)
{
// 컴포넌트가 활성 상태
}
Behavior 클래스는 component를 상속받아 동작의 기본 틀을 제공하며, MonoBehaviour, Animator, AudioSource 등 여러 Unity 클래스의 기반이 된다. 이는 Unity에서 활성화 및 비활성화를 관리할 수 있는 컴포넌트의 기본 클래스다.
게임 개발자는 이를 통해 스크립트 기반의 동작을 활성화하거나 비활성화하고, 컴포넌트의 상태를 확인할 수 있다.
즉, Unity의 컴포넌트 기반 아키텍처에서 동작 관리의 핵심 역할을 담당한다.
MonoBehaviour
이제 가장 많이 사용되는 MonoBehaviour다. 우선 왜 이름이 MonoBehaviour인지 알아야 한다.
https://waterglass0105.tistory.com/122
[Unity] 유니티 프레임 워크, .NET과 GC
우선 .NET에 대해 알아야한다..NET은 소프트웨어 개발을 위한 도구, 라이브러리 및 언어를 포함하는 플랫폼으로, 이를 통해 다양한 디바이스와 운영체제에서 실행 가능한 애플리케이션 제작이 가
waterglass0105.tistory.com
MonoBehaviour의 Mono는 유니티의 스크립팅 백엔드 방식 중 하나인 Mono 프레임 워크를 사용함을 알리는 것이다.
MonoBehaviour 클래스는 Unity에서 자주 사용하는 베이스 클래스다. 이러한 MonoBehaviour는 다양한 속성과 주요 메서드를 가지고 있는데, 이는 다음과 같다.
주요 속성
destroyCancellationToken: MonoBehaviour가 파괴될 때 발생하는 CancellationToken을 제공.
useGUILayout: GUI 레이아웃 처리를 활성화/비활성화하는 속성.
didStart, didAwake: Start와 Awake 메서드 호출 여부를 확인하는 속성.
runInEditMode: 에디터 모드에서도 스크립트를 실행할 수 있도록 설정하는 속성.
주요 메서드
- Invoke/CancelInvoke
특정 메서드를 일정 시간 후 실행하거나 반복 실행할 수 있도록 지원.
예: Invoke, InvokeRepeating, CancelInvoke. - Coroutine
코루틴을 시작, 중단, 전체 중단하는 기능 제공.
예: StartCoroutine, StopCoroutine, StopAllCoroutines. - IsInvoking
메서드 실행 상태를 확인하는 기능.
코드를 간단하게 요약하면 다음과 같이 표현할 수 있다.
public class MonoBehaviour : Behaviour
{
// 속성
public CancellationToken destroyCancellationToken { get; }
public bool useGUILayout { get; set; }
public bool didStart { get; }
public bool didAwake { get; }
public bool runInEditMode { get; set; }
// 메서드
public void Invoke(string methodName, float time);
public void InvokeRepeating(string methodName, float time, float repeatRate);
public void CancelInvoke();
public bool IsInvoking();
public Coroutine StartCoroutine(IEnumerator routine);
public void StopCoroutine(Coroutine routine);
public void StopAllCoroutines();
// 유틸리티
public static void print(object message);
}
앞선 그림에서도 볼 수 있듯, MonoBehaviour는 다음의 상속 구조를 갖는다.
Object → Component → Behaviour → MonoBehaviour
MonoBehaviour가 게임 오브젝트에 붙을 수 있는 이유는 Component를 상속받기 때문이다.
MonoBehaviour는 Component를 상속받아 Unity 엔진에서 "게임 오브젝트에 붙일 수 있는 구성 요소"로 간주된다. 즉, Unity는 Component를 기반으로 하는 객체만 게임 오브젝트에 부착할 수 있다. 그리고 Behaviour를 상속받아 추가 동작을 제공받음으로써, MonoBehaviour는 Behaviour의 enabled와 같은 속성을 통해 컴포넌트의 활성화 상태를 제어할 수 있게된다. MonoBehaviour를 상속받는 가장 큰 이유는, MonoBehaviour는 Unity 엔진의 메시지 기반 시스템과 통합되어 있어 Unity 생명 주기 메서드를 활용할 수 있기 때문이다.
즉, Start, Update, FixedUpdate, OnCollisionEnter과 같은 생명 주기 메서드를 사용하려면 MonoBehaviour를 상속받아야 한다. 이 외에도, 코루틴, 게임 오브젝트와의 통합등도 MonoBehaviour에서 제공한다.
물론, 이론적으로는 Component를 상속받으면 MonoBehaviour를 상속받지 않아도 게임 오브젝트에 붙일 수 있을 것이다.
하지만 실용적이지는 않다.
Component를 직접 상속받으면 GameObject.AddComponent<T>()를 통해 부착할 수 있다. 하지만, 앞서 말한 것 처럼, Unity 생명 주기 메서드(Start, Update 등)를 사용할 수 없으며, Unity 엔진의 코루틴이나 메시지 시스템과 통합되지 않는다.
정리해보자면 MonoBehaviour는 Behaviour와 Component를 상속받아 Unity 엔진에서 게임 오브젝트에 부착 가능한 컴포넌트로 동작할 수 있다.
그리고, Component가 아닌 MonoBehaviour를 상속받아는 것은 MonoBehaviour가 Unity 생명 주기 메서드, 코루틴, 메시지 시스템 등 Unity 엔진의 주요 기능과 통합된 동작을 제공하기 때문이다.
따라서, Component를 직접 상속받는 경우에는 이러한 기능을 사용할 수 없기 때문에 비효율적이다.
Behaviour는 이러한 MonoBehaviour에 활성화(enabled) 및 상태 관리 기능을 제공하며, MonoBehaviour는 이를 기반으로 Unity 엔진의 동작과 상호작용한다.
즉, MonoBehaviour는 게임 로직을 작성하고 Unity 엔진과 완전히 통합된 컴포넌트를 만들기 위한 최적의 기본 클래스다.
'Study > Unity Engine' 카테고리의 다른 글
[Unity] Data Serialization (0) | 2025.01.25 |
---|---|
[Unity] 유니티 이해하기 03 - Input System (0) | 2025.01.24 |
[Unity] 유니티 이해하기 02 - 이벤트 함수의 실행순서 그리고 스크립트 (0) | 2025.01.24 |
[Unity] 유니티 이해하기 01 - 게임오브젝트와 컴포넌트 (0) | 2025.01.24 |
[Unity] 유니티 프레임 워크, .NET과 GC (0) | 2025.01.24 |