TL;DR

  • Unity의 본질은 GameObject-Component 조합, Scene/Prefab 자산 구조, MonoBehaviour 라이프사이클이다.
  • Mono, IL2CPP, Burst, SRP, Addressables, asmdef 같은 런타임·빌드 도구를 이해해야 팀 규모가 커져도 유지된다.
  • XR에서는 Unity OpenXR Plugin, XRI, Meta OpenXR 조합이 현재 기본 경로다.

1. 개념

Unity는 C# 스크립팅과 GameObject-Component 모델, 에디터 중심 제작 방식, 멀티플랫폼 빌드를 묶은 실시간 3D 엔진이다. 게임뿐 아니라 모바일 앱, 시뮬레이터, XR 콘텐츠 제작에 널리 쓰인다.

2. 배경

2000년대 중반 게임 엔진 시장은 비싸고 대형 스튜디오 중심이었다. Unity는 저렴한 가격, 쉬운 에디터, 빠른 멀티플랫폼 전개, Asset Store 생태계를 무기로 인디와 모바일 시장에서 빠르게 확산됐다.

3. 이유

Unity 프로젝트는 코드만이 아니라 Scene, Prefab, Package, Import 설정, 빌드 파이프라인이 함께 동작한다. 이 구조를 모르면 Missing Reference, 빌드 실패, 성능 문제, XR 설정 충돌을 반복하게 된다.

4. 특징

  • GameObject–Component, Scene, Prefab 기반 제작 모델
  • Mono/IL2CPP/Burst와 asmdef를 조합한 런타임·컴파일 구조
  • URP/HDRP, Addressables, DOTS/ECS 등 확장 가능한 엔진 스택
  • XR Plugin Framework, OpenXR, XRI, PolySpatial 같은 플랫폼 연동
  • 에디터·패키지·CI/CD를 포함한 제작 파이프라인 중심 개발 경험

5. 상세 내용

Unity 게임 엔진 완전 가이드

작성일: 2026-04-29 카테고리: Game Dev / XR / Unity / C# 포함 내용: Unity Technologies, GameObject, Component, Prefab, Variant Prefab, Nested Prefab, Scene, Hierarchy, Project 구조, Library/Packages/ProjectSettings, AssetDatabase, .meta, GUID, FileID, Mono/IL2CPP/Burst/Mono.Cecil, Editor/Player, Build Profile, Inspector/Hierarchy/Project Window, Awake/Start/Update/FixedUpdate/LateUpdate, OnEnable/OnDisable/OnDestroy, Coroutine, async/await, UniTask, Awaitable, ScriptableObject, MonoBehaviour, Transform/Rigidbody/Collider, Canvas/RectTransform, URP/HDRP/Built-in/SRP, ShaderGraph, VFX Graph, Addressables/Asset Bundles, DOTS/ECS/Burst/Job System, UI Toolkit/UGUI/IMGUI, Input System, Cinemachine/Timeline, Visual Scripting (Bolt), TextMeshPro, NGO/Mirror/Photon/FishNet, Unity Hub/Cloud/Build Server, Plastic SCM/Unity Version Control, Polyspatial visionOS, Unity 6 GPU Resident Drawer, Single Pass Instanced, Foveated Rendering, Application SpaceWarp, XR Plugin Framework, Unity OpenXR Plugin, XR Interaction Toolkit, AR Foundation, Meta XR SDK, Genshin Impact / Among Us / Pokemon GO / Hearthstone / Cuphead / Hollow Knight / Beat Saber / VRChat / MRTK / Polyspatial 사례, ScriptableObject Event Channel, Zenject/VContainer DI, .asmdef, GameCI


1. Unity란?

┌─────────────────────────────────────────────────────────────────┐
│                    Unity 한 줄 정의                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  "C# 스크립팅 + GameObject-Component 모델 + 멀티플랫폼 빌드를     │
│   하나의 에디터에서 통합 제공하는 게임/XR 개발 엔진"              │
│                                                                  │
│  ┌──────────────────────────────────────────────────────┐       │
│  │  특징:                                                │       │
│  │  ├── 1) Composition over Inheritance                  │       │
│  │  ├── 2) MonoBehaviour 라이프사이클 (Awake/Start/...)  │       │
│  │  ├── 3) 단일 코드베이스 → iOS/Android/PC/콘솔/웹/XR   │       │
│  │  ├── 4) Mono(JIT) / IL2CPP(AOT) / Burst(LLVM SIMD)   │       │
│  │  ├── 5) URP/HDRP — Scriptable Render Pipeline        │       │
│  │  ├── 6) Asset Store + UPM (Package Manager)           │       │
│  │  └── 7) DOTS/ECS — 데이터 지향 고성능 옵션            │       │
│  └──────────────────────────────────────────────────────┘       │
└─────────────────────────────────────────────────────────────────┘

2. 용어 사전 (Terminology Dictionary)

2.1 회사 / 엔진

용어 풀 이름 의미와 어원
Unity “통일/하나됨”. (1) 기술적 통합: 하나의 에디터에서 멀티플랫폼 빌드, (2) 커뮤니티 통합: 대형 스튜디오와 인디 개발자 통합
Unity Technologies 2004년 8월 코펜하겐 “Over the Edge I/S”로 창립, 2007년 사명 변경. 미션: “Democratize game development”

2.2 핵심 객체 모델

용어 의미와 어원
GameObject 씬의 모든 존재의 기본 단위. 자체 기능 없음, Transform만 보유. 캐릭터/카메라/조명/빈 컨테이너 모두 GameObject
Component 라틴어 componere (조합). GameObject에 부착되는 기능 모듈. Composition over Inheritance 패턴. GoF Component Pattern에서 차용
Prefab prefabricated (사전 제작된)의 줄임말. 건축업 “조립식 건물”에서 차용. .prefab 에셋으로 저장되어 인스턴스화 가능
Prefab Variant (2018.3+) Base Prefab을 상속받아 일부만 오버라이드한 파생. 객체지향 상속을 Prefab 시스템에 도입
Nested Prefab (2018.3+) Prefab 내부에 다른 Prefab 포함. 2018.3 이전에는 불가능
Scene 연극/영화의 “장면”. .unity 파일. GameObject가 배치된 3D 공간
Hierarchy 그리스어 hierarchia (성스러운 지배). Transform의 부모-자식 관계와 1:1 대응하는 트리
Inspector 라틴어 inspicere (들여다보다). 선택된 객체의 모든 속성 편집 창

2.3 에셋 / 직렬화

용어 풀 이름 의미
AssetDatabase Unity Editor 전용 API. 에셋 임포트/수정/삭제/검색 프로그래밍
.meta 모든 에셋에 자동 생성되는 사이드카 파일. VCS 필수 포함
GUID Globally Unique Identifier 128-bit 고유 ID. 파일 경로/이름 변경에도 참조 유지
FileID (LocalIdentifierInFile) 단일 에셋 내 객체 구별. Prefab 내 GameObject/Component 각각 다른 FileID
Force Text Project Settings → Editor → Asset Serialization. .asset/.prefab/.unity를 YAML 텍스트로 → git diff 가능

2.4 런타임 / 컴파일

용어 풀 이름 의미
Mono 그리스어 monos (단독). MS .NET의 오픈소스 재구현. JIT. 에디터 + 일부 Standalone
IL2CPP Intermediate Language to C++ C# IL → C++ 변환 → 네이티브 컴파일. AOT. iOS/WebGL/콘솔 필수
Burst “burst”(폭발적 처리). LLVM 기반 AOT/JIT. SIMD 벡터화. Job System / DOTS 전용
Mono.Cecil .NET IL 바이트코드를 Reflection 없이 읽고 수정. Weaver 도구, Mirror/NGO RPC 자동생성

