프로젝트 구성
Udonite가 어떤 스크립트를 컴파일하는지, 어셈블리 정의는 어떻게 얽히는지, 그리고 코드를 Udon에서 빼는 방법.
프로그램이 되는 스크립트
아래를 모두 만족하는 클래스가 Udon 프로그램이 됩니다.
MonoBehaviour를 상속합니다. 직접이든UdoniteBehaviour를 거치든 상관없습니다abstract가 아니고, 제네릭이 아니며, 다른 형식 안에 중첩되어 있지 않습니다- 스크립트가
Assets/아래 어딘가에 있습니다
조건을 만족하는 클래스는 모두 루트이고, 루트마다 같은 GameObject에 자기 몫의 Udon 프로그램이 붙습니다. 등록할 것도 없고 특별한 폴더도 없습니다. Assets/Scripts/Doors/Door.cs에 있는 스크립트든 Assets/Door.cs에 있는 스크립트든 똑같은 방식으로 찾습니다.
조건을 만족하지 않는 클래스는 오류가 아닙니다. 추상 기반 클래스, 제네릭 헬퍼, 단순 데이터 클래스, 정적 유틸리티는 behaviour가 쓰는 평범한 C#입니다. 그 자체가 프로그램이 되지 않을 뿐입니다.
어셈블리 정의
어셈블리 정의를 쓰든 쓰지 않든 Udonite는 똑같이 동작합니다.
어셈블리 정의가 아무 데도 없으면 스크립트는 Unity 기본 Assembly-CSharp에 들어가고 Udonite가 그것을 컴파일합니다. .asmdef를 두면 스크립트는 그 어셈블리에 들어가고 Udonite는 그쪽을 컴파일합니다. 어느 한쪽이 정식 경로이고 다른 쪽이 우회책인 것이 아닙니다. 규칙은 그 어셈블리가 Assets/ 아래에 소스를 두고 있다는 것뿐입니다.
이건 들리는 것보다 중요합니다. 어셈블리가 코드에서 무엇이 보이는지를 두 가지 결정하기 때문입니다.
참조. behaviour는 자신의 어셈블리가 참조하는 어떤 형식이든 쓸 수 있습니다. 월드를 World.Runtime과 World.Interactables로 나누고 후자가 전자를 참조한다면, World.Interactables의 behaviour는 World.Runtime의 형식을 평소처럼 쓸 수 있습니다.
정의 심볼. 어셈블리가 컴파일에 쓰는 스크립팅 정의 심볼이 곧 Udonite가 컴파일에 쓰는 심볼입니다. 그래서 #if UNITY_EDITOR도, 직접 만든 정의도 프로젝트의 다른 곳과 똑같이 동작합니다.
에디터 전용 어셈블리는 건너뜁니다. 플랫폼 목록이 Editor로 설정된 .asmdef에 든 것은 도구이지 월드 로직이 아니므로, 그 안의 어떤 것도 Udon으로 컴파일되지 않습니다.
여러 파일로 나누기
behaviour는 파일 하나에 담긴 것에 갇히지 않습니다. 같은 어셈블리의 다른 파일에 있는 헬퍼 클래스, enum, 인터페이스, 기반 클래스를 그대로 쓸 수 있으므로 월드는 필요한 만큼 파일을 나눠도 됩니다.
경계는 파일이 아니라 어셈블리입니다. 헬퍼가 다른 어셈블리에 있다면 behaviour의 어셈블리가 그것을 참조해야 합니다. Unity의 다른 곳과 같습니다.
패키지 안의 스크립트
Packages/ 아래의 스크립트는 Udon으로 컴파일되지 않습니다. 빠뜨린 것이 아니라 의도한 것입니다. 가져온 패키지에는 Udon의 존재를 모른 채 작성된 MonoBehaviour 클래스가 수백 개 들어 있을 수 있습니다. 그것을 컴파일하면 직접 쓰지도 않았고 고칠 수도 없는 코드에 대한 거부로 콘솔이 묻혀버립니다.
예외는 Udonite가 직접 제공하는 컴포넌트, 예를 들어 NetworkTransform입니다. 이들은 월드에서 돌아가도록 만들어졌으므로 패키지 안에 있어도 컴파일됩니다.
패키지의 behaviour를 월드에서 쓰고 싶다면, Assets/ 아래에 자신의 behaviour를 쓰고 거기에서 패키지의 컴포넌트를 다루는 것이 확실한 방법입니다.
UdonSharp와 함께 쓰기
UdonSharpBehaviour를 상속한 클래스는 건드리지 않고 UdonSharp가 컴파일하도록 둡니다. Udonite는 MonoBehaviour 클래스만 맡으므로 두 컴파일러가 같은 스크립트를 두고 다투지 않고 한 프로젝트에서 함께 돌아갑니다.
코드를 Udon에서 빼기
Assets/ 아래에 있어도 프로그램이 되어서는 안 되는 코드가 있습니다. 에디터 도구, 데스크톱에서만 돌아가는 외부 컴포넌트, 아직 옮기는 중인 스크립트 같은 것들입니다. 제외하면 Udonite는 그것을 더 이상 컴파일하지 않습니다.
가장 빠른 방법은 체크박스입니다. Udonite → Open Window를 열고 Overview 탭의 트리에서 그 스크립트나 폴더의 체크를 해제하세요. 폴더를 해제하면 그 아래 전부가 제외됩니다. 이미 제외된 것을 다시 체크하면, 비활성화된 줄을 남기는 대신 제외 자체를 없앱니다. 제외된 스크립트나 폴더는 사라지지 않고 트리 안에서 회색으로 남습니다. 열려 있는 씬에 아직 살아 있는 인스턴스가 있으면 경고가 뜹니다. 그 인스턴스는 곧 Udon 프로그램을 받지 못하게 되기 때문입니다. 같은 창의 Diagnostics 탭과 Settings 탭은 시작하기에서 다룹니다.
어떤 체크박스든 뒤에서는 같은 파일을 읽고 씁니다. 손으로 편집해도 체크박스와 똑같이 동작합니다. 제외 항목은 ProjectSettings/UdoniteExclusions.txt에 한 줄에 하나씩 적습니다. 순서는 상관없습니다. 한 줄은 어셈블리 이름이거나 애셋 GUID입니다.
# Udonite 제외 목록. 한 줄에 하나이며 순서는 상관없습니다.
asm:SomeVendor.Runtime # 월드에서는 결코 돌아가지 않을 패키지
guid:3c6e5249679282e459858775b10f38d0 # Assets/Editor/LevelBuilder.cs
asm:은 어셈블리 이름을 받습니다. 서드파티 패키지를 통째로 뺄 때는 보통 이쪽입니다. Unity가 그런 패키지를 하나의 어셈블리로 컴파일하기 때문입니다.
guid:는 Unity의 16진수 32자리를 받습니다. 애셋 옆의 .meta 파일에 있습니다. 스크립트 하나를 가리킬 수도 폴더를 가리킬 수도 있으며, 폴더를 가리키면 그 아래 전부가 제외됩니다.
GUID인 데에는 이유가 있습니다. 경로는 누군가 파일을 옮기는 순간 더 이상 맞지 않게 되고, 그것도 아무 말 없이 그렇게 됩니다. 이런 규칙에는 가장 나쁜 방식의 고장입니다. GUID는 옮겨져도 살아남습니다. 줄 끝의 # 메모를 남겨둘 값어치가 있는 것도 같은 이유입니다. 언젠가 GUID가 풀리지 않게 되면, 그 줄이 무엇이었는지 알려주는 기록은 그 메모뿐입니다. 애셋이 삭제되면 그 줄은 파일을 다음에 무언가 읽는 순간 — 창을 열 때든, 다음 컴파일 때든 — 자동으로 지워지며, 아무것도 가리키지 않는 GUID로 남지 않습니다.
폴더의 GUID는 손으로 찾기 번거롭습니다. Unity는 자기 UI 어디에도 그것을 보여주지 않습니다. Overview에서 폴더를 제외하면 GUID를 입력할 필요가 전혀 없으며, 그것이 파일에 폴더의 줄을 넣는 확실한 방법입니다.
다시 포함하는 방법은 없습니다. 폴더 제외를 그 안의 파일 하나만 나중에 다시 포함시켜 좁힐 수는 없습니다. 그 파일 자체의 GUID를 폴더 밖에서 제외하거나, 제외된 폴더 밖으로 옮기세요.
항목은 지우지 않고 끌 수도 있습니다. !asm:Cinemachine처럼 앞에 !를 붙이면 줄(과 그 메모)은 파일에 남지만 그 상태에서는 아무것도 제외하지 않습니다 — Overview에서는 그 스크립트가 포함된 것으로 보이며, 줄이 없는 것과 똑같이 보입니다. !를 쓰는 것은 손으로 하는 일이고, Overview가 대신 해 주지 않습니다. 하지만 그 뒤에 같은 스크립트를 Overview에서 제외하면, 중복을 쓰는 대신 그 줄을 다시 활성화합니다. 손으로 붙인 !를 되돌리는 데 GUID를 다시 칠 필요가 없다는 뜻입니다. 그 뒤에 다시 포함시키면, 이번에는 비활성화가 아니라 줄 자체를 아예 없앱니다.
여기서 자주 어긋나는 것이 둘 있어 각자 코드를 가지고 있습니다. Udonite가 읽지 못하는 줄은 기대하는 형식과 함께 UDN0007로 보고됩니다. 제외한 코드를 여전히 호출하는 behaviour는 UDN0008로 보고됩니다. 월드에서는 그 호출이 닿을 곳이 없기 때문입니다.
작업하는 동안 Udonite가 알려 주는 것
컴파일보다 먼저 알려 주는 것이 둘 있고, 둘 다 이미 보고 있는 자리에서 읽히도록 만든 것입니다.
에디터의 물결선. Udonite는 Roslyn 애널라이저를 함께 배포하므로, 몇 가지 거부는 컴파일 뒤가 아니라 타이핑하는 동안 나타납니다. 변경 가능한 static 필드, catch 절, 그리고 Udon이 결코 호출하지 않는 Unity 이벤트입니다. 컴파일러와 같은 UDN 코드를 달고 있어서, 검색하면 답이 둘이 아니라 하나 나옵니다.
이것들은 경고이고, 모든 것을 잡아내지는 않습니다. 에디터가 깨끗하다고 해서 프로그램이 컴파일되는 것은 아닙니다. 그건 컴파일해 봐야 알 수 있습니다.
비어 있는 behaviour 참조. 다른 behaviour를 가리키는 public 필드에 아무것도 연결되어 있지 않으면, 콘솔이 behaviour와 필드 이름을 짚어 알려 줍니다.
Udonite: Switch on 'Door Controls' has an empty behaviour reference: 'target'.
Calling through one halts the behaviour for the rest of the session with nothing
logged, so wire it in the inspector, or make the field private if the script
assigns it itself.
보고되는 것은 다른 behaviour에 대한 참조뿐입니다. 비어 있는 GameObject나 AudioSource 필드는 평범하고 의도적인 경우도 많습니다. behaviour 참조는 호출되기 위해 존재하고, null인 채로 호출하는 것이 바로 아무 흔적도 남기지 않는 실패입니다.
프로그램이 놓이는 곳
각 프로그램은 해당 behaviour와 같은 GameObject에 붙고, 업로드할 때 월드에 실리는 것이 바로 그것입니다. C#은 다음 편집을 위해 프로젝트에 남습니다. 평소 외에 따로 커밋할 것은 없습니다. 프로그램은 Unity가 다시 컴파일할 때마다, 그리고 씬을 저장할 때마다 다시 만들어집니다.