유니티를 공부하다보면 자연스럽게 접하게 되는 것이 Mono와 il2cpp이다.

둘에 대해 알아보도록 하자.

 

스크립팅 백엔드

스크립팅 백엔드란, 우리가 작성한 스크립트를 실행가능한 언어로 번역하는 것을 의미한다. 쉽게 말하면 컴파일러와 비슷한 의미이다. 다만, 컴파일러보다 조금 더 역할이 많은 넓은 범위라고 생각하면 될 것 같다. 유니티에서 우리가 개발하는 게임에 어떤 스크립팅 백엔드를 사용할 지 설정할 수 있으며 유니티에서 제공하는 두 선택지가 모노와 il2cpp인 것이다.

 

Mono

C#은 기본적으로 .Net Framework 위에서 작동한다. 닷넷 프레임워크는 Windows에서만 실행된다는 한계가 있다. 자마린 사는 이러한 문제점을 극복하고 닷넷 프레임워크 위에서 설계된 어플리케이션이 다양한 플랫폼에서 실행되기를 원했고, 닷넷 프레임워크를 기반으로 크로스 플랫폼을 지원하는 프레임워크를 만들고자 했다고 한다. 그리고 그 프로젝트의 이름이 Mono라고 한다.

 

.Net Framework는 소스가 공개되지 않았기 때문에 mono 프로젝트 초창기엔 자마린과 마이크로 소프트 사이에 여러가지 갈등이 있었다고 한다. 시간이 흐른 후, 마이크로 소프트의 운영 방침이 바뀌면서 .Net Framework의 오픈소스 버전을 새로 만들었고 이 오픈 소스를 기반으로 모노 프로젝트가 지금까지 진행되고 있다고 한다.

 

Unity에서 지원하는 Mono가 바로 이 Mono이다. 다만, 완전히 동일한 것은 아니다. 유니티에서 사용하는 Mono는 자마린의 Mono 프로젝트를 포크(원본을 완전히 복제하는 것)하여 게임 개발에 맞게 최적화 및 추가 기능을 더한 것이라고 한다.

 

Mono는 .Net Framework에 뿌리를 두고 있기 때문에 작동 방식이 매우 유사하다. IL이라는 중간 언어로 컴파일 해놓고 런타임에 기계어로 변환하며 프로그램을 실행한다.

 

il2cpp

Mono는 위에서 말했듯이 IL이라는 중간 언어로 컴파일 한 뒤, 런타임에 기계어로 번역하는 방식으로 프로그램을 실행한다. 하지만 이렇게 프로그램을 실행하게 되면 당연히 그 속도가 느릴 수 밖에 없다. 코드를 완전히 기계어로 번역해놓고 런타임에 추가적인 작업을 하지 않는 cpp에 비해서 말이다. 

 

il2cpp는 이러한 이유로 만들어진 것이다. 게임이라는 것은 최적화가 정말 무지무지 중요한 어플리케이션이다. 무지막지한 그래픽스 렌더링과 물리, 수학 연산을 하면서 1초에 60프레임을 꾸준히 유지해줘야 하니 말이다. 이를 위해 unity에선 스크립팅 백엔드의 추가적인 선택지로 il2cpp를 만들었다. 

 

il2cpp는 우리가 작성한 스크립트를 IL로 컴파일하고 IL을 다시 CPP 코드로 번역한다. 그리고 이 CPP 코드를 다시 컴파일하여 완전히 기계어로 번역된 프로그램을 생성하고 이를 통해 게임을 실행하게 된다. 

 

mono vs il2cpp

위에서 설명한 내용을 이해했다면 두 스크립팅 백엔드의 장단점은 정말 명확하게 알 수 있을 것이다.

 

mono는 편한 대신 성능이 느리다. 컴파일 시간이 상대적으로 매우 짧기 때문에 유연하게 코드를 변경하며 개발을 실행할 수 있다. 반면 런타임 성능이 상대적으로 낮기 때문에 무거운 게임을 만들게 된다면 최적화 부분에서 신경을 정말 많이 써야할 것이다.

 

반면 il2cpp는 컴파일 시간이 상대적으로 매우 긴만큼 개발에 있어 불편함이 따를 것이다. 하지만 그만큼 런타임 성능이 우수하기 때문에 무거운 게임을 만들수록 il2cpp의 이점을 크게 느낄 수 있을 것이다.