2.5 MonoBehaviour 라이프사이클

콜백 설명
Awake 스크립트 인스턴스 로드 시. 비활성 오브젝트도 호출. 자기 자신 초기화
OnEnable 활성화될 때마다. Start 이전
Reset Editor만. Add Component / Reset 메뉴 시
Start 첫 Update 직전 1회. 모든 Awake 완료 후. 다른 오브젝트 참조 안전
FixedUpdate 물리 스텝 (기본 0.02초 = 50Hz). Rigidbody.AddForce 등
OnTrigger/CollisionEnter/Stay/Exit 물리 콜백. FixedUpdate 직후
Update 매 프레임. 메인 게임 로직
LateUpdate 모든 Update 후. 카메라 추적, 최종 상태
OnPreCull / OnBecameVisible/Invisible / OnRenderImage 렌더링 콜백
OnDisable / OnDestroy 비활성화 / 파괴
OnApplicationQuit / Pause / Focus 앱 종료 / 일시정지 / 포커스 (모바일)
OnValidate Editor만. Inspector 값 변경 시

2.6 Coroutine vs async/await

용어 의미
Coroutine 1958년 Melvin Conway 제안. C# IEnumerator + yield return. 메인 스레드 전용, Unity API 완전 사용 가능
async/await C# 5.0 (2012). Unity 2017.1 지원. Task 반환, 멀티스레드 가능, 메인 스레드 API 제한적
UniTask Cysharp 오픈소스. async/await 대체. 거의 zero allocation, Unity 메인 스레드 통합
Awaitable Unity 2023+ 내장. UniTask 유사. await NextFrameAsync() / WaitForSecondsAsync()

2.7 ScriptableObject

용어 의미
ScriptableObject “스크립트 가능한 객체”. GameObject가 아닌 에셋 파일(.asset). 씬 독립, 메모리 공유
CreateAssetMenu [CreateAssetMenu] 어트리뷰트로 Editor에서 우클릭 생성
이벤트 채널 Unity 공식 Open Project 1 패턴. UnityAction + ScriptableObject 조합

2.8 물리 / UI

용어 어원
Transform 위치/회전/크기 변환 행렬. 모든 GameObject에 필수
Rigidbody 물리학 “강체(Rigid Body)”. PhysX가 이동/회전 제어
Collider “충돌하는 것”. Rigidbody와 분리 → Trigger 구현 가능
Canvas “화폭”. UI 요소가 그려지는 2D 공간. 4.6에 UGUI와 함께 도입
RectTransform Transform 파생. Width/Height/Anchors/Pivot 추가

2.9 렌더링

용어 풀 이름 의미
SRP Scriptable Render Pipeline 2018.1 도입. C# API로 렌더링 파이프라인 전체 커스터마이징
Built-in 2018 이전 고정 파이프라인. “레거시”. 신규 비권장
URP Universal Render Pipeline 2019.3에 LWRP에서 개명. 모바일~PC 범용
HDRP High Definition Render Pipeline 고사양 PC/콘솔. PBR, 레이트레이싱, 볼류메트릭
ShaderGraph 2018 도입. 노드 기반 비주얼 셰이더 → ShaderLab 자동 생성
VFX Graph 2018.3 도입. GPU 컴퓨트 셰이더, 수백만 파티클

2.10 데이터 지향 (DOTS)

용어 풀 이름 의미
DOTS Data-Oriented Technology Stack ECS + Job System + Burst
ECS Entity Component System Entity(정수 ID), Component(데이터 struct), System(로직)
Job System C# 멀티스레드 작업 안전 스케줄링. NativeArray로 race condition 방지
Burst LLVM AOT. SIMD. NativeContainer만 사용

2.11 UI / 입력

용어 의미
IMGUI Immediate Mode GUI. OnGUI(). 매 프레임 즉시 그림. Editor 확장에만 사용
UGUI Unity GUI / uGUI. 4.6 도입. GameObject 기반. Canvas/Image/Text
UI Toolkit (UIElements) 2019.1 Editor용 → 2021.2 런타임. UXML/USS/C#. Flexbox 레이아웃. Retained Mode
Legacy Input Manager Input.GetKey(). Edit > Project Settings > Input
New Input System 2019.1+. Action Map → Action → Binding. 동적 리매핑, 멀티플레이어

2.12 미디어 / 도구

용어 의미
Cinemachine “영화적 카메라”. 가상 카메라, 돌리 트랙. 2017 통합
Timeline 시퀀서. 트랙/클립 기반 컷씬 편집
Visual Scripting (Bolt) Ludiq의 Bolt를 2020년 4월 Unity가 인수. 2021 LTS 내장
TextMeshPro Stephan Bouchard 개발 → Unity 2017 인수. SDF 폰트. 2023.2부터 uGUI 패키지에 병합

2.13 네트워킹

솔루션 개발사 특성
NGO (Netcode for GameObjects) Unity 공식 GameObject 기반, 소규모 협동 (2-10인)
Mirror OSS UNET 후속, 성숙, LAN
Photon (PUN/Fusion) Exit Games 클라우드 호스팅, 매치메이킹
FishNet OSS 고성능, 대역폭 효율

2.14 인프라 / 플랫폼

용어 의미
Unity Hub 2018 도입. 다중 에디터 버전, 프로젝트, 라이선스 관리
Unity Cloud UGS (Unity Gaming Services). 빌드/분석/멀티플레이어
Unity Build Server 사내 서버 빌드 라이선스. CI/CD
Plastic SCMUnity Version Control 2020.08 인수. 대용량 바이너리 강함
Polyspatial Poly(다양) + Spatial(공간). visionOS 패키지. 렌더링은 Apple RealityKit 위임

3. Unity 등장 배경

3.1 2004년의 게임 엔진 시장

┌─────────────────────────────────────────────────────────────────┐
│                  Pre-Unity (2004) 풍경                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Unreal Engine 2/3   $$$ 수십만 달러 라이선스 → 대형 스튜디오 전용│
│  CryEngine 1         사내 전용 (Far Cry용)                       │
│  Torque              $99 (혁신적이었지만 UX 열악, 문서 부족)     │
│  GameMaker           무료/저가, 비프로그래머용 2D                │
│  Adventure Game Studio 무료, 어드벤처 전용                       │
│                                                                  │
│  결과: "3D 멀티플랫폼을 합리적 비용으로" 가능한 도구 부재         │
└─────────────────────────────────────────────────────────────────┘

3.2 Unity 승리의 5가지 요인

  1. 가격 파괴: 초기 $1,500 (Pro), $200 (Hobby) — 경쟁사의 1/100
  2. 접근성: 드래그앤드롭, 비주얼 에디터 중심
  3. 2009 무료 버전: 사용자 수 하룻밤 사이 2배 → 대학 강의실
  4. 2008 iPhone App Store: 대형사가 iOS를 무시하는 사이 Unity 사용자가 시장 선점
  5. Asset Store (2010): 커뮤니티 에셋/플러그인 마켓 → Network Effect

4. 역사 연대표

연도 사건
2002 세 창립자 OpenGL 포럼에서 만남
2004.08 코펜하겐 “Over the Edge I/S” 설립 (Helgason, Ante, Francis)
2005.06 WWDC에서 Unity 1.0 발표 (Mac OS X 전용). 첫 게임 GooBall 상업 실패 → 엔진 회사로 피벗
2007 “Unity Technologies”로 사명 변경. Unity 2.0: DirectX, 동적 그림자
2008 iPhone App Store 출시 → Unity iOS 지원
2009.03 Unity 2.5: Windows 에디터 지원
2009.10 무료 버전 출시 → 사용자 폭증
2010 Unity 3.0: Android, Beast 라이트맵. Asset Store 오픈
2012 Unity 4.0: DirectX 11, Mecanim 애니메이션, Linux 프리뷰
2015 Unity 5.0: PBR, WebGL, 무료 Personal Edition
2016.12 버전 체계 변경: 순번 → 연도 (2017.x …)
2017 Timeline, Cinemachine, Autodesk 통합
2018 SRP (URP/HDRP), ShaderGraph, VFX Graph, Burst, ECS 프리뷰. Unity Hub
2019 URP/HDRP 프로덕션, 새 Input System, UI Toolkit Editor
2020.08 Plastic SCM 인수 (Unity Version Control 전신)
2020.09 NYSE 상장 (티커: U). $52 → $200 돌파
2021 LTS Visual Scripting(Bolt) 내장, Apple Silicon, UI Toolkit 런타임
2022.07 ironSource $4.4B 인수 발표 (전액 주식)
2022.11 ironSource 합병 완료
2023.09 Runtime Fee 발표 → 대규모 반발. Godot/Unreal 이탈
2023.10 John Riccitiello CEO 사임. James Whitehurst 임시
2024 Matthew Bromberg 신임 CEO. Runtime Fee 완전 철회
2024.10 Unity 6 출시 (연도 체계 탈피). GPU Resident Drawer, AI(Muse/Sentis), OpenXR 주력, ECS 코어 통합
2025.04 Unity 6.1: Deferred+, 폴더블
2025+ Unity 6.2/6.4 베타. DirectStorage

Runtime Fee 사태 (2023)

2023.09.12  설치당 요금 발표 — 수익 $200K + 설치 200K 초과 시 $0.01~0.20/설치
            ├── 설치 = 매출 아님 (F2P 위협)
            ├── 소급 적용 (계약 신뢰 훼손)
            └── 설치 수 조작 공격 가능

반응       대형 스튜디오 사용 중단 선언
           voodoo, Century Games — Unity Ads 수익화 일시 중단
           Godot 후원 폭증
2023.09.22  수정안 (수익 2.5%) — 여전히 반발
2023.10.09  Riccitiello CEO 사임
2024        Bromberg CEO, Runtime Fee 완전 철회 → 구독 인상 방식

유산        "한번 잃은 신뢰는 회복하기 어렵다"

5. 프로젝트 구조

5.1 폴더 구조

MyProject/
├── Assets/                          ← VCS 포함 필수
│   ├── _Project/                    (컨벤션: 프로젝트 전용)
│   │   ├── Core/
│   │   │   └── Core.asmdef
│   │   ├── Features/
│   │   │   ├── Player/
│   │   │   │   ├── Scripts/
│   │   │   │   ├── Prefabs/
│   │   │   │   └── Player.asmdef
│   │   │   └── Enemy/
│   │   └── Shared/
│   ├── Editor/                      (어디 있든 Editor 빌드만)
│   ├── Plugins/                     (Phase 1 컴파일, 서드파티 DLL)
│   ├── Resources/                   (런타임 Resources.Load — 레거시)
│   ├── StreamingAssets/             (압축 없이 그대로 패키징)
│   └── ThirdParty/
├── Library/                         ← VCS 제외
│   ├── ArtifactDB                   (애셋 임포트 DB)
│   ├── ScriptAssemblies/            (컴파일 .dll)
│   ├── ShaderCache/
│   └── il2cpp_cache/
├── Packages/                        ← VCS 포함 필수
│   ├── manifest.json
│   └── packages-lock.json
├── ProjectSettings/                 ← VCS 포함 필수
│   ├── ProjectVersion.txt
│   ├── TagManager.asset
│   ├── InputManager.asset
│   └── GraphicsSettings.asset
├── UserSettings/                    ← VCS 제외 (개인 설정)
├── Logs/                            ← VCS 제외
├── Temp/                            ← VCS 제외 (자동 생성/삭제)
└── Build/                           ← VCS 제외

5.2 .meta / GUID / FileID

# Sword.prefab.meta
fileFormatVersion: 2
guid: e3ad2bf01b7a6b7409eb683402aa8668   ← 불변 식별자
NativeFormatImporter:
  externalObjects: {}
  mainObjectFileID: 100100000
  userData:
# Scene 파일 내 컴포넌트 참조
m_Script: {fileID: 11500000, guid: e3ad2bf01b7a6b7409eb683402aa8668, type: 3}
필드 의미
guid 어느 파일인지 (.meta GUID)
fileID 파일 내 어느 객체인지
type 0=embedded, 2=external, 3=meta-referenced

Missing Reference의 가장 흔한 원인: 탐색기/Finder에서 파일 직접 이동/이름 변경 → .meta 미동행 → GUID 연결 끊김.

5.3 .gitignore + .gitattributes