'유니티 > 엔진 기초' 카테고리의 다른 글

유니티 기초 - 모노 비헤이비어 (MonoBehaviour)  (0) 2024.08.07

유니티에서 씬에 사용될 게임 오브젝트를 C# 스크립트 파일로 생성해보면, MonoBehaviour이라는 클래스를 상속받은 채로 클래스가 생성되어 있는 것을 볼 수 있다.

 

이러한 MonoBehaviour 클래스는 왜 존재하는 것이며 왜 상속받고 있는 것일까?

 

MonoBehaviour

유니티 Docs에 따르면, MonoBehaviour클래스의 가장 큰 역할은 에디터와 스크립트 파일을 연결해주는 것이다.

 

C#으로 작성된 클래스를 에디터에서 읽고, 뷰포트에 띄우고, 컴포넌트를 추가하는 등의 작업을 하기 위해선 해당 클래스에 대한 정보를 에디터가 알아야 할 필요가 있는데, 이를 도와주는 것이 MonoBehaviour 클래스인 것이다.

 

즉, 에디터에서 해당 클래스를 어떤 방식으로든 이용하고 싶다면 MonoBehaviour 클래스를 상속받는 것은 선택이 아닌 필수인 것이다.

 

MonoBehaviour의 역할은 물론 그것 하나 뿐만은 아니다. 아래의 사진을 보자.

해당 사진은 유니티에서 제공하는 유니티 엔진 스크립트의 생명주기를 설명하는 사진이다. 유니티 엔진이 매 프레임 어떻게 동작하고 어떤 함수들을 어떤 순서대로 호출하는지를 보여주는 것이다.

 

우리가 작성한 클래스가 위의 생명주기에 맞춰서 동작하기 위해선 그냥 클래스를 냅다 만든다고 되는 것이 아니다. 유니티에서 제공하는 프레임워크를 벗어나서 마음대로 클래스를 만들게 되면, 이는 위의 생명주기를 벗어나 독자적으로 활동하게 된다. 그렇게 되면, 유니티 엔진에서 제공하는 다양한 기능을 활용할 수 없을 뿐더러 안정성도 해치는 일이 된다.

 

하지만, MonoBehaviour를 상속받게 되면 해당 클래스는 유니티 엔진 스크립트의 생명 주기와 결합이 된다. 위의 사진의 사이클 안에서 작동하게 되는 것이다. 즉, MonoBehaviour 클래스는 유니티 엔진의 프레임워크를 강제하는 역할도 하는 것이다.

 

MonoBehaviour 클래스를 상속받는다면 발생하는 이점이 이것 뿐만은 아니다. 위에서 말했던 것처럼 MonoBehaviour를 상속받게 되면, 유니티 엔진의 프레임워크를 강제받게 된다. 즉, 우리는 유니티 엔진에서 안내하는 방식으로 클래스를 설계하고 구성해야 한다는 것이다. 

 

이 것은 어떻게 보면 불편하고 제약적인 행동으로 보일 수도 있지만, 이를 통해서 우리는 엔진의 구체적인 기능을 이해하지 않아도 클래스를 설계할 수 있게 된다. MonoBehaviour로부터 제공받는 Start(), Update() 등의 함수가 엔진 내부에서 정확히 어떻게 동작하는 지를 이해할 필요 없이 어떠한 역할을 하는지만 이해한다면 우리의 의도대로 작동하는 클래스를 설계할 수 있게 된다. 즉, MonoBehaviour를 상속받고 유니티 엔진이 제공하는 프레임워크에 강제받게 됨으로써 우리는 엔진의 구체적인 작동방식을 이해하지 않아도 클래스를 설계할 수 있게 되는 것이다. 

 

정리해보자면 MonoBehaviour의 역할은 크게 3가지로 볼 수 있다.

 

1. C#으로 작성된 클래스와 에디터를 연결해준다.

2. 사용자에게 유니티 엔진의 프레임워크를 강제한다.

3. 엔진을 구체적으로 이해하지 못해도 사용할 수 있도록 도와준다.

'유니티 > 엔진 기초' 카테고리의 다른 글

유니티 기초 - 스크립팅 백엔드 (Mono, il2cpp)  (1) 2024.08.24

+ Recent posts