/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/UserSettings/
/Logs/
/*.csproj
/*.sln
.vs/
*.png filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.unity filter=lfs diff=lfs merge=lfs -text
*.prefab filter=lfs diff=lfs merge=lfs -text

Project Settings → Editor → Asset Serialization → Force Text 필수 (YAML diff/merge).

5.4 Assembly Definition (.asmdef)

{
    "name": "MyGame.Runtime",
    "rootNamespace": "MyGame",
    "references": ["Unity.TextMeshPro", "Unity.Addressables"],
    "includePlatforms": [],
    "allowUnsafeCode": false,
    "autoReferenced": false,
    "noEngineReferences": false
}

효과: Player 코드 변경 시 Player.asmdef + 참조 어셈블리만 재컴파일 → 수십 초 → 수 초.

컴파일 4단계: | Phase | Assembly | 위치 | |——-|———|—–| | 1 | Assembly-CSharp-firstpass | Plugins/ | | 2 | Assembly-CSharp-Editor-firstpass | Plugins/Editor/ | | 3 | Assembly-CSharp | 그 외 런타임 | | 4 | Assembly-CSharp-Editor | 그 외 Editor |

Phase N은 Phase N+1을 참조 못 함.

5.5 특수 폴더

폴더 동작
Editor/ 어디 있든 Editor 빌드에만 포함
Plugins/ Phase 1 컴파일
Resources/ Resources.Load("path") 가능. 모두 빌드에 포함 (레거시, Addressables 권장)
StreamingAssets/ 압축 없이 그대로 복사. Android는 jar URL
Editor Default Resources/ EditorGUIUtility.Load

6. MonoBehaviour 라이프사이클 (Unity 핵심)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
              UNITY MONOBEHAVIOUR LIFECYCLE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[ 씬 로드 / 오브젝트 생성 ]
         │
         ▼
    ┌─────────┐
    │  Awake  │  ← 비활성 오브젝트도 호출. 자기 자신 초기화
    └─────────┘   모든 Awake 완료 후 Start
         │
         ▼  (활성화된 경우)
    ┌──────────┐
    │ OnEnable │  ← 활성화될 때마다 (Start 이전)
    └──────────┘
         │
         ▼  [첫 프레임 직전, 1회]
    ┌─────────┐
    │  Start  │  ← 다른 오브젝트 참조 안전 (모든 Awake 완료 보장)
    └─────────┘
         │
━━━━━━━━━━━━━━━━━━━━━━━━ [프레임 루프 반복] ━━━━━━━━━━━━━━━
         │
         ▼  [물리 — 고정 timestep 0.02s]
    ┌─────────────┐
    │ FixedUpdate │  ← 한 프레임에 0회 또는 N회
    └─────────────┘
         │
         ▼
    ┌────────────────────────────┐
    │ Physics callbacks          │
    │  OnTriggerEnter/Stay/Exit  │
    │  OnCollisionEnter/Stay/Exit│
    └────────────────────────────┘
         │
         ▼  [입력 → 메인 로직]
    ┌────────┐
    │ Update │  ← 매 프레임. 프레임률 의존
    └────────┘
         │
         ▼  [코루틴 재개]
    ┌──────────────────────────────┐
    │ Coroutines (yield null)      │
    │ Coroutines (WaitForSeconds)  │
    └──────────────────────────────┘
         │
         ▼  [모든 Update 완료 후]
    ┌────────────┐
    │ LateUpdate │  ← 카메라 추적, 애니메이션 후처리
    └────────────┘
         │
         ▼  [애니메이션]
    ┌────────────────┐
    │ OnAnimatorMove │
    │ OnAnimatorIK   │
    └────────────────┘
         │
         ▼  [렌더링 콜백]
    ┌──────────────────────────────┐
    │ OnPreCull / OnBecameVisible  │
    │ OnPreRender / OnRenderObject │
    │ OnPostRender                 │
    │ OnRenderImage (Built-in RP)  │
    │ OnGUI                        │
    │ OnDrawGizmos (Editor)        │
    └──────────────────────────────┘
         │
         ▼  [프레임 끝]
    ┌────────────────────────────────┐
    │ Coroutines (WaitForEndOfFrame) │
    └────────────────────────────────┘
         │
         └─────────── [다음 프레임] ─────────┐
                                              │
━━━━━━━━━━━━━━━━━━━━━━━ [비활성화/제거] ━━━━━━━━━━━━━━━━━━
         │
         ▼
    ┌───────────┐    ┌───────────┐
    │ OnDisable │ →  │ OnDestroy │
    └───────────┘    └───────────┘
         │
         ▼  [앱 종료]
    ┌────────────────────────┐
    │ OnApplicationPause     │  (모바일)
    │ OnApplicationFocus     │
    │ OnApplicationQuit      │
    └────────────────────────┘

6.1 Awake vs Start (면접 단골)

항목 Awake Start
호출 시점 오브젝트 생성 즉시 첫 Update 직전
GameObject 활성 여부 무관 활성화 시에만
다른 오브젝트 참조 위험 (순서 미보장) 안전 (전체 Awake 완료)
주 용도 자체 초기화, 컴포넌트 캐싱 외부 참조, 이벤트 구독
public class PlayerHealth : MonoBehaviour
{
    [SerializeField] private int maxHealth = 100;
    private int currentHealth;
    private Rigidbody rb;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();   // 자기 컴포넌트 OK
        currentHealth = maxHealth;        // 자체 변수 OK
        // GameManager.Instance 참조는 위험
    }

    void Start()
    {
        // 모든 오브젝트의 Awake 완료 보장
        GameManager.Instance.RegisterPlayer(this);  // 안전
        UIManager.Instance.SetMaxHealth(maxHealth);
    }
}

6.2 FixedUpdate — 물리 전용

시간:    0    0.016  0.032  0.048  0.064 (60fps)
프레임:  │F1  │      │F2    │      │F3
물리:    │P   │P     │P     │P     │P     (50Hz, 0.02s 간격)

30fps일 때: 프레임당 P 1~2회 실행
// 잘못된 패턴: Input을 FixedUpdate에서 읽기
void FixedUpdate()
{
    if (Input.GetButtonDown("Jump"))  // ← 입력 놓칠 수 있음
        rb.AddForce(Vector3.up * 500);
}

// 올바른 패턴: Input은 Update, 물리는 FixedUpdate
private bool jumpQueued = false;
void Update()
{
    if (Input.GetButtonDown("Jump")) jumpQueued = true;
}
void FixedUpdate()
{
    if (jumpQueued)
    {
        rb.AddForce(Vector3.up * 500, ForceMode.Impulse);
        jumpQueued = false;
    }
}

6.3 Update vs LateUpdate

// Player.cs
void Update()
{
    transform.position += movement * speed * Time.deltaTime;
}

// CameraFollow.cs
void LateUpdate()  // ★ Update가 아니라 LateUpdate
{
    // Update에서 플레이어 이동 완료 후 카메라가 추적 → 떨림 없음
    transform.position = Vector3.Lerp(transform.position,
                                       player.position + offset,
                                       smoothSpeed);
}

6.4 Coroutine 내부 동작

IEnumerator MyCoroutine()
{
    Debug.Log("시작");
    yield return new WaitForSeconds(2f);
    Debug.Log("2초 후");
    yield return null;
    Debug.Log("다음 프레임");
}

C# 컴파일러가 IEnumerator 스테이트 머신으로 변환. Unity 스케줄러는:

  1. 활성 코루틴 목록 순회
  2. yield 조건 확인
  3. 충족 시 MoveNext() 호출 → 다음 yield까지 실행
  4. MoveNext()가 false 반환 → 목록에서 제거

주의: GameObject 비활성화 시 코루틴 일시정지(취소 X). 재활성화 시 자동 재개 안 됨 → 수동 재시작 필요.

// 안티: 매 호출 21바이트 GC 할당
yield return new WaitForSeconds(1f);

// 정답: 캐시
private readonly WaitForSeconds wait1s = new WaitForSeconds(1f);
yield return wait1s;

7. 컴포넌트 기반 아키텍처

7.1 Composition over Inheritance

[전통 OOP — 폭발적 계층]
Entity
├── Character
│   ├── Player
│   │   └── Mage
│   └── Enemy
│       └── FlyingEnemy  ← 비행 + AI 다중상속?
└── Prop
    └── InteractiveProp
        └── FlyingInteractiveProp  ← 폭발

[Unity Component — 조합]
GameObject (FlyingEnemy)
├── Transform
├── Rigidbody
├── HealthComponent       ← 재사용
├── AIMovementComponent
├── FlyingBehavior
└── EnemyAnimator

7.2 GetComponent 성능

// 안티
void Update()
{
    GetComponent<Rigidbody>().AddForce(Vector3.up); // O(n) 매 프레임
}

// 정답 1: SerializeField로 Inspector 연결
[SerializeField] private Rigidbody rb;

// 정답 2: Awake 캐싱
void Awake() { rb = GetComponent<Rigidbody>(); }

// 정답 3: TryGetComponent (2019.2+, ~20% 빠름, 할당 없음)
if (TryGetComponent<Collider>(out var col)) col.isTrigger = true;

// 필수 의존성 명시
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]
public class PhysicsObject : MonoBehaviour { }

8. Prefab 시스템

8.1 Prefab 종류

Original Prefab → 씬 인스턴스, Override 가능
Prefab Variant  → Base 상속 + 일부 Override (2018.3+)
Nested Prefab   → Prefab 안 Prefab (2018.3+)

8.2 Override 우선순위

Variant Override > Original Prefab Value
인스턴스 Override > Variant Override > Original Prefab Value

8.3 함정

함정 해결
탐색기에서 Prefab 이동/이름변경 Editor 내에서만 변경 (.meta도 동행)
필드명 변경 후 Override 손실 [FormerlySerializedAs("oldName")]
Nested Prefab 내부 수정이 인스턴스 Override로 기록 실제 Nested Prefab 파일을 직접 열어 수정
[FormerlySerializedAs("speed")]
public float moveSpeed = 5f;

9. ScriptableObject

9.1 vs MonoBehaviour

항목 MonoBehaviour ScriptableObject
부착 GameObject 필수 독립 .asset
종속 독립
게임 루프 Awake/Start/Update 없음
메모리 씬마다 복사 1개 인스턴스 공유
용도 런타임 로직 데이터 컨테이너

9.2 데이터 컨테이너 패턴

[CreateAssetMenu(fileName = "WeaponData", menuName = "Game/Weapon")]
public class WeaponData : ScriptableObject
{
    public int damage = 10;
    public float attackSpeed = 1.5f;
    public Sprite icon;
    public AudioClip swingSound;
}

public class Enemy : MonoBehaviour
{
    [SerializeField] private EnemyData data; // 참조만 → 100마리가 1개 데이터 공유
}

9.3 Event Channel 패턴 (Ryan Hipple, Unite Austin 2017)

Unity 공식 Open Project 1 패턴.

[CreateAssetMenu(menuName = "Events/Int Event Channel")]
public class IntEventChannelSO : ScriptableObject
{
    public UnityAction<int> OnEventRaised;
    public void RaiseEvent(int value) => OnEventRaised?.Invoke(value);
}

// 발신자 — 수신자를 모름
public class EnemyDeath : MonoBehaviour
{
    public IntEventChannelSO OnScoreUpdated;
    void Die() => OnScoreUpdated.RaiseEvent(100);
}

// 수신자 — 발신자를 모름
public class ScoreUI : MonoBehaviour
{
    public IntEventChannelSO OnScoreUpdated;
    void OnEnable()  => OnScoreUpdated.OnEventRaised += UpdateUI;
    void OnDisable() => OnScoreUpdated.OnEventRaised -= UpdateUI;
    void UpdateUI(int score) { /* ... */ }
}
[EnemyDeath] ──RaiseEvent()──▶ [IntEventChannelSO Asset]
                                       │
                                       ├──▶ [ScoreUI]
                                       ├──▶ [AchievementManager]
                                       └──▶ [AudioManager]

씬 경계 초월 가능, Singleton 없음, 테스트 가능.

9.4 제한사항

1. 런타임 변경은 Editor에서 반영되지만 빌드된 플레이어에서 세션 간 유지 안 됨
   → 저장은 PlayerPrefs / JSON / DB 필요

2. ScriptableObject는 씬 모름 → 씬 오브젝트 직접 참조 저장 시 손실

3. Play Mode → Edit Mode 전환 시 일부 수정 사항 자동 롤백

10. 런타임 모델

10.1 세 가지 런타임

C# 소스
   │
   ▼ [Roslyn]
.NET IL (bytecode)
   │
   ├──▶ [Mono]    JIT, 빠른 빌드, 느린 런타임. Editor + 일부 Standalone
   │
   ├──▶ [IL2CPP]  IL → C++ → 네이티브. AOT. iOS/WebGL/콘솔 필수
   │              긴 빌드, 빠른 런타임, Reflection.Emit/dynamic 불가
   │
   └──▶ [Burst]   LLVM AOT, SIMD. NativeContainer만. Job/DOTS

10.2 IL2CPP 파이프라인

[C# 소스] → [Roslyn] → [.NET IL DLL] → [Stripping]
                                            │
                                            ▼
                                     [IL2CPP] → [C++ 코드]
                                            │
                                            ▼
                              [플랫폼 C++ 컴파일러]
                              Xcode (iOS/macOS)
                              Android NDK (Android)
                              MSVC (Windows)
                                            │
                                            ▼
                              [.ipa / .apk / .exe]

10.3 IL2CPP 제한 / link.xml

// 안티
var method = new DynamicMethod(...);  // Reflection.Emit 런타임 오류
dynamic obj = ...;                     // 컴파일 경고, 런타임 오류

Code Stripping 보호:

<!-- Assets/link.xml -->
<linker>
  <assembly fullname="MyGame.Runtime" preserve="all"/>
  <assembly fullname="mscorlib">
    <type fullname="System.Collections.Generic.Dictionary`2" preserve="all"/>
  </assembly>
</linker>
[Preserve]
public class SaveData
{
    [Preserve] public string playerName;
    [Preserve] public int score;
}

// AOT 제네릭 힌트
void UsedOnlyForAOTCodeGeneration()
{
    new Dictionary<string, MyCustomData>();
    new List<MyCustomData>();
}

10.4 Burst Compiler

using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;

[BurstCompile]
public struct PhysicsJob : IJobParallelFor
{
    [ReadOnly] public NativeArray<float3> positions;
    [ReadOnly] public NativeArray<float3> velocities;
    public NativeArray<float3> results;
    public float deltaTime;

    public void Execute(int index)
    {
        // Burst → SIMD 네이티브 코드. 수십~수백배 빠름
        results[index] = positions[index] + velocities[index] * deltaTime;
    }
}

제약: 참조 타입(class), GC 객체, 대부분의 Unity API 불가. struct + NativeArray만.


11. 빌드 파이프라인

11.1 Build Profile (Unity 6 신규)

Unity 6 이전 Build Settings에서 단일 설정만 저장 가능 → Profile로 다중 환경(iOS Release, Android Debug 등) 저장.

11.2 플랫폼별 핵심

iOS
├── Scripting Backend: IL2CPP (강제)
├── Graphics API:      Metal
├── Architecture:      ARM64
└── Code Stripping:    활성화 (앱스토어 크기 제한)

Android
├── Scripting Backend: Mono (개발) / IL2CPP (릴리즈)
├── Graphics API:      Vulkan (권장) / OpenGL ES 3.x
├── Target ABI:        ARM64 (필수, Play 정책)
├── Minification:      ProGuard / R8
└── Build System:      Gradle

WebGL
├── Scripting Backend: IL2CPP
├── Graphics API:      WebGL 2.0
├── Compression:       Brotli / Gzip
└── 메모리 힙 제한 주의

Standalone
├── Mono (기본) / IL2CPP (권장)
└── Windows DX11/12, macOS Metal, Linux Vulkan/GL

11.3 에셋 로딩 전략

Resources/ (레거시)
  + 간단, Resources.Load("path")
  - 폴더 전체 빌드 포함, 메모리 해제 불완전

AssetBundles (직접 관리)
  + 세밀한 제어
  - 의존성/메모리 수동, 복잡

Addressables (권장)
  + AssetBundles 자동화, 원격 CDN, 명시적 해제
  - 학습 곡선
// Addressables — 반드시 명시적 해제
private AsyncOperationHandle<GameObject> handle;

async UniTask SpawnEnemy()
{
    handle = enemyRef.LoadAssetAsync<GameObject>();
    var prefab = await handle.ToUniTask();
    Instantiate(prefab);
}

void OnDestroy()
{
    if (handle.IsValid()) Addressables.Release(handle);  // 안 하면 누수
}

12. Time / Threading

12.1 Time API

Time.deltaTime         // 직전 프레임 경과(초). timeScale 영향
Time.unscaledDeltaTime // timeScale 무시 (UI, 일시정지 메뉴)
Time.fixedDeltaTime    // FixedUpdate 간격 (기본 0.02)
Time.time              // 누적 시간 (timeScale 영향)
Time.unscaledTime      // 누적 (timeScale 무시)
Time.realtimeSinceStartup  // 일시정지/timeScale 무관
Time.frameCount        // 누적 프레임 번호
Time.timeScale         // 0=일시정지, 1=정상, 0.3=슬로우

// 슬로우 모션
Time.timeScale = 0.3f;
Time.fixedDeltaTime = 0.02f * Time.timeScale;  // 물리도 슬로우

12.2 스레딩 모델

[ 메인 스레드 ] ← Unity 게임 루프 전체
   │
   ├── GameObject API (생성/파괴/이동)
   ├── Component API
   ├── Transform
   ├── Physics, Rendering, Audio (대부분)
   └── Scene Management

[ 백그라운드 스레드 ] ← 안전
   │
   ├── 순수 C# 계산
   ├── System.IO, System.Net
   ├── Burst Job (NativeContainer)
   └── UnityWebRequest 내부
// 안티
async Task BadAsync()
{
    await Task.Run(() =>
    {
        transform.position = Vector3.zero;  // 런타임 오류!
    });
}

// 정답
async Task GoodAsync()
{
    var result = await Task.Run(() => HeavyComputation());  // 백그라운드
    transform.position = result;  // 메인 스레드 (async/await SyncContext)
}

12.3 Coroutine vs UniTask vs Task

항목 Coroutine UniTask Task
메인 스레드 항상 항상 주로 (재개 시 컨텍스트 의존)
GC 할당 있음 거의 없음 있음
취소 StopCoroutine CancellationToken Cancel
예외 처리 어려움 try/catch try/catch
Unity 6 완전 지원 서드파티 (UPM) Awaitable로 부분 통합
// UniTask 패턴 (권장)
async UniTask LoadSceneAsync(string sceneName, CancellationToken ct)
{
    AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
    op.allowSceneActivation = false;
    while (op.progress < 0.9f)
    {
        loadingBar.value = op.progress;
        await UniTask.Yield(ct);
    }
    await UniTask.Delay(500, cancellationToken: ct);
    op.allowSceneActivation = true;
}

// Unity 6 Awaitable (내장)
async Awaitable LoadAsync()
{
    await Awaitable.NextFrameAsync();
    await Awaitable.WaitForSecondsAsync(0.5f);
    await Awaitable.MainThreadAsync();
}

13. XR & OpenXR 통합 (Unity의 핵심 사용 영역)

13.1 XR Plugin Framework

[Unity App C#]
    │
    ▼
[High-Level XR Packages]
   XR Interaction Toolkit (com.unity.xr.interaction.toolkit)
   AR Foundation         (com.unity.xr.arfoundation)
   XR Hands              (com.unity.xr.hands)
    │
    ▼
[XR Subsystems Layer — Engine 내장]
   XRDisplaySubsystem  → 스테레오 렌더링
   XRInputSubsystem    → 추적, 컨트롤러
   XRMeshSubsystem     → 환경 메시
   XRRaycastSubsystem  → AR 레이캐스트
   ARCameraSubsystem   → AR 카메라
   ARPlaneSubsystem    → 평면 감지
   XRHandSubsystem     → 손 추적
    │
    ▼
[XR Provider Plugin — 하나만 활성]
   com.unity.xr.openxr           ← 권장
   com.unity.xr.meta-openxr      ← Meta 확장
   com.unity.xr.arcore           ← Android 폰 AR
   com.unity.xr.arkit            ← iOS 폰 AR
   com.unity.polyspatial.visionos ← visionOS (별도 경로)
   com.unity.xr.oculus           ← [DEPRECATED]
    │
    ▼
[Native Runtime / OS]
   OpenXR Loader / ARCore / ARKit / RealityKit

13.2 Unity OpenXR Plugin

com.unity.xr.openxr
  v0.1.x preview (2020) → v1.0.x (2021) → v1.5+ (2022 권장)
  v1.14 (2023)  Oculus XR Plugin 기능 동등성 달성
  v1.16 (2024 현재)  OpenXR-SDK 1.1.53 기반, Unity 2022.3 LTS+

Feature Groups (Project Settings → XR Plug-in Management → OpenXR):

  • Interaction Profiles: Oculus Touch, Vive, Index, WMR, Eye Gaze, Khronos Simple
  • Features: Meta Quest Support, Hand Tracking Subsystem, Eye Gaze Interaction, Mock Runtime, Performance Settings

13.3 XR Interaction Toolkit (XRI v3)

[XR Origin (XR Rig)]
  └─ Camera Offset
       ├─ Main Camera (HMD)
       ├─ Left Controller
       │    ├─ XR Controller (Action-based)
       │    ├─ XR Ray Interactor
       │    ├─ XR Direct Interactor
       │    └─ XR Socket Interactor
       └─ Right Controller (동일)

[Interactive Objects]
  └─ XR Grab Interactable / Simple Interactable

[Interaction Manager]
  └─ XRInteractionManager

[Locomotion System]
  ├─ Continuous Move / Snap Turn / Teleportation
  └─ Climb (v3 신규)

Action-based Input (v3에서 Device-based deprecated):

[SerializeField] InputActionReference triggerAction;
void OnEnable()
{
    triggerAction.action.Enable();
    triggerAction.action.performed += ctx => { /* 트리거 */ };
}

13.4 Meta 통합 — 3가지 경로

경로 패키지 권장
A com.unity.xr.openxr + com.unity.xr.meta-openxr 신규 프로젝트
B Meta XR All-in-One SDK (Asset Store) 풍부한 Meta 생태계 (Avatars, Voice, Presence Platform)
C com.unity.xr.oculus [DEPRECATED, 사용 금지]

13.5 PolySpatial (visionOS) — OpenXR 아님

[Unity Simulation: Logic / Physics / MonoBehaviours]
       ↓ (PolySpatial 중간 레이어)
[Apple RealityKit Rendering]  ← OpenXR 미사용
       ↓
[visionOS Display]
모드 설명
Window 2D/3D 플랫
Bounded Volume 3D 박스 (다른 앱과 공존)
Unbounded / Full Immersive 단독 몰입

제한: 전체화면 포스트 프로세싱, Decal, 일부 파티클 미지원. HDRP 완전 지원 부재.

13.6 VR/MR 성능 최적화

항목 권장
렌더링 (Quest) URP + Vulkan
스테레오 Single Pass Instanced (드로우 콜 절반)
FFR Foveated Rendering API: SRP Foveation (OpenXR 1.11+)
ASW Application SpaceWarp (Vulkan + URP, 36→72 FPS 합성)
텍스처 ASTC (모바일), BC (PC)
Quest 주사율 72/90/120Hz. 90Hz = 11.1ms 예산. CPU 3-4ms, GPU 8ms 목표
// SRP Foveation
List<XRDisplaySubsystem> displays = new();
SubsystemManager.GetSubsystems(displays);
displays[0].foveatedRenderingLevel = 0.75f;
displays[0].foveatedRenderingFlags =
    XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;  // 아이트래킹

// Application SpaceWarp (Meta)
OVRManager.SetSpaceWarp(true);

13.7 Single Pass Instanced 셰이더 호환

Project Settings → Player → XR Settings → Stereo Rendering Mode
   = Single Pass Instanced

커스텀 셰이더:
struct appdata { UNITY_VERTEX_INPUT_INSTANCE_ID };
v2f vert(appdata v) {
    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_TRANSFER_INSTANCE_ID(v, o);
    ...
}

14. 아키텍처 패턴

14.1 Dependency Injection: Zenject vs VContainer

항목 Zenject (Extenject) VContainer
성능 기준 5~10x 빠름
GC 할당 있음 Resolve 시 0
AOT/IL2CPP 제한적 완전 지원
유지보수 비활성 (legacy) 활성
신규 권장 X O
// VContainer
public class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<AudioService>(Lifetime.Singleton);
        builder.Register<IPlayerRepository, PlayerRepository>(Lifetime.Scoped);
        builder.RegisterComponentInHierarchy<PlayerController>();
    }
}

public class PlayerController : MonoBehaviour
{
    private AudioService _audio;
    [Inject]
    public void Construct(AudioService audio) => _audio = audio;
}

14.2 Service Locator vs Singleton vs DI

Singleton ─── 전역, 숨겨진 의존성, 테스트 어려움
   │
Service Locator ─ 인터페이스 교체 가능, 여전히 숨겨진
   │
DI ─── 명시적 의존성, 테스트 용이, 복잡도 증가

현실적 선택:

  • 소규모: Singleton (적은 수, 규율)
  • 중간: Service Locator + SO Event Channel
  • 대규모/장기: VContainer + UniRx/R3 또는 MessagePipe

14.3 DOTS / ECS

OOP (MonoBehaviour):
[GameObject][Transform][Renderer][Health][AI]
메모리 분산, cache miss 높음

ECS:
Entity 0001 → [Position][Velocity][Health]
Entity 0002 → [Position][Velocity][Health]
Archetype Chunk: [Pos|Pos|...][Vel|Vel|...][HP|HP|...]
연속 메모리, SIMD, Burst
public struct MoveSpeed : IComponentData { public float Value; }

public partial struct MovementSystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        float dt = SystemAPI.Time.DeltaTime;
        foreach (var (transform, speed) in
            SystemAPI.Query<RefRW<LocalTransform>, RefRO<MoveSpeed>>())
        {
            transform.ValueRW.Position.y += speed.ValueRO.Value * dt;
        }
    }
}

Unity 6 현황: ECS 1.x Production-ready (V Rising 등). “ECS for All” 완전 통합은 Unity 7+ 예정. Unity 6에서는 Hybrid (MonoBehaviour + ECS 서브시스템) 가 현실적.

14.4 ScriptableObject 기반 FSM

[CreateAssetMenu(menuName = "AI/State")]
public abstract class StateSO : ScriptableObject
{
    public abstract void Enter(AIController ai);
    public abstract void Execute(AIController ai);
    public abstract void Exit(AIController ai);
}

[CreateAssetMenu(menuName = "AI/Transition")]
public class TransitionSO : ScriptableObject
{
    public DecisionSO Decision;
    public StateSO TrueState;
    public StateSO FalseState;
}

복잡한 AI는 UnityHFSM OSS 권장.

14.5 MVVM + UI Toolkit (Unity 6)

public class PlayerViewModel : INotifyPropertyChanged
{
    private int _health;
    public int Health
    {
        get => _health;
        set { _health = value; PropertyChanged?.Invoke(this, new(nameof(Health))); }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

void OnEnable()
{
    var label = root.Q<Label>("health-label");
    label.SetBinding("text", new DataBinding {
        dataSource = viewModel,
        dataSourcePath = new PropertyPath(nameof(PlayerViewModel.Health))
    });
}

15. 성능 최적화

15.1 Update Manager 패턴

Unity 공식: 수백~수천 MonoBehaviour의 네이티브→매니지드 전환 오버헤드 감소.

public interface IUpdatable { void CustomUpdate(float dt); }

public class UpdateManager : MonoBehaviour
{
    public static UpdateManager Instance { get; private set; }
    private readonly List<IUpdatable> _updatables = new();

    void Awake() { Instance = this; DontDestroyOnLoad(gameObject); }

    public void Register(IUpdatable u)   => _updatables.Add(u);
    public void Unregister(IUpdatable u) => _updatables.Remove(u);

    void Update()
    {
        float dt = Time.deltaTime;
        for (int i = 0; i < _updatables.Count; i++)
            _updatables[i].CustomUpdate(dt);
    }
}

public class Enemy : MonoBehaviour, IUpdatable
{
    void OnEnable()  => UpdateManager.Instance.Register(this);
    void OnDisable() => UpdateManager.Instance.Unregister(this);
    public void CustomUpdate(float dt) { /* ... */ }
}

10,000 Update 콜 시나리오에서 유의미한 CPU 절약 (Unity 공식 벤치마크).

15.2 렌더링 최적화

드로우콜 배칭 우선순위:
SRP Batcher (최우선, 같은 Shader Variant)
  └─ Static Batching (정적, 같은 Material)
       └─ GPU Instancing (동일 Mesh+Material, SRP Batcher 비호환)
            └─ Dynamic Batching (소규모 메시)

GPU Resident Drawer (Unity 6 URP):

  • BatchRendererGroup API 자동 GPU 인스턴싱
  • 복잡 씬 CPU 부하 최대 50% 감소
  • URP Asset → GPU Resident Drawer + Forward+ 패스

15.3 메모리 / GC 최적화

// 안티 — Update 내 할당
void Update()
{
    string log = "Pos: " + transform.position;          // 문자열 → GC
    var enemies = FindObjectsOfType<Enemy>();           // O(n), GC
    var list = new List<Vector3>();                     // 매 프레임 할당
    float val = (float)(int)someBoxedValue;             // boxing
}

// 정답
private Enemy[] _enemies;
private List<Vector3> _reusable = new(64);

void Awake() { _enemies = FindObjectsOfType<Enemy>(); }

void Update() { _reusable.Clear(); /* 재사용 */ }

15.4 모바일 특화

항목 권장
텍스처 ASTC 6x6 (품질/크기 균형)
메시 LOD groups, Mesh Compression
오디오 Vorbis (스트리밍), ADPCM (짧은 효과음)
조명 Light Probes 우선, realtime 최소
Adaptive Performance 패키지로 동적 품질 조정

16. 안티패턴 / 함정

16.1 Coroutine

// 안티: 매 호출 21바이트 GC
yield return new WaitForSeconds(1f);

// 정답: 캐시
private readonly WaitForSeconds wait1s = new(1f);
yield return wait1s;

// StopCoroutine은 참조로
private Coroutine c;
c = StartCoroutine(Routine());
StopCoroutine(c);  // 이름 문자열 X

16.2 async/await

// 안티
async void LoadData() { ... }      // 예외 삼켜짐, 절대 금지

async Task LoadAsset()
{
    await Task.Delay(1000);         // ThreadPool 스레드 재개
    transform.position = Vector3.zero;  // 크래시!
}

// 정답: UniTask
async UniTaskVoid LoadAsset(CancellationToken ct)
{
    await UniTask.Delay(1000, cancellationToken: ct);
    transform.position = Vector3.zero;  // 메인 스레드 안전
}

// GameObject 파괴 시 자동 취소
LoadAsset(this.GetCancellationTokenOnDestroy()).Forget();

16.3 Physics

// 안티 — transform 직접 조작
void Update()
{
    transform.position += Vector3.right * speed * Time.deltaTime;
}

// 정답 — Rigidbody, FixedUpdate
private Rigidbody rb;
private Vector3 inputDir;

void Update() { inputDir = ... ; }   // 입력은 Update

void FixedUpdate()
{
    rb.MovePosition(rb.position + inputDir * speed * Time.fixedDeltaTime);
}

16.4 DontDestroyOnLoad 이중 생성

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);   // 중복 파괴 필수
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

더 나은 대안: Bootstrap 씬 — 앱 시작 시 1회만 로드.

16.5 메모리 누수 패턴

패턴 해결
Singleton에 Activity context applicationContext
비정적 내부 클래스 Handler/Runnable WeakReference 또는 정적
미등록 BroadcastReceiver 대칭 등록/해제
미종료 Cursor using 블록

16.6 Deprecated

안티 대체
AsyncTask Coroutine + viewModelScope (Android) — Unity는 UniTask
Loaders / CursorLoader Room + Flow
LocalBroadcastManager SharedFlow / StateFlow
Apache HTTP (API 28 제거) OkHttp / HttpURLConnection

16.7 Magic String 회피

// 안티
SceneManager.LoadScene("GameScene");

// 정답: SceneReference 패턴
[Serializable]
public class SceneReference
{
#if UNITY_EDITOR
    [SerializeField] private UnityEditor.SceneAsset _sceneAsset;
#endif
    [SerializeField] private string _scenePath;
    public AsyncOperation LoadAdditive() =>
        SceneManager.LoadSceneAsync(_scenePath, LoadSceneMode.Additive);
}

17. 테스트 전략

Assets/_Project/Tests/
├── EditMode/
│   ├── EditMode.Tests.asmdef   ← includePlatforms: ["Editor"]
│   └── PlayerHealthTests.cs    ← 순수 로직, Unity 런타임 X
└── PlayMode/
    ├── PlayMode.Tests.asmdef   ← includePlatforms: []
    └── IntegrationTests.cs     ← MonoBehaviour, 물리, 코루틴
// Edit Mode
[TestFixture]
public class PlayerHealthTests
{
    [Test]
    public void TakeDamage_ReducesHealth()
    {
        var hp = new PlayerHealth(100);
        hp.TakeDamage(30);
        Assert.AreEqual(70, hp.Current);
    }
}

// Play Mode
public class SpawnTests
{
    [UnityTest]
    public IEnumerator Enemy_SpawnsAndDies()
    {
        var enemy = Object.Instantiate(Resources.Load<GameObject>("Enemy"));
        yield return new WaitForSeconds(0.1f);
        Assert.IsNotNull(enemy);
    }
}

18. CI/CD — GameCI + GitHub Actions

name: Unity Build & Test
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { lfs: true }
      - uses: actions/cache@v3
        with:
          path: Library
          key: Library-Test-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
      - uses: game-ci/unity-test-runner@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with: { testMode: all, artifactsPath: test-results }

  build:
    needs: test
    strategy:
      matrix:
        targetPlatform: [StandaloneWindows64, WebGL, Android]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { lfs: true }
      - uses: actions/cache@v3
        with:
          path: Library
          key: Library-${{ matrix.targetPlatform }}-${{ hashFiles('Assets/**', 'Packages/**') }}
      - uses: game-ci/unity-builder@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with: { targetPlatform: ${{ matrix.targetPlatform }} }

캐시 활용 시 빌드 시간 50%+ 단축.


19. 빅테크 / 실전 사례

19.1 Genshin Impact (miHoYo/HoYoverse)

항목 내용
출시 2020
플랫폼 iOS/Android/PC/PS4/PS5/Switch
Unity 선택 모바일 우선 + 크로스플랫폼
렌더링 Built-in Pipeline 기반 대규모 커스텀 (URP/HDRP 미사용)
핵심 손그림 셀 셰이딩(SDF 외곽선, 페이셜 라이팅 맵), 그래픽 라이브러리 자체 구현
PS5 업그레이드 CPU-GPU 비동기, 고해상도 텍스처 스트리밍

2018년 miHoYo 기술 디렉터 Jack He의 GDC 발표 “From mobile to high-end PC: Achieving high quality anime style rendering on Unity”.

19.2 Among Us (Innersloth)

3인 개발팀. 2018 출시, 2020 폭발.

  • 엔진: Unity + Adobe Animate(2D 애니메이션)
  • 서버: Google App Engine + Cloud Datastore
  • 위기: 5M+ 동시 접속 → Unity Multiplay 도입으로 안정화 (Unity 공식 케이스 스터디)

19.3 Pokemon GO (Niantic)

2016 출시. AR + 위치 기반.

  • AR: 초기 자체 → ARKit/ARCore 통합
  • 서버: Java GAE + Cloud Datastore + GCP
  • 출시 직후 서버 다운, 미국 외 지역 출시 지연 → GCP 탄력 스케일링으로 점진 해결

19.4 Hearthstone (Blizzard)

2014 출시. 디지털 카드 게임. Blizzard가 자체 엔진 보유했음에도 Unity 채택 이유는 모바일 멀티플랫폼. 한 번 작성, 여러 플랫폼 빌드. PC/iPad UI 통합.

19.5 Cuphead (StudioMDHR)

  1. 2인 형제. XNA → Unity 전환.
    • 모든 프레임 손 그림 (~50,000장, 한 프레임 25분)
    • 게임 60fps, 애니메이션 24fps (1930년대 느낌)
    • Unity Sprite Renderer + Asset Store 2D Toolkit

19.6 Hollow Knight (Team Cherry)

  1. 3인 호주 인디. Stencyl → Unity 2015.
    • 2D in 3D (스프라이트를 3D 공간 레이어로)
    • Asset Store: 2D Toolkit, PlayMaker (비주얼 FSM)
    • 조명: 소프트 투명 도형 직접 구현

19.7 Beat Saber (Beat Games / Meta)

2018 출시. Unity 2019 기반.

  • 초기: SteamVR + OculusVR SDK + PSVR
  • 2023.04 OpenXR 이식 “매우 간단한 작업이었다”
  • 커뮤니티 모드 SDK (Unity 2019 기반)

19.8 VRChat

소셜 VR 플랫폼. VRChat 자체가 Unity 기반.

  • VRChat SDK (VRSDK), VPM (VRChat Package Manager)
  • Avatars 3.0: PhysBones (Dynamic Bones 대체), Contact Receiver/Sender, Eye Tracking
  • 아바타/월드는 AssetBundle로 빌드 → 런타임 로드

19.9 MRTK (HoloLens)

Microsoft Mixed Reality Toolkit.

  • HoloLens 1/2 핸드/아이 트래킹, 공간 매핑 추상화
  • MRTK3: Unity XR Management + XRI 기반. OpenXR 기반. Unity 2021.3 LTS+

19.10 Apple Vision Pro Polyspatial

2024 출시. Unity PolySpatial 패키지.

  • Unity 게임 로직 + 물리 + 애니메이션 → RealityKit 위임
  • Shared Space (멀티태스킹) vs Full Space (몰입)
  • Play to Device (에디터 → Vision Pro 실시간 스트리밍)

20. 경험 많은 엔지니어의 실제 선택

영역 초보자 경험자
이벤트 통신 UnityEvent Inspector SO Event Channel
서비스 접근 Singleton 남발 VContainer DI
비동기 async Task / Coroutine 혼용 UniTask 일관
물리 이동 transform.position in Update Rigidbody.MovePosition in FixedUpdate
씬 참조 “GameScene” 매직 스트링 SceneReference + Bootstrap
에셋 로드 Resources.Load Addressables
컴파일 속도 asmdef 없음 Feature별 asmdef
많은 오브젝트 MB Update 개별 UpdateManager 또는 DOTS
CI 없음 GameCI + GitHub Actions
XR Provider Oculus XR Plugin Unity OpenXR + Meta OpenXR
XRI Input Device-based Action-based (InputActionReference)
Quest 렌더링 Built-in URP + Vulkan

21. 참고 자료

공식 문서

XR 공식

아키텍처 패턴

비동기 / 도구

CI/CD / 테스트

역사 / 사례

도서

  • Androids: The Team That Built the Android OS (Chet Haase, No Starch 2021) — Android지만 게임 엔진 역사 관점에서 함께 추천
  • Game Programming Patterns (Robert Nystrom)
  • Unity in Action (Joseph Hocking)

심층 분석 블로그