<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>바른생활해보자</title>
    <link>https://liveforgame.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 09:08:20 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>HONGGG</managingEditor>
    <image>
      <title>바른생활해보자</title>
      <url>https://tistory1.daumcdn.net/tistory/3857449/attach/1dc8826cfb4a4346be68308e2a14c94c</url>
      <link>https://liveforgame.tistory.com</link>
    </image>
    <item>
      <title>[AI] MCP(Model Context Protocol) - AI의 USB</title>
      <link>https://liveforgame.tistory.com/entry/AI-MCPModel-Context-Protocol-AI%EC%9D%98-USB-C</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;AI가 똑똑해지는 것만으로는 부족하다.&lt;br /&gt;외부 세계와 연결되어야 진짜 일을 할 수 있다.&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;MCP는 그 연결의 표준이다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;MCP란 무엇인가&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MCP(Model Context Protocol)&lt;/b&gt;는 Anthropic이 2024년 11월에 공개한 오픈 표준 프로토콜이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 모델이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;외부 도구, 데이터베이스, API, 파일 시스템 등과 소통하는 방식을 하나로 통일&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USB-C가 등장하기 전, 안드로이드는 마이크로 USB, 아이폰은 라이트닝, 카메라는 미니 USB를 썼다. 기기마다 케이블이 달랐고 USB-C는 &lt;b&gt;이 혼란을 하나의 규격으로 정리&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 AI 세계에서 같은 일을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 Claude에 Google Drive를 연결하려면 전용 커넥터를 만들고, GPT에 같은 Google Drive를 연결하려면 또 다른 커넥터를 만들어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 모델 N개와 도구 M개가 있으면 N&amp;times;M개의 커넥터가 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 이것을 N+M으로 줄인다. &lt;b&gt;도구 쪽에서 MCP 서버 하나만 만들면, MCP를 지원하는 &lt;u&gt;모든 AI 클라이언트가 그 도구를 사용&lt;/u&gt;&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;왜 MCP가 중요한가&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;AI 똑똑하지만 손이 없다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 강력하지만 태생적 한계가 있다. 학습 데이터 이후의 정보를 모르고, 외부 시스템에 접근할 수 없으며, 실제 작업(파일 생성, 이메일 발송, 데이터베이스 쿼리 등)을 수행할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지는 이 문제를 해결하기 위해 각 도구마다 맞춤형 API 연동 코드를 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;MCP 이전 vs 이후&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;b&gt; 항목 &lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;b&gt; &lt;span style=&quot;text-align: start;&quot;&gt;MCP &lt;span style=&quot;text-align: start;&quot;&gt;이전&amp;nbsp;&lt;/span&gt; &lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;b&gt; MCP 이후 &lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;통합 방식&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;도구마다 맞춤 커넥터 개발&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;표준 프로토콜로 한 번만 개발&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;유지보수&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;AI 모델 변경 시 커넥터 전체 수정&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;MCP 서버는 모델과 무관하게 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;호환성&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;특정 AI 플랫폼에 종속&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;모든 MCP 호환 클라이언트에서 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;개발 비용&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;N&amp;times;M (모델 수 &amp;times; 도구 수)&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 21px;&quot;&gt;N+M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;업계 채택 현황&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 더 이상 Anthropic만의 프로토콜이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI, Google DeepMind, Microsoft, AWS, Cloudflare가 모두 지원하며, Linux Foundation 산하 Agentic AI Foundation(AAIF)에서 관리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2026년 기준으로 Gartner는 API 게이트웨이 벤더의 75%, iPaaS 벤더의 50%가 MCP 기능을 갖출 것을 전망한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP의 작동 원리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;아키텍처 구조&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 클라이언트-서버 구조를 따른다. 5개 레이어로 구성된다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;애플리케이션 레이어
(Claude, ChatGPT 등)
	&amp;darr;
MCP 클라이언트
(기능 탐색, 요청 라우팅)
	&amp;darr;
전송 레이어
(stdio, HTTP/SSE, WebSocket)
	&amp;darr;
MCP 서버
(리소스, 도구, 프롬프트)
	&amp;darr;
데이터 소스
(파일, API, 데이터베이스)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;핵심 개념 3가지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;리소스(Resources)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버가 AI에게 제공하는 데이터다.&amp;nbsp;&lt;b&gt;파일 내용, 데이터베이스 레코드, API 응답 등&lt;/b&gt;이 리소스에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;AI가 &quot;읽을 수 있는 것&quot;&lt;/b&gt;&lt;/span&gt;이라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;도구(Tools)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;AI가 &quot;실행할 수 있는 것&quot;&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 생성, 이메일 발송, 데이터베이스 쿼리, 외부 API 호출 등 &lt;b&gt;실제 동작을 수행하는 함수&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 모델이 도구를 발견하고, 파라미터를 채워 호출하면 MCP 서버가 실행하고 결과를 돌려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;프롬프트(Prompts)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버가 제공하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;미리 정의된 프롬프트 템플릿&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 작업에 최적화된 지침을 AI에게 전달하여 일관된 품질을 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;전송 방식&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;stdio (표준 입출력)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버가 &lt;b&gt;로컬 프로세스로 실행&lt;/b&gt;된다. Claude Code에서 로컬 도구를 연결할 때 주로 사용한다. 설정이 간단하고 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Streamable HTTP&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버가 &lt;b&gt;원격 서비스로 실행&lt;/b&gt;된다. 웹 기반 배포, 팀 공유, 클라우드 환경에 적합하다. 2026년 로드맵의 핵심 개선 영역이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP 서버의 실제 사용 사례&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;개발 워크플로우&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;GitHub MCP 서버 &lt;/b&gt;: AI가 이슈 조회, PR 생성, 코드 리뷰를 직접 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 MCP 서버 &lt;/b&gt;: 자연어로 SQL 쿼리 실행, 결과 분석&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일시스템 MCP 서버 &lt;/b&gt;: 프로젝트 파일 읽기, 수정, 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;비즈니스 자동화&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Slack MCP 서버 &lt;/b&gt;: 배포 알림, 빌드 실패 통지 자동화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Google Drive MCP 서버 &lt;/b&gt;: 문서 검색, 요약, 편집&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Jira MCP 서버 &lt;/b&gt;: 티켓 생성, 상태 업데이트, 스프린트 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;게임 개발에서의 활용&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unity/Unreal 빌드 시스템과 연동하여 자동 빌드 트리거&lt;/li&gt;
&lt;li&gt;에셋 데이터베이스 조회 및 관리&lt;/li&gt;
&lt;li&gt;버그 트래커 연동으로 이슈 자동 분류&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Claude Code에서 MCP 서버 설정하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;기본 설정 구조&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 MCP 서버는 settings.json에 설정한다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;filesystem&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [&quot;-y&quot;, &quot;@modelcontextprotocol/server-filesystem&quot;, &quot;/path/to/dir&quot;]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;설정 위치별 용도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;위치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt; 용도 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;~/.claude/settings.json&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 프로젝트에서 사용할 MCP 서버&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;.claude/settings.json&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;팀이 공유하는 프로젝트 전용 MCP 서버&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;.claude/settings.local.json&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;개인 프로젝트 오버라이드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;서브에이전트에서 MCP 사용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code의 서브에이전트(.claude/agents/*.md)에서 특정 MCP 서버만 연결할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 db-analyst 에이전트는 postgres MCP 서버만 사용하게 되어, 권한 범위를 최소화할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: db-analyst
description: 데이터베이스 분석 전담 에이전트
mcpServers:
  - postgres-server
model: sonnet
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP의 보안 고려사항&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;알려진 위험&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프롬프트 인젝션&lt;/b&gt;: 악의적 데이터가 MCP 서버를 통해 AI의 지시를 조작할 수 있다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도구 권한 남용&lt;/b&gt;: 여러 도구를 조합하여 데이터를 유출할 가능성이 있다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유사 도구 공격&lt;/b&gt;: 신뢰할 수 있는 도구와 이름이 비슷한 악성 도구가 대체될 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;방어 원칙&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;최소 권한 원칙&lt;/b&gt;: 에이전트에 필요한 MCP 서버만 연결&lt;/li&gt;
&lt;li&gt;&lt;b&gt;샌드박스 환경&lt;/b&gt;: AI가 승인된 데이터와 동작에만 접근 가능하도록 격리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명시적 컨텍스트 선언&lt;/b&gt;: AI가 리소스 접근 전에 의도와 맥락을 명시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;권한 범위 지정&lt;/b&gt;: AI 접근 권한을 기존 시스템 권한과 일치시키는 세분화된 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP 로드맵&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;1. 전송 진화와 확장성&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Streamable HTTP 전송을 개선하여 &lt;b&gt;MCP 서버가 수평 확장 가능&lt;/b&gt;하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드밸런서와의 충돌 해결, 세션 관리 표준화가 핵심이다. 또한 .well-known URL을 통해 서버 메타데이터를 노출하는 MCP Server Card 표준을 도입하여, &lt;b&gt;연결 없이도 서버의 기능을 탐색&lt;/b&gt;할 수 있게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;2. 에이전트 간 통신&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;다른 에이전트에게 작업을 위임&lt;/b&gt;&lt;/span&gt;하는 패턴이 늘어나면서, 작업 실패 시 재시도 의미론, 작업 라이프사이클 관리 등의 규격이 필요해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;3. 거버넌스 성숙&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스 프로젝트로서의 거버넌스 체계를 정비한다. 워킹그룹이 프로토콜 개발의 주요 수단이 되고, SEP(Spec Enhancement Proposal)를 통해 변경 사항을 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;4. 엔터프라이즈 준비&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사 추적, SSO 통합 인증, 게이트웨이 패턴, 설정 이식성 등 기업 환경에서 필요한 기능들을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 핵심 스펙이 아닌 &lt;b&gt;확장(extension)으로 구현&lt;/b&gt;될 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP vs 기존 기술 비교&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;항목&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;REST API&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;OpenAPI&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt; &lt;span style=&quot;background-color: #2780d4; color: #ffffff; text-align: start;&quot;&gt;MCP&lt;/span&gt; &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;범용 웹 서비스 통신&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;API 명세 표준화&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;AI 모델과 도구 연결 표준화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;대상&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 소프트웨어&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;API 개발자&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;AI 에이전트/모델&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;도구 탐색&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;수동 (문서 참조)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;자동 (스펙 파싱)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;자동 (프로토콜 내장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;양방향 통신&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;제한적&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;없음&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;컨텍스트 관리&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;없음&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;없음&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;내장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 REST API를 대체하는 것이 아니다.&amp;nbsp;MCP 서버 내부에서 실제 데이터 작업은 여전히 기존 API를 통해 이루어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 그 위에 &lt;b&gt;AI가 이해할 수 있는 표준 레이어를 씌운 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시작하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Claude Code에서 기본 MCP 서버 사용해보기&lt;/b&gt;: 파일시스템 MCP 서버를 설정하고 Claude가 파일을 직접 읽고 쓰는 것을 체험&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공식 레퍼런스 서버 탐색&lt;/b&gt;: &lt;a href=&quot;https://github.com/modelcontextprotocol&quot;&gt;GitHub MCP 서버 저장소&lt;/a&gt;에서 다양한 서버 구현 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;나만의 MCP 서버 만들기&lt;/b&gt;: TypeScript 또는 Python SDK를 사용해 간단한 도구를 MCP 서버로 래핑&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트에 통합&lt;/b&gt;: CLAUDE.md에 MCP 서버 사용 규칙을 문서화하고, settings.json에 서버를 등록&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 AI가 &quot;대화만 잘하는 챗봇&quot;에서 &quot;실제 업무를 수행하는 에이전트&quot;로 진화하는 데 필요한 핵심 인프라다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST가 웹 서비스의 통신 방식을 통일했듯이, &lt;b&gt;MCP는 AI와 외부 세계의 통신 방식을 통일&lt;/b&gt;하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임 개발자 관점에서 보면, CLAUDE.md가 &quot;Claude에게 코딩 규칙을 가르치는 것&quot;이라면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MCP는 &quot;Claude에게 외부 도구를 사용하는 손을 달아주는 것&quot;&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지를 잘 조합하면 Claude Code를 단순한 코드 생성기가 아니라 프로젝트 전체를 이해하고 도구를 활용하는 개발 파트너로 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;공식 문서 및 스펙&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://modelcontextprotocol.io&quot;&gt;MCP 공식 사이트&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(프로토콜 스펙, SDK 문서, 거버넌스 정보)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/modelcontextprotocol&quot;&gt;MCP GitHub 저장소&lt;/a&gt; (TypeScript/Python SDK, 레퍼런스 서버 구현)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.modelcontextprotocol.io/posts/2026-mcp-roadmap/&quot;&gt;2026 MCP 로드맵&lt;/a&gt; (전송 확장성, 에이전트 통신, 거버넌스, 엔터프라이즈 준비 4대 우선 영역)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://modelcontextprotocol.io/development/roadmap&quot;&gt;MCP Roadmap 공식 페이지&lt;/a&gt; (워킹그룹별 우선순위 및 SEP 가이드라인)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/settings&quot;&gt;Claude Code Settings 공식 문서&lt;/a&gt; (MCP 서버 설정 방법, 설정 계층 구조)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;분석 및 가이드&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Model_Context_Protocol&quot;&gt;Model Context Protocol &amp;mdash; Wikipedia&lt;/a&gt; (MCP 개요, 채택 현황, 보안 이슈 요약)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/universe7creator/the-complete-guide-to-model-context-protocol-mcp-building-ai-native-applications-in-2026-5e57&quot;&gt;MCP Complete Guide 2026 &amp;mdash; DEV Community&lt;/a&gt; (아키텍처, 구현 패턴, 실전 적용 가이드)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devstarsj.github.io/2026/03/18/model-context-protocol-mcp-complete-guide-2026/&quot;&gt;MCP: The Standard That's Changing AI Integration &amp;mdash; Dev Note&lt;/a&gt; (MCP 서버 구현 예제 코드 포함)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smarte.pro/blog/model-context-protocol-mcp&quot;&gt;What Is MCP? Complete Beginner's Guide 2026 &amp;mdash; SmarteAI&lt;/a&gt; (비개발자를 위한 MCP 개념 설명)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://truto.one/blog/what-is-mcp-model-context-protocol-the-2026-guide-for-saas-pms/&quot;&gt;What is MCP? The 2026 Guide for SaaS PMs &amp;mdash; Truto&lt;/a&gt; (SaaS 관점의 MCP 전략, Gartner 전망 인용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;업계 동향&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://thenewstack.io/model-context-protocol-roadmap-2026/&quot;&gt;MCP's Biggest Growing Pains &amp;mdash; The New Stack&lt;/a&gt; (프로덕션 환경의 MCP 과제와 로드맵 분석)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cdata.com/blog/2026-year-enterprise-ready-mcp-adoption&quot;&gt;2026: The Year for Enterprise-Ready MCP Adoption &amp;mdash; CData&lt;/a&gt; (엔터프라이즈 MCP 도입 전략, 보안 및 거버넌스)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Computer/AI</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/332</guid>
      <comments>https://liveforgame.tistory.com/entry/AI-MCPModel-Context-Protocol-AI%EC%9D%98-USB-C#entry332comment</comments>
      <pubDate>Tue, 7 Apr 2026 14:13:10 +0900</pubDate>
    </item>
    <item>
      <title>[Claude] Claude.md</title>
      <link>https://liveforgame.tistory.com/entry/Claude-Claudemd</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Claude-Code 나만의 프로젝트를 이해하는 개발자로..&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;CLAUDE.md 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Claude Code는 매 세션마다 기억을 잃는다.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 어제 훌륭한 대화를 했더라도, 오늘 새 세션을 열면 내 코드 스타일도, 프로젝트 구조도, 선호하는 도구도 모른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 같은 설명을 반복하는 것은 시간 낭비다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;CLAUDE.md는 이를 해결한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CLAUDE.md&lt;/b&gt;는 클로드가 &lt;b&gt;세션 시작 시 자동으로 읽는 마크다운 파일&lt;/b&gt;로, 한 번 작성해두면 모든 대화에 자동 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 쓴 CLAUDE.md 하나가 프롬프트 수십 줄보다 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;핵심 원칙: 짧고, 구체적이고, 실행 가능하게&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md 작성에서 가장 중요한 원칙이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;짧게 유지하라&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;100줄 이하가 이상적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론티어 사고 모델은 약 150~200개의 지침을 합리적으로 따를 수 있지만, 그 이상은 준수율이 급격히 떨어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;모든 것을 담으려 유혹을 참아야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;구체적인 규칙을 작성하라&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;pnpm 사용, npm 말고&quot; 같은 구체적 규칙은 약 89%의 준수율을 보이는 반면, &lt;b&gt;&quot;깔끔한 코드를 작성하라&quot; 같은 모호한 지침&lt;/b&gt;은 약 35%에 머문다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;제재는 대안과 함께&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 CLAUDE.md 파일들은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;안전한 대안을 함께 제시&lt;/b&gt;&lt;/span&gt;한다는 것이다.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;# 나쁜 예
- flag 파라미터 사용 금지

# 좋은 예
- flag 파라미터로 동작을 분기하지 말 것 &amp;mdash; 함수를 분리&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;파일 계층 구조 이해하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md는 단일 파일이 아니라 &lt;b&gt;계층 시스템&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;u&gt;&lt;b&gt;나중에 로딩되는 파일이 더 높은 우선순위&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;로딩 순서 (낮은 &amp;rarr; 높은 우선순위)&lt;br /&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt;순서&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;&lt;b&gt;위치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;b&gt;용도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;/etc/claude-code/CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;관리자 전역 정책 (오버라이드 불가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;~/.claude/&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;CLAUDE.md&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;개인&amp;nbsp;글로벌&amp;nbsp;설정&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;&lt;b&gt;{프로젝트 루트}&lt;/b&gt;/CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;b&gt;팀&amp;nbsp;공유&lt;/b&gt;&amp;nbsp;프로젝트&amp;nbsp;규칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;.claude/CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;프로젝트&amp;nbsp;규칙&amp;nbsp;(&lt;b&gt;서브디렉토리&lt;/b&gt;&amp;nbsp;버전)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 6.04651%; text-align: center; height: 21px;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 27.2869%; height: 21px;&quot;&gt;CLAUDE.local.md&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;b&gt;개인&lt;/b&gt;&amp;nbsp;프로젝트&amp;nbsp;오버라이드&amp;nbsp;(gitignore&amp;nbsp;대상)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;윈도우 경로 정리&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글로벌: &lt;code&gt;C:\Users\{사용자명}\.claude\CLAUDE.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;글로벌 규칙 폴더: &lt;code&gt;C:\Users\{사용자명}\.claude\rules\*.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;글로벌 설정: &lt;code&gt;C:\Users\{사용자명}\.claude\settings.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;글로벌과 프로젝트를 섞지 마라&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;글로벌 파일&lt;/b&gt;에는 프로젝트와 무관한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;개인 선호&lt;/b&gt;&lt;/span&gt;만, &lt;b&gt;프로젝트 파일&lt;/b&gt;에는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;해당 프로젝트의 스택과 구조&lt;/b&gt;&lt;/span&gt;만 넣어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지가 섞이면 Claude가 매 작업마다 불필요한 컨텍스트를 짊어지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;글로벌 CLAUDE.md&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;글로벌 파일&lt;/b&gt;은 모든 프로젝트에 적용되는 &lt;u&gt;&lt;b&gt;나의 개발 원칙&lt;/b&gt;&lt;/u&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최상위 엔지니어들의 글로벌 파일에서 공통적으로 발견되는 항목들을 정리하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;언어 설정&lt;/b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하지만 매 세션마다 &quot;한국어로 대답해줘&quot;를 반복하지 않아도 된다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 대화와 설명은 한국어로 응답
- 코드 주석, 커밋 메시지, 변수명은 영어&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;코드 스타일 (범용)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;여기서 핵심은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&quot;모든 프로젝트에 적용되는가?&quot;&lt;/b&gt;를 자문하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity 전용 규칙이나 특정 프레임워크 패턴은 여기에 넣지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 엄격한 타이핑 &amp;mdash; 함수 반환값, 변수, 컬렉션 모두 타입 명시
- 단일 책임 원칙 &amp;mdash; 하나의 함수는 하나의 일만 수행
- 새 로직 작성 전 기존 코드에 동일 로직이 있는지 먼저 검색
- 매직 넘버 금지 &amp;mdash; 상수로 정의하고 이름을 부여&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;에러 처리&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 에러를 조용히 무시하지 말 것 &amp;mdash; 항상 명시적으로 처리
- 포괄적 catch-all 금지 &amp;mdash; 구체적 에러 타입 사용
- 에러 메시지에 원인과 조치 방법 포함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;작업 행동 규칙&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 코딩 품질에 가장 큰 영향을 미친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude의 가장 흔한 실수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;너무 많은 것을 한꺼번에 바꾸는 것&quot;&lt;/b&gt;이다. 이 규칙 하나만 넣어도 코드 품질이 체감될 만큼 달라진다.&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;- 실패하면: 멈추고 &amp;rarr; 원인 설명 &amp;rarr; 확인 후 진행
- 변경 전 영향 범위 파악 &amp;mdash; &quot;다른 곳에서 안 쓴다&quot;는 추측 금지, grep으로 증명
- 되돌릴 수 없는 작업은 반드시 확인 요청
- 한 번에 너무 많이 바꾸지 말 것 &amp;mdash; 작은 단위로 검증하며 진행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;금지사항&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;- 추측으로 패키지 버전이나 API 시그니처 지정 금지 &amp;mdash; 확인 후 사용
- 요청하지 않은 리팩토링 금지 &amp;mdash; 현재 작업 범위에만 집중
- &quot;깔끔하게 정리했습니다&quot; 같은 모호한 보고 금지 &amp;mdash; 무엇을 변경했는지 구체적으로 명시&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;프로젝트 CLAUDE.md&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 파일에는 세 가지를 넣는다: &lt;b&gt;무엇(WHAT)&lt;/b&gt;, &lt;b&gt;왜(WHY)&lt;/b&gt;, &lt;b&gt;어떻게(HOW)&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;WHAT &amp;mdash; 기술 스택과 구조&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;## 프로젝트 개요
Unity 2022.3 LTS, URP 기반의 3D 액션 게임

## 디렉토리 구조
- Assets/Scripts/Core &amp;mdash; 게임 루프, 매니저
- Assets/Scripts/Combat &amp;mdash; 전투 시스템
- Assets/Scripts/UI &amp;mdash; UI 관련
- Assets/Prefabs &amp;mdash; 프리팹
- Assets/ScriptableObjects &amp;mdash; 데이터 에셋&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;WHY &amp;mdash; 아키텍처 결정 사항&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;## 아키텍처 결정
- 싱글톤 대신 ScriptableObject 기반 이벤트 시스템 사용
  &amp;rarr; 테스트 용이성과 씬 간 의존성 제거 목적
- ECS는 사용하지 않음 &amp;rarr; MonoBehaviour 기반 유지&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;HOW &amp;mdash; 빌드, 테스트, 워크플로우&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;## 명령어
- 테스트: Unity Test Runner (EditMode + PlayMode)
- 빌드: File &amp;gt; Build Settings &amp;gt; Windows x64

## 코딩 규칙
- MonoBehaviour 상속 클래스는 PascalCase
- SerializeField는 private + [SerializeField]
- GetComponent는 Awake()에서 캐싱, Update()에서 호출 금지
- Update()에서 GC 할당 금지 (new, LINQ, string 연결 등)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;워크플로우&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;/init으로 시작하고, 깎아내기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 디렉토리에서 &lt;code&gt;/init&lt;/code&gt; 명령을 실행하면 &lt;b&gt;Claude가 프로젝트를 분석해 CLAUDE.md 초안&lt;/b&gt;을 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 생성된 파일은 보통 &lt;b&gt;불필요한 내용이 많으므로&lt;/b&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;필요한 것만 남기고 삭제하는 방식&lt;/b&gt;&lt;/span&gt;이 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백지에서 쓰는 것보다 깎아내는 게 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;실수 기반으로 점진적 추가&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 완벽한 파일을 만들려 하지 말자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude가 반복적으로 실수하는 패턴을 발견할 때마다 한 줄씩 추가하는 것이 가장 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Claude가 자꾸 &lt;code&gt;var&lt;/code&gt;를 이 한 줄을 추가하면 된다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;- var 사용 금지 &amp;mdash; 명시적 타입 선언 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;rules/ 디렉토리 활용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 CLAUDE.md가 길어질 것 같으면 &lt;code&gt;~/.claude/rules/&lt;/code&gt; 폴더에 주제별 &lt;code&gt;.md&lt;/code&gt; 파일로 분리할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;~/.claude/
├── CLAUDE.md          &amp;larr; 핵심 규칙 (30~50줄)
└── rules/
    ├── git.md         &amp;larr; Git 관련 규칙
    ├── error.md       &amp;larr; 에러 처리 규칙
    └── naming.md      &amp;larr; 네이밍 규칙&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;컨텍스트 관리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md에 넣은 모든 내용은 &lt;b&gt;매 대화마다 컨텍스트 윈도우를 차지&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불필요한 내용이 많을수록 Claude가 실제 작업에 쓸 수 있는 공간이 줄어든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 관련 없는 지침이 많으면 Claude가 파일 전체를 무시할 확률도 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;설정 파일과 역할 분리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md에 넣으면 안 되는 것들도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;권한, 도구 허용, 모델 선택&lt;/b&gt; 같은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하드웨어적 설정&lt;/b&gt;&lt;/span&gt;은 &lt;code&gt;settings.json&lt;/code&gt;에 넣어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md는 &quot;어떻게 코딩할 것인가&quot;에 대한 지침이고, settings.json은 &quot;무엇을 허용할 것인가&quot;에 대한 설정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 143px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt;내용 예제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&quot;pnpm 사용, npm 말고&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;CLAUDE.md&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&quot;Bash 도구 허용&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;settings.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&quot;커밋 메시지는 영어&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;CLAUDE.md&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&quot;Co-Authored-By 제거&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;settings.json (attribution.commit: &quot;&quot;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;&quot;테스트 먼저 실행&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 21px;&quot;&gt;CLAUDE.md&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;&quot;모델은 sonnet 사용&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;settings.json&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;CLAUDE.md에 절대 넣지 말아야 할 것&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API 키, 비밀번호, 토큰&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CLAUDE.md는 컨텍스트에 로딩되므로 보안 위험&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Claude가 이미 아는 것&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 문법, 일반적인 라이브러리 API 설명&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;뻔한 지침&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;깨끗한 코드 작성&quot;, &quot;주석 추가&quot; 같은 당연한 내용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;너무 긴 문서&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상세한 아키텍처 문서는 별도 파일에 두고 &lt;code&gt;@&lt;/code&gt;로 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;사용량 관리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 사용량 제한이 있다. &lt;code&gt;/status&lt;/code&gt;에서 Usage 탭을 확인하면 세션과 주간 사용량을 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Current session&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 세션의 사용량. 매일 특정 시간에 리셋&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Current week&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주간 전체 사용량. 매주 리셋&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세션이 100%가 되면 완전 차단이 아니라 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;속도 제한&lt;/b&gt;&lt;/span&gt;이 걸림&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/extra-usage&lt;/code&gt;로 추가 사용량 활성화 가능]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 관리도 사용량에 영향을 미친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;컨텍스트가 50%를 넘으면&lt;/span&gt; &lt;code&gt;/compact&lt;/code&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;로 압축&lt;/span&gt;&lt;/b&gt;하고, 작업 전환 시에는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;code&gt;/clear&lt;/code&gt;로 리셋&lt;/b&gt;&lt;/span&gt;하는 습관을 들이자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;요약 체크리스트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;에 개인 글로벌 규칙 작성 (50~100줄)&lt;/li&gt;
&lt;li&gt;프로젝트 루트에서 &lt;code&gt;/init&lt;/code&gt; 실행 후 불필요한 내용 삭제&lt;/li&gt;
&lt;li&gt;사용하면서 Claude의 반복 실수를 발견할 때마다 한 줄씩 추가&lt;/li&gt;
&lt;li&gt;파일이 길어지면 &lt;code&gt;rules/&lt;/code&gt; 디렉토리로 분리&lt;/li&gt;
&lt;li&gt;주기적으로 검토하여 더 이상 필요 없는 규칙 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 효과적인 CLAUDE.md는 &lt;b&gt;실제 마찰을 해결하는 파일&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론적으로 완벽한 규칙집이 아니라, 내가 반복적으로 겪는 문제를 한 줄씩 해결해 나간 파일이 결국 가장 강력하다.&lt;/p&gt;</description>
      <category>Computer/AI</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/331</guid>
      <comments>https://liveforgame.tistory.com/entry/Claude-Claudemd#entry331comment</comments>
      <pubDate>Tue, 7 Apr 2026 04:28:09 +0900</pubDate>
    </item>
    <item>
      <title>[Unity] #1 Profiler - 프로파일러 모듈</title>
      <link>https://liveforgame.tistory.com/entry/Unity-1-Profiler-%ED%94%84%EB%A1%9C%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EB%AA%A8%EB%93%88</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity Profiler 기본 항목&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;숫자를 해석하는 법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 글에서는 왜 최적화보다 프로파일링이 먼저인지 이야기했다.&lt;br /&gt;핵심은 단순했다. 감으로 문제를 고치기 전에, 먼저 무엇이 실제 병목인지 읽을 수 있어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은&amp;nbsp;&lt;b&gt;Unity Profiler에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;반드시 읽을 수 있어야 하는 기본 항목&lt;/span&gt;들&lt;/b&gt;에 대한 글이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Profiler를 처음 열면 CPU, GPU, Rendering, Memory, Audio, Physics, UI, Timeline, Hierarchy 등 여러 정보가 한꺼번에 보이기에, 아무것도 읽히지 않는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qe2Ln/dJMcagLOw4X/7HxVCQiSUI9Mk0hRaa8ca0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qe2Ln/dJMcagLOw4X/7HxVCQiSUI9Mk0hRaa8ca0/img.png&quot; data-alt=&quot;프로파일러 기본 모듈 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qe2Ln/dJMcagLOw4X/7HxVCQiSUI9Mk0hRaa8ca0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQe2Ln%2FdJMcagLOw4X%2F7HxVCQiSUI9Mk0hRaa8ca0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;256&quot; height=&quot;496&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로파일러 기본 모듈 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 욕심을 줄이고, &quot;모든 걸 다 본다&quot;가 아니라 &lt;u&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&quot;가장 중요한 것부터 순서대로 읽는다&quot;&lt;/span&gt;는 접근이 필요&lt;/b&gt;&lt;/u&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Unity Profiler&lt;/b&gt;의 &lt;b&gt;핵심 항목&lt;/b&gt;이 무엇인지 이해한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 항목&lt;/b&gt;이 어떤 종류의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;비용을 의미&lt;/b&gt;&lt;/span&gt;하는지 구분한다&lt;/li&gt;
&lt;li&gt;실제 게임 성능 문제를 볼 때 &lt;b&gt;어떤 순서로 읽어야 하는지&lt;/b&gt; 감을 잡는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;&quot;Profiler를 어디부터 읽어야 하는지 아는 사람&quot;&lt;/b&gt;이 되는 것이 이번 단계의 목표를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU Usage, Timeline, Hierarchy의 역할 차이 알기&lt;/li&gt;
&lt;li&gt;GC Alloc이 왜 중요한지 알기&lt;/li&gt;
&lt;li&gt;Rendering 수치를 단순 시각 정보가 아니라 비용 정보 보기&lt;/li&gt;
&lt;li&gt;성능 문제를 볼 때 어떤 순서로 Profiler를 열어봐야 할지 알기&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Profiler 확인 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;일단 뭐가 제일 높게 찍히는지 보면 되는 거 아닌가?&quot;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;위 인용란의 문장은 반은 맞고, 반은 틀리다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 값은 분명 중요하다. 하지만 숫자 하나만 보고 결론을 내리면 쉽게 오판한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로 어떤 프레임에서 CPU Usage가 높게 나왔다고 다음 사실들이 무시되면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 전체&lt;/b&gt;가 높은 것인가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메인 스레드&lt;/b&gt;만 높은 것인가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 함수 하나&lt;/b&gt;가 튄 것인가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GC&lt;/b&gt; 때문에 순간적으로 멈춘 것인가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;렌더링 준비 비용&lt;/b&gt;이 큰 것인가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로딩 후처리&lt;/b&gt;가 그 프레임에 몰린 것인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 프로파일러는 &quot;정답을 주는 창&quot;이 아니라 &lt;b&gt;질문을 좁혀가는 도구&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;CPU Usage - 가장 큰 지도&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Profiler에서 가장 먼저 보게 되는 항목 중 하나가 &lt;b&gt;CPU Usage&lt;/b&gt;다.&lt;br /&gt;이 항목은 말 그대로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;CPU에서 프레임이 어떻게 소비되고 있는지를 큰 분류로 보여준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPInbu/dJMcabKwmuq/4dMPU5lGppOUl3hP0IXNq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPInbu/dJMcabKwmuq/4dMPU5lGppOUl3hP0IXNq1/img.png&quot; data-alt=&quot;런타임에 발생하는 CPU 점유율 표시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPInbu/dJMcabKwmuq/4dMPU5lGppOUl3hP0IXNq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPInbu%2FdJMcabKwmuq%2F4dMPU5lGppOUl3hP0IXNq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;226&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;런타임에 발생하는 CPU 점유율 표시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;왜 CPU Usage가 중요할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 게임 플레이 문제는 결국 &lt;b&gt;CPU에서 체감&lt;/b&gt;되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 처리&lt;/li&gt;
&lt;li&gt;게임 로직&lt;/li&gt;
&lt;li&gt;애니메이션 업데이트&lt;/li&gt;
&lt;li&gt;물리 처리&lt;/li&gt;
&lt;li&gt;UI 갱신&lt;/li&gt;
&lt;li&gt;렌더링 준비&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;로딩 후처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 같은 &lt;b&gt;대부분의 작업은 우선 CPU에서&lt;/b&gt; 돌아간다.&lt;br /&gt;그래서 성능 문제가 생겼을 때, 가장 먼저 &quot;이번 프레임이 CPU 쪽 문제인가?&quot;를 확인하는 출발점이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반에는 세부 분류를 모두 외우려 하기보다, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;지금 병목이 스크립트 쪽인지, 렌더 준비 쪽인지, GC 쪽인지&quot; 정도만 구분&lt;/b&gt;&lt;/span&gt;할 수 있어도 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;사용량이 가장 높은 항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;&lt;b&gt;따라오는 의문&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;Scripts&lt;/b&gt; 점유율 과도&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;코드 실행량이 많나?&lt;br /&gt;하나의 코드에서 발생하나?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;Rendering&amp;nbsp;&lt;/b&gt;점유율&amp;nbsp;과도&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;그리는 준비 비용이 큰가?&lt;br /&gt;어떤 렌더링 리소스가 가장 크게 비중을 차지했나?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;GC&lt;/b&gt; 점유율 과도&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;메모리 할당/회수 문제가 발생하나?&lt;br /&gt;메모리 리크가 발생하고 있나?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;Main Thread&lt;/b&gt; 점유율 과도&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;메인 스레드가 프레임을 잡아 먹고 있나?&lt;br /&gt;불필요한 반복 비용에 잡혀있는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU Usage는 &lt;b&gt;정답을 주지는 않지만,&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;문제의 대분류를 찾을 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;아직 정답을 주지는 않지만, 어디를 더 깊게 파야 하는지를 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Timeline - 프레임 안에서 무슨 일이 순서대로 일어났는지 보는 창&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU Usage가 큰 지도라면, Timeline은 그 지도를 확대해서 보여주는 도구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Timeline의 가장 큰 장점은 &lt;b&gt;프레임 안에서 어떤 작업이 어떤 순서로, 얼마나 길게 실행되었는지를 시간축으로 보여준다&lt;/b&gt;는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1653&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsnuk7/dJMcaiv2MuX/q9OqaXys53bJ0SPtaUMzS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsnuk7/dJMcaiv2MuX/q9OqaXys53bJ0SPtaUMzS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsnuk7/dJMcaiv2MuX/q9OqaXys53bJ0SPtaUMzS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsnuk7%2FdJMcaiv2MuX%2Fq9OqaXys53bJ0SPtaUMzS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1653&quot; height=&quot;522&quot; data-origin-width=&quot;1653&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;이게 왜 중요할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 성능 문제는 &quot;무엇이 느린가&quot;보다 &lt;u&gt;&lt;b&gt;&quot;언제, 어떤 맥락에서 느려졌는가&quot;&lt;/b&gt;&lt;/u&gt;가 더 중요할 때가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로 팝업을 여는 순간 프레임이 튄다고 가정해면, Timeline을 보면 이런 흐름이 드러날 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;팝업 Open 프로세스&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버튼 입력 처리&lt;/li&gt;
&lt;li&gt;스크립트에서 팝업 Open 호출&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;텍스트 갱신&lt;/li&gt;
&lt;li&gt;UI 리빌드&lt;/li&gt;
&lt;li&gt;렌더링 준비&lt;/li&gt;
&lt;li&gt;프레임 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 순서가 보이면 우리는 단순히 &quot;UI가 느리다&quot;가 아니라 &lt;b&gt;&quot;팝업 Open 이후 데이터 바인딩과 UI 리빌드가 같은 프레임에 겹쳤다&quot;&lt;/b&gt;라고 말할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Timeline은 이런 경우에 특히 강력하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 이벤트 직후 스파이크가 생길 때&lt;/li&gt;
&lt;li&gt;여러 시스템이 한 프레임에 몰려 있을 때&lt;/li&gt;
&lt;li&gt;스레드별 실행 흐름을 보고 싶을 때&lt;/li&gt;
&lt;li&gt;원인과 결과의 순서를 확인하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 너무 많은 줄이 보여서 복잡해 보이지만, 초반에는 아래처럼만 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Main Thread에서 가장 긴 구간&lt;/b&gt;이 무엇인가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Render Thread는 어떤 상태&lt;/b&gt;인가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 이벤트 직후 어떤 마커가&lt;/b&gt; 이어서 나타나는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GC가 끼어드는 시점&lt;/b&gt;은 언제인가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Timeline은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프레임 내부의 사건 기록&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Hierarchy - 무엇이 많이 쌓였는지 보기 좋은 집계표&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Timeline이 시간 순서 중심이라면, &lt;b&gt;Hierarchy는 비용 누적 중심&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hierarchy는 &lt;b&gt;어떤 함수나 마커가 총 얼마의 시간을 차지했는지&lt;/b&gt; 보기 쉽다.&lt;br /&gt;시간축보다 구조적으로 정리되어 보이기 때문에, 초반에는 오히려 Timeline보다 읽기 쉬울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1650&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEvKTf/dJMcabcCKit/xievwNmHnDYKhIV4MGu56k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEvKTf/dJMcabcCKit/xievwNmHnDYKhIV4MGu56k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEvKTf/dJMcabcCKit/xievwNmHnDYKhIV4MGu56k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEvKTf%2FdJMcabcCKit%2FxievwNmHnDYKhIV4MGu56k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1650&quot; height=&quot;532&quot; data-origin-width=&quot;1650&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Hierarchy 장점&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 함수들에 사용되는 &lt;b&gt;가장 큰 비용을 빨리 찾고 싶을 때&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;호출 구조를 따라가며 &lt;b&gt;누적 비용&lt;/b&gt;을 보고 싶을 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 시스템이 전체 프레임에서 얼마를 차지&lt;/b&gt;하는지 확인하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면...&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PlayerLoop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BehaviourUpdate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Canvas.SendWillRenderCanvases&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Camera.Render&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Physics.Simulate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 상위 항목 아래에 어떤 비용이 쌓이는지 보기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hierarchy는 특히 &quot;무엇이 많이 쌓였는가&quot;를 볼 때 좋지만, 반면 &quot;어떤 순서로 일어났는가&quot;는 Timeline이 더 잘 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 창은 서로 경쟁 관계가 아니라 보완 관계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Timeline&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Hierarchy&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;사건의&amp;nbsp;순서와&amp;nbsp;맥락&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;비용의&amp;nbsp;누적과&amp;nbsp;크기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로파일링 초반에 &lt;b&gt;Timeline으로 맥락을 보고, Hierarchy로 크기를 검증하는 습관&lt;/b&gt;을 들여보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;GC Alloc - 최적화를 놓치는 주원인&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임이 버벅일 때 사람들은 종종 렌더링, 이펙트, 복잡한 로직만 의심한다.&lt;br /&gt;그런데 실제로는 의외로 자주 &lt;b&gt;GC Alloc&lt;/b&gt;가 핵심 원인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC Alloc은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프레임 중 발생한 메모리 할당&lt;/b&gt;&lt;/span&gt;을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 &quot;메모리를 썼다&quot;는 사실보다, &lt;u&gt;&lt;b&gt;그 메모리 할당이 이후 GC를 유발해 프레임을 끊기게 만들 수 있다&lt;/b&gt;&lt;/u&gt;는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 나오는 원인은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자열 합치기&lt;/li&gt;
&lt;li&gt;임시 리스트 생성&lt;/li&gt;
&lt;li&gt;LINQ 사용&lt;/li&gt;
&lt;li&gt;foreach 박싱&lt;/li&gt;
&lt;li&gt;람다 캡처&lt;/li&gt;
&lt;li&gt;JSON 파싱 후 임시 객체 생성&lt;/li&gt;
&lt;li&gt;UI 바인딩 시 반복적인 객체 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 팝업을 열 때 프레임이 튄다고 할때, 겉으로 보면 UI 문제처럼 보일 수 있다.&lt;br /&gt;하지만 실제로는 팝업을 열면서 리스트를 새로 만들고, 문자열을 가공하고, 데이터를 매핑하는 과정에서 GC Alloc이 커질 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 병목은 &quot;UI 렌더&quot;가 아니라 &lt;b&gt;UI를 그리기 전에 데이터를 준비하는 코드&lt;/b&gt;일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반에 반드시 익혀야 할 습관은 이것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&quot;스파이크 프레임이 나오면, CPU 마커만 보지 말고 GC Alloc도 같이 본다.&quot;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC Alloc은 수치가 작아 보여도 무시하면 안 된다. 상시로 조금씩 쌓이는 할당은 결국 큰 GC로 돌아올 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Rendering - CPU에서 렌더링 준비 비용을 보는 관점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Profiler의 Rendering 관련 항목은 &lt;b&gt;&quot;GPU가 얼마나 바쁜가&quot;와는 조금 다르다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 경우 Unity Profiler에서 먼저 보게 되는 것은 &lt;b&gt;CPU가 렌더링을 준비하는 비용&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 건 다음과 같은 시그널이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Draw Calls 증가&lt;/li&gt;
&lt;li&gt;Batches 증가&lt;/li&gt;
&lt;li&gt;SetPass Calls 증가&lt;/li&gt;
&lt;li&gt;Visible objects 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값들이 중요한 이유는, 게임이 복잡해질수록 단순히 &quot;보이는 것이 많다&quot;가 아니라 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;얼마나 비효율적으로 그리기 준비를 하고 있는가&lt;/b&gt;&lt;/span&gt;가 문제로 드러나기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 머티리얼을 못 묶어서 배치가 쪼개질 수 있다&lt;/li&gt;
&lt;li&gt;UI가 여러 마스크와 다른 텍스처 조합으로 인해 배치가 깨질 수 있다&lt;/li&gt;
&lt;li&gt;파티클과 이펙트가 Draw Call을 많이 늘릴 수 있다&lt;/li&gt;
&lt;li&gt;장면 전환 시 한 프레임에 렌더링 준비가 몰릴 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rendering 수치는 단독으로 보면 막연할 수 있기에 CPU Usage, Timeline과 같이 봐야 해석이 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로, &lt;b&gt;&lt;code&gt;Canvas.BuildBatch&lt;/code&gt;&lt;/b&gt;가 높고 &lt;b&gt;Batches&lt;/b&gt;도 같이 늘었다면 &lt;u&gt;&lt;b&gt;UI 구조와 렌더링 준비 비용이 연결&lt;/b&gt;&lt;/u&gt;되어 있다는 뜻으로 볼 수 있다. 즉, Rendering은 단순 시각 효과의 문제가 아니라 &lt;b&gt;프레임을 준비하는 과정의 비용&lt;/b&gt;을 읽는 창이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Memory - 느려짐이 아니라, 느려질 준비가 되어 있는지 보는 창&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Memory는 어떤 프레임이 느렸는지를 직접 보여주는 창이라기보다, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;앞으로 문제가 생길 여지를 보여주는 창&lt;/b&gt;&lt;/span&gt;에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 사용량이 계속 증가하거나, 특정 시점마다 &lt;b&gt;큰 할당과 해제가 반복&lt;/b&gt;되면 나중에 &lt;b&gt;GC나 로딩 스파이크, 심지어 메모리 부족 문제&lt;/b&gt;로 이어질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 깊게 들어가기에 페이지가 새로 필요하기에, 적어도 다음 정도는 볼 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메모리 사용량이 지속적으로 증가&lt;/b&gt;하는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;씬 전환 후 메모리가 정상적&lt;/b&gt;으로 내려오는가&lt;/li&gt;
&lt;li&gt;특정 &lt;b&gt;기능 실행 시 큰 임시 할당&lt;/b&gt;이 생기는가&lt;/li&gt;
&lt;li&gt;객체가 예상보다 오래 살아남는가 = &lt;b&gt;객체 예상 평균생존기간 초과&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리는 당장 프레임 하나만 보고 판단하기 어렵기 때문에, CPU나 GC 문제와 연결해서 보는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로딩 후 메모리 급증&lt;/li&gt;
&lt;li&gt;이후 GC 스파이크 발생&lt;/li&gt;
&lt;li&gt;플레이 중 주기적 hitch 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 연결되면, 단순한 순간 병목이 아니라 메모리 라이프사이클 문제일 수 있다는 힌트를 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Frame Debugger - 실제로 어떻게 그려졌는지 확인하는 도구&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Profiler가 시간 기준 분석 도구라면, Frame Debugger는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;렌더 순서 분석 도구&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Frame Debugger는 한 프레임 안에서 실제 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Draw call이 어떻게 발생했는지를 단계별로 보여준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;&quot;왜 draw call이 늘었는가&quot;, &quot;왜 배치가 안 묶였는가&quot;&lt;/b&gt;를 볼 때 매우 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 도구는 특히 이런 상황에서 강하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI 배치가 이상하게 많이 쪼개질 때&lt;/li&gt;
&lt;li&gt;머티리얼이 섞여 draw call이 늘 때&lt;/li&gt;
&lt;li&gt;마스크와 클리핑이 많이 걸릴 때&lt;/li&gt;
&lt;li&gt;특정 오브젝트가 예상보다 자주 그려질 때&lt;/li&gt;
&lt;li&gt;Overdraw를 의심할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Frame Debugger는 숫자보다 &lt;b&gt;실제 그려지는 순서와 분리 이유&lt;/b&gt;를 보여준다는 점에서 강력하다.&lt;br /&gt;Profiler에서 &quot;왜 이 마커가 높지?&quot;라는 질문이 생겼을 때, Frame Debugger가 그 이유를 시각적으로 설명해주는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;읽기 순서&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;1. CPU Usage에서 큰 분류를 본다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이번 프레임이 CPU 병목인가?&lt;/li&gt;
&lt;li&gt;Main Thread가 긴가?&lt;/li&gt;
&lt;li&gt;Scripts / Rendering / GC 중 무엇이 눈에 띄는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;2. Timeline으로 프레임 안의 사건 순서를 본다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스파이크가 정확히 언제 발생했는가?&lt;/li&gt;
&lt;li&gt;어떤 이벤트 직후 비용이 몰렸는가?&lt;/li&gt;
&lt;li&gt;여러 비용이 같은 프레임에 겹쳤는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. Hierarchy로 누적 비용을 본다&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 비용을 차지하는 함수/마커는 무엇인가?&lt;/li&gt;
&lt;li&gt;상위 구조 아래 어떤 비용이 쌓였는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;4. GC Alloc을 확인한다&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 프레임의 문제에 메모리 할당이 끼어들었는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;5. Rendering / UI / Frame Debugger로 세부 원인을 확인한다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;draw call이 왜 늘었는가?&lt;/li&gt;
&lt;li&gt;UI 배치가 왜 깨졌는가?&lt;/li&gt;
&lt;li&gt;실제 그리는 순서가 어떻게 되어 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;팝업을 열었는데 프레임이 튄다면&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 상황을 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&quot;게임 로비에서 인벤토리 팝업을 여는 순간 프레임이 튄다.&quot;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Profiler를 어떻게 읽을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. CPU Usage 확인&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Main Thread가 튀었는가?&lt;/li&gt;
&lt;li&gt;Scripts와 Rendering 중 어느 쪽이 더 큰가?&lt;/li&gt;
&lt;li&gt;GC Alloc이 함께 발생했는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Timeline 확인&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버튼 클릭 직후 어떤 호출이 이어졌는가?&lt;/li&gt;
&lt;li&gt;팝업 Open 이후 데이터 바인딩이 들어갔는가?&lt;/li&gt;
&lt;li&gt;UI 관련 마커가 뒤이어 나타나는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Hierarchy 확인&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 비용은 &lt;code&gt;Canvas.BuildBatch&lt;/code&gt;인가?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Graphic.Rebuild&lt;/code&gt;인가?&lt;/li&gt;
&lt;li&gt;데이터 처리 함수인가?&lt;/li&gt;
&lt;li&gt;Instantiate인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 추가 분석&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI Details에서 Batches/Vertices가 얼마나 증가했는가?&lt;/li&gt;
&lt;li&gt;Frame Debugger에서 draw call이 크게 쪼개졌는가?&lt;/li&gt;
&lt;li&gt;GC Alloc이 높다면 문자열/리스트 생성이 있었는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막연히 &quot;팝업이 무겁다&quot;가 아니라 &quot;팝업 Open 시 데이터 바인딩 + 텍스트 갱신 + UI 리빌드가 같은 프레임에 몰려 메인 스레드가 튄다&quot;라고 해석할 수 있게 된다.&lt;/p&gt;</description>
      <category>개발/Unity</category>
      <category>Profiler</category>
      <category>unity</category>
      <category>분석</category>
      <category>유니티</category>
      <category>프로파일링</category>
      <category>학습</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/330</guid>
      <comments>https://liveforgame.tistory.com/entry/Unity-1-Profiler-%ED%94%84%EB%A1%9C%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EB%AA%A8%EB%93%88#entry330comment</comments>
      <pubDate>Fri, 3 Apr 2026 18:20:02 +0900</pubDate>
    </item>
    <item>
      <title>[Unity] #0 Profiler - 개요</title>
      <link>https://liveforgame.tistory.com/entry/Unity-1-Profiler-%EA%B0%9C%EC%9A%94</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity 프로파일링 학습 로드맵&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;최적화 기법을 외우기 전에, 프로파일러를 읽는 사람 되기&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 학습의 목표는 단순히 &quot;최적화하는 법&quot;을 아는 것이 아니다.&lt;br /&gt;진짜 목표는 프로파일러에서 보이는 숫자와 마커를 보고, 현재 구조의 문제를 스스로 해석할 수 있는 능력을 만드는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 이번 학습은 다음 질문에 답할 수 있도록 설계한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금 프레임이 왜 느린가?&lt;/li&gt;
&lt;li&gt;이 비용은 UI 때문인가, 로직 때문인가, 데이터 바인딩 때문인가?&lt;/li&gt;
&lt;li&gt;팝업 On/Off 비용이 어느 정도면 괜찮고, 어느 정도면 구조를 바꿔야 하는가?&lt;/li&gt;
&lt;li&gt;현재 UI 구조에서 어떤 설계가 더 유리한가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;학습 개요&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 문제가 보이면 많은 경우 바로 해결책을 떠올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 수를 줄여야 하나?&lt;/li&gt;
&lt;li&gt;Canvas를 나눠야 하나?&lt;/li&gt;
&lt;li&gt;로딩 방식을 바꿔야 하나?&lt;/li&gt;
&lt;li&gt;Update를 줄여야 하나?&lt;/li&gt;
&lt;li&gt;비동기로 바꿔야 하나?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 조언은 많이 보이지만 실제로 어떤 비용이 발생하는지 모르면 그 &lt;b&gt;판단은 거의 감에 가깝다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를&amp;nbsp;들어&amp;nbsp;프레임&amp;nbsp;드랍이&amp;nbsp;발생했다고&amp;nbsp;해보자. &lt;br /&gt;&lt;br /&gt;겉으로&amp;nbsp;보기에는&amp;nbsp;&quot;이펙트가&amp;nbsp;많아서&amp;nbsp;느린&amp;nbsp;것&amp;nbsp;같다&quot;고&amp;nbsp;느껴질&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;하지만&amp;nbsp;실제&amp;nbsp;프로파일러를&amp;nbsp;열어보면&amp;nbsp;병목은&amp;nbsp;전혀&amp;nbsp;다른&amp;nbsp;곳에&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 첫 단계의 핵심은 &lt;b&gt;&quot;최적화 기술&quot;이 아니라 &quot;측정의 언어&quot;를 익히는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;프로파일러는 단순히 느린 구간을 보여주는 도구가 아니다.&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프레임 안에서 어떤 시스템이 시간을 쓰고 있는지를 분해해서 보여주는 해석 도구&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어가&amp;nbsp;&lt;b&gt;60FPS&lt;/b&gt;를 목표로 한다면 &lt;b&gt;한 프레임은 16.67ms 안에 끝나야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;초 단위 계산 : 1 / 60 = &lt;b&gt;0.0166666...s&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;밀리초(ms) 계산 : 1000ms / 60 = &lt;b&gt;16.67ms&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;즉, 어떤 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;UI 팝업을 여는 순간 8ms가 추가&lt;/b&gt;&lt;/span&gt;로 튄다면, 그것은 단순한 숫자가 아니라 &lt;span style=&quot;background-color: #006dd7; color: #ffffff;&quot;&gt;&lt;b&gt;전체 프레임 예산의 절반 가까이를 소비&lt;/b&gt;&lt;/span&gt;했다는 뜻이다. &lt;/span&gt;&lt;u&gt;&lt;b&gt;이 해석이 가능해야 프로파일링이 시작&lt;/b&gt;&lt;/u&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계의 목표는 하나다. &quot;느리다&quot;를 말하는 대신, &lt;b&gt;&lt;u&gt;&quot;어느 프레임에서 무엇이 몇 ms 튀었다&quot;라고 말할 수 있게 되는 것&lt;/u&gt;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;프로파일링은&quot;툴 사용법&quot;이 아니라 &quot;판단 체계&quot;다.&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티 프로파일러는 프로파일러 창에서 버튼 몇 개를 누르는 것으로 사용하는 것이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;툴 조작도 필수적이지만 실질적으로 해당 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;툴이 제공하는 숫자를 해석할 줄 아는것&lt;/b&gt;&lt;/span&gt;이 가장 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;프로파일링은 결국 다음과 같은 질문에 답하는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금 느린 구간은 어느 프레임에서 발생했는가?&lt;/li&gt;
&lt;li&gt;그 프레임에서 가장 큰 비용은 무엇인가?&lt;/li&gt;
&lt;li&gt;그 비용은 CPU인가, GPU인가, 메모리인가?&lt;/li&gt;
&lt;li&gt;이 비용은 일시적인가, 반복적인가?&lt;/li&gt;
&lt;li&gt;사용자가 체감할 만큼 큰가?&lt;/li&gt;
&lt;li&gt;목표 플랫폼 기준에서 허용 가능한 범위인가?&lt;/li&gt;
&lt;li&gt;구조&amp;nbsp;문제인가,&amp;nbsp;구현&amp;nbsp;문제인가,&amp;nbsp;데이터&amp;nbsp;문제인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프로파일링 학습 마일스톤&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;1단계. 프로파일러가 무엇을 보여주는지 이해한다.&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계에서는 &quot;메뉴 설명&quot;보다, 각 항목이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무슨 종류의 비용을 뜻하는지&lt;/b&gt;를 익혀본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU Usage&lt;/li&gt;
&lt;li&gt;Timeline&lt;/li&gt;
&lt;li&gt;Hierarchy&lt;/li&gt;
&lt;li&gt;Rendering&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;GC Alloc&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2단계. 프레임 예산과 측정 기준을 세운다.&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;60FPS 기준 16.67ms&lt;/li&gt;
&lt;li&gt;30FPS 기준 33.33ms&lt;/li&gt;
&lt;li&gt;순간 스파이크와 상시 비용 구분&lt;/li&gt;
&lt;li&gt;평균값과 최대값 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3단계. 실제 게임 기능 하나를 골라 본다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기능 하나를 잡고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;그 기능이 일어나는 프레임을 정확히 찾아본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI 팝업 전환&lt;/li&gt;
&lt;li&gt;로비 진입&lt;/li&gt;
&lt;li&gt;전투 시작&lt;/li&gt;
&lt;li&gt;인벤토리 정렬&lt;/li&gt;
&lt;li&gt;로딩 직후 연출 재생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4단계. 원인과 결과를 연결한다.&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;팝업 On 시 Canvas 관련 마커 상승&quot;&lt;/li&gt;
&lt;li&gt;&quot;로딩 직후 Instantiate 비용 상승&quot;&lt;/li&gt;
&lt;li&gt;&quot;정렬 버튼 클릭 후 GC Alloc 증가&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5단계. 변경 전후를 비교한다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로파일링은 분석 후&amp;nbsp;구조를 바꾸거나 코드를 수정한 뒤, &lt;b&gt;변경 전과 변경 후를 비교&lt;/b&gt;해야 완성된다.&lt;/p&gt;</description>
      <category>개발/Unity</category>
      <category>Profiler</category>
      <category>개선</category>
      <category>성능</category>
      <category>유니티</category>
      <category>프로파일링</category>
      <category>학습</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/329</guid>
      <comments>https://liveforgame.tistory.com/entry/Unity-1-Profiler-%EA%B0%9C%EC%9A%94#entry329comment</comments>
      <pubDate>Fri, 3 Apr 2026 17:17:11 +0900</pubDate>
    </item>
    <item>
      <title>[Unity] 최적화 체크리스트</title>
      <link>https://liveforgame.tistory.com/entry/Unity-%EC%B5%9C%EC%A0%81%ED%99%94-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity 성능 최적화 체크리스트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;측정 기준부터 고정해라.&lt;/span&gt; &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;어떤&amp;nbsp;씬을&amp;nbsp;측정할지&amp;nbsp;정한다.&lt;/li&gt;
&lt;li&gt;어떤&amp;nbsp;기기에서&amp;nbsp;볼지&amp;nbsp;정한다.&lt;/li&gt;
&lt;li&gt;측정 항목을 고정한다 : FPS, Main Thread ms, GC Alloc, Draw Call, SetPass, 메모리 사용량, 로딩 시간.&lt;/li&gt;
&lt;li&gt;변경&amp;nbsp;전/후&amp;nbsp;수치를&amp;nbsp;반드시&amp;nbsp;기록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;CPU&amp;nbsp;병목부터&amp;nbsp;본다.&lt;/span&gt; &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Update,&amp;nbsp;LateUpdate,&amp;nbsp;FixedUpdate에&amp;nbsp;불필요한&amp;nbsp;반복&amp;nbsp;로직이&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;GetComponent,&amp;nbsp;Find,&amp;nbsp;Camera.main&amp;nbsp;같은&amp;nbsp;반복&amp;nbsp;호출을&amp;nbsp;줄인다.&lt;/li&gt;
&lt;li&gt;LINQ,&amp;nbsp;boxing,&amp;nbsp;문자열&amp;nbsp;결합,&amp;nbsp;delegate&amp;nbsp;캡처가&amp;nbsp;런타임&amp;nbsp;hot&amp;nbsp;path에&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;이벤트 기반으로 바꿀 수 있는 풀링 로직을 찾는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;GC&amp;nbsp;Alloc을&amp;nbsp;관리한다.&lt;/b&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프레임마다&amp;nbsp;new가&amp;nbsp;발생하는&amp;nbsp;코드가&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;로그&amp;nbsp;문자열&amp;nbsp;조합이&amp;nbsp;런타임에서&amp;nbsp;과하게&amp;nbsp;발생하지&amp;nbsp;않는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;컬렉션&amp;nbsp;재할당,&amp;nbsp;임시&amp;nbsp;배열&amp;nbsp;생성,&amp;nbsp;ToList()&amp;nbsp;남발을&amp;nbsp;줄인다.&lt;/li&gt;
&lt;li&gt;가능하면&amp;nbsp;전투/UI&amp;nbsp;핵심&amp;nbsp;루프는&amp;nbsp;GC&amp;nbsp;Alloc&amp;nbsp;0B/frame을&amp;nbsp;목표로&amp;nbsp;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;UI를&amp;nbsp;별도로&amp;nbsp;본다.&lt;/b&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Canvas를&amp;nbsp;너무&amp;nbsp;크게&amp;nbsp;묶지&amp;nbsp;않았는지&amp;nbsp;확인한다.&lt;/li&gt;
&lt;li&gt;Layout&amp;nbsp;Group,&amp;nbsp;Content&amp;nbsp;Size&amp;nbsp;Fitter,&amp;nbsp;잦은&amp;nbsp;SetActive가&amp;nbsp;Rebuild를&amp;nbsp;유발하는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;ScrollView&amp;nbsp;항목&amp;nbsp;재사용이&amp;nbsp;되는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;텍스트&amp;nbsp;변경이&amp;nbsp;빈번한&amp;nbsp;UI를&amp;nbsp;묶어서&amp;nbsp;관리하는지&amp;nbsp;본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;로딩과&amp;nbsp;Addressables를&amp;nbsp;본다.&lt;/span&gt; &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;초기&amp;nbsp;로드가&amp;nbsp;과도하게&amp;nbsp;크지&amp;nbsp;않은지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;프리로드와&amp;nbsp;지연&amp;nbsp;로드를&amp;nbsp;구분했는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;Handle&amp;nbsp;해제&amp;nbsp;누락이&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;Addressables&amp;nbsp;그룹이&amp;nbsp;너무&amp;nbsp;뭉쳐&amp;nbsp;있거나&amp;nbsp;너무&amp;nbsp;쪼개져&amp;nbsp;있지&amp;nbsp;않은지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;씬&amp;nbsp;진입&amp;nbsp;시&amp;nbsp;동기&amp;nbsp;대기가&amp;nbsp;들어가&amp;nbsp;있는지&amp;nbsp;본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;메모리와&amp;nbsp;리소스를&amp;nbsp;본다.&lt;/b&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;텍스처&amp;nbsp;크기와&amp;nbsp;압축이&amp;nbsp;적절한지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;중복&amp;nbsp;로드되는&amp;nbsp;에셋이&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;참조가&amp;nbsp;끊기지&amp;nbsp;않아&amp;nbsp;해제&amp;nbsp;안&amp;nbsp;되는&amp;nbsp;객체가&amp;nbsp;없는지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;오브젝트&amp;nbsp;풀링이&amp;nbsp;필요한&amp;nbsp;대상을&amp;nbsp;찾는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;렌더링&amp;nbsp;비용도&amp;nbsp;분리해서&amp;nbsp;본다.&lt;/span&gt; &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Draw&amp;nbsp;Call,&amp;nbsp;SetPass,&amp;nbsp;Overdraw를&amp;nbsp;확인한다.&lt;/li&gt;
&lt;li&gt;머티리얼/아틀라스&amp;nbsp;분리가&amp;nbsp;비효율적이지&amp;nbsp;않은지&amp;nbsp;본다.&lt;/li&gt;
&lt;li&gt;반투명&amp;nbsp;UI가&amp;nbsp;겹쳐&amp;nbsp;과도한&amp;nbsp;Overdraw를&amp;nbsp;만들지&amp;nbsp;않는지&amp;nbsp;본다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Unity</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/328</guid>
      <comments>https://liveforgame.tistory.com/entry/Unity-%EC%B5%9C%EC%A0%81%ED%99%94-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8#entry328comment</comments>
      <pubDate>Fri, 3 Apr 2026 12:41:24 +0900</pubDate>
    </item>
    <item>
      <title>[개발] AI 시대 나는 무엇을 해야할까</title>
      <link>https://liveforgame.tistory.com/entry/%EA%B0%9C%EB%B0%9C-AI-%EC%8B%9C%EB%8C%80-%EB%82%98%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%84-%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;트렌드는 빠르게 변한다.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 기술의 발전속도는 기하급수적이지만, 대 AI시대가 열리고 그 속도는 상상을 초월하는 수준에 달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 개발자 3~4명 아니 우습게 10명분의 작업이 월 30만 원짜리 AI 멤버십이면 상단 한 수준으로 개발되는 시대가 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해본 적도 없는 작업도 프롬프트로 요구사항만 적으면&amp;nbsp; 알아서 개발이 되어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기에는 AI에게 기능 위주 개발을 맡겼다면, 이제는 앱 전체에 구조까지 전부 맡기는 수준이다. (실제로 그렇게 일하는 분들도 봤다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 금융이나 개인정보와 같은 수준 있는 보안과 복잡한 절차/기능이 필요한 콘텐츠에는 AI에게 전체 설계를 맡기지는 않겠지만, 자잘한 기능 구현정도는 코드 리뷰 및 QA 과정을 더욱 강화하여 사용할 수 있을 정도로도 보인다. (이쪽 전문가는 아니라 자세히는 모른다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 또한 게으른 편이라 AI의 발전에 엄청난 윤택함을 느끼고 있다. 하지만 반대로 나의 일반적 작업의 대부분이 대체되는 것도 충분히 느껴지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 무엇을 해야 할까? 고민을 해보고 당연하지만 기억해야하는 대답을 적어볼까 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;할 줄 아는 것이 당연하게 되는 세상&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 지금 시대가 무엇인가를 해보고 싶다면 누구나 간단하게 개발로 찍먹을 해볼 수 있는 시대라고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은 곧, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;기능 구현의 시간이 쉽고 단축&lt;/b&gt;&lt;/span&gt;되었다고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자였던 친한 형이 GPT조차 없던 시절 이런 말을 한 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;누구에게나 무한한 시간이 주어지면 못 만드는 건 없다.&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 다수 동의하는 말이다. 하지만 안타깝게도 우리에게는 무한한 시간이 주어지지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;'콘텐츠 구상 &amp;gt; 필요 기능 추산 &amp;gt; 구조 설계 &amp;gt; 구현 &amp;gt; 테스트 &amp;gt; 검증 &amp;gt; 3자 QA'&lt;/b&gt;과정을 시간과 비용의 제약 때문에 개발자라는 직군이 필요했던 부분이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 지금은 이 흐름 상당 부분이 AI 보조하에 대체될 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 기능 구현에 대한 부분은 전적으로 AI에게 의존하면 되는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 개인적으로는 이는 AI를 사용하는 사람의 생각의 깊이와 폭의 차이는 사람마다 다를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음 소프트웨어를 개발한다 치자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;이쑤시개의 개수를 세는 기능을 만들어라.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 간단하게는&amp;nbsp;'&lt;b&gt;이미지가 주어지면 해당 이미지에서 확인가능한 이쑤시개의 개수를 세는 프로그램을 만들어야 한다.&lt;/b&gt;'로 시작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 다음과 같이 추가 질문을 할 수 있다. (= 추가질문은 프롬프트에 추가적으로 적을 수 있는 지시문이 될 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;953&quot; data-start=&quot;938&quot;&gt;이미지 포맷은 일정한가?&lt;/li&gt;
&lt;li data-end=&quot;968&quot; data-start=&quot;954&quot;&gt;촬영 환경은 고정인가?&lt;/li&gt;
&lt;li data-end=&quot;986&quot; data-start=&quot;969&quot;&gt;객체 위치는 항상 동일한가?&lt;/li&gt;
&lt;li data-end=&quot;1003&quot; data-start=&quot;987&quot;&gt;결과는 어디에 저장되는가?&lt;/li&gt;
&lt;li data-end=&quot;1015&quot; data-start=&quot;1004&quot;&gt;서버가 필요한가?&lt;/li&gt;
&lt;li data-end=&quot;1027&quot; data-start=&quot;1016&quot;&gt;인증은 필요한가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 고민들을 계속하다 보면 쓸 때 없는 고민들이 다수 있다. 그래도 가아끔 설계 의도와 배경을 알고 있는 사람만이 할 수 있는 질문들도 나올 수가 있다. 그리고 이는 &lt;b&gt;시스템 설계 영역&lt;/b&gt;으로 이어질 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;물론 이러한 질문 수준도&amp;nbsp;&lt;b&gt;아는 만큼만 나온다.&lt;/b&gt; 그래서 직접 공부/경험해야 하는 거다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 질문을 정리하고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기능의 원자성을 가능한 보장 하여 차후&lt;/span&gt; 구조가 바뀌더라도 설계 자체가 흔들리지는 않을 정도의 노력은 해봐야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI를 적극적으로 사용하되 그 프롬프트에 지시하기까지의 생각은 정리해보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 프롬프트마저도 자동 생성해 주는 기능들도 있다. 만약 본인의 생각의 깊이와 폭이 넓지 않다면(나부터) 이런 기능들로 놓치고 있는 부분들까지 대비하도록 쓸 수 있을 듯하지만 &lt;b&gt;AI는 방향을 정하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 매우 빠르게 답을 만들어내지만 그 답이 &amp;ldquo;맞는 방향인지&amp;rdquo;는 판단하지 않는다.&lt;br /&gt;같은 기능을 만들어도 누군가는 재사용 가능한 구조를 만들고 누군가는 한 번 쓰고 버릴 코드를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 판단을 잘해보려 노력해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;우리의 최종적 역할은 구현자가 아니다.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유명한 개발자 유튜버분들 영상을 보다가 &quot;기능을 구현할 수는 있지만 자신이 만든 것도 이해하지도 못하고 버그의 원인도 못 찾는 사람들이 있다.&quot;라는 말을 들은 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드 작성, PR생성, 프로젝트 생성마저도 대신해주는 바이브 코딩이 되는 시대에는 더 와닿는 말이 된 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 나도 이런 적이 한 번도 없었다고는 양심이 찔려 말할 수는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일회용 코드, &lt;b&gt;공유하기 힘든 코드에 대한 부끄러움을 스스로 느끼는 것이 시작&lt;/b&gt;일 것이다. ('공유될 일이 절대 없다'하여도)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 AI를 잘 쓰는 사람과 그렇지 못한 사람의 차이는 프롬프트가 아니라 &lt;b&gt;설계에서 갈리는 것&lt;/b&gt; 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 기능을 만들어도 누군가는 확장 가능한 구조를 만들 것이고, 누군가는&amp;nbsp;다시&amp;nbsp;버려야&amp;nbsp;하는&amp;nbsp;코드를&amp;nbsp;만든다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;무엇을 만들어야 하는지&lt;/li&gt;
&lt;li&gt;왜&amp;nbsp;그렇게&amp;nbsp;만들어야&amp;nbsp;하는지&lt;/li&gt;
&lt;li&gt;어떤&amp;nbsp;확장성을&amp;nbsp;고려해야&amp;nbsp;하는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 부분은 여전히 사람의 영역으로 보인다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;우리는 무엇을 해야 하는가?&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI를 사용하지 말자고 이 글을 쓰는 것이 아니다. 오히려 적극적 활용을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 한 가지 전제만 있으면 될듯하다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;고민하지 않고 쓰지 말기&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1775&quot; data-start=&quot;1755&quot;&gt;요구사항을 명확하게 정의할 것&lt;/li&gt;
&lt;li data-end=&quot;1791&quot; data-start=&quot;1776&quot;&gt;질문을 깊게 던질 것&lt;/li&gt;
&lt;li data-end=&quot;1808&quot; data-start=&quot;1792&quot;&gt;구조를 먼저 설계할 것&lt;/li&gt;
&lt;li data-end=&quot;1826&quot; data-start=&quot;1809&quot;&gt;결과를 반드시 이해할 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1969&quot; data-start=&quot;1942&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1969&quot; data-start=&quot;1942&quot; data-ke-size=&quot;size16&quot;&gt;이제는 시간이 없어도 무엇인가를 만들 수 있는 시대가 왔다.&lt;/p&gt;
&lt;p data-end=&quot;1969&quot; data-start=&quot;1942&quot; data-ke-size=&quot;size16&quot;&gt;다만, 그 '무엇인가'를 &lt;b&gt;제대로 만들 수 있는가는 여전히 사람에게 달려 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1969&quot; data-start=&quot;1942&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일기</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/327</guid>
      <comments>https://liveforgame.tistory.com/entry/%EA%B0%9C%EB%B0%9C-AI-%EC%8B%9C%EB%8C%80-%EB%82%98%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%84-%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C#entry327comment</comments>
      <pubDate>Sat, 28 Mar 2026 20:48:26 +0900</pubDate>
    </item>
    <item>
      <title>[회고] Unity asmdef 세분화 회고</title>
      <link>https://liveforgame.tistory.com/entry/%ED%9A%8C%EA%B3%A0-Unity-asmdef-%EC%84%B8%EB%B6%84%ED%99%94-%ED%9A%8C%EA%B3%A0</link>
      <description>&lt;h2 style=&quot;color: #006dd7;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Unity asmdef 세분화 회고 : 설계 회고&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 실제 분할 과정에서 무엇을 버리고 무엇을 남겨야 하는지를 정리한 실전 초안이다.&lt;br /&gt;&lt;b&gt;독립성 없는 코드는 asmdef 분할 이전에 이미 구조적으로 불안한 코드&lt;/b&gt;다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한 줄 요약&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;asmdef는 성능 최적화 버튼이 아니라, &lt;b&gt;아키텍처 품질 검사기&lt;/b&gt;다.&lt;/li&gt;
&lt;li&gt;분할이 안 된다면 asmdef 문제가 아니라 &lt;b&gt;의존성 설계 문제&lt;/b&gt;다.&lt;/li&gt;
&lt;li&gt;단방향 참조 제약은 불편하지만, 그 덕분에 인터페이스/이벤트/레지스트리 같은 &lt;b&gt;건강한 우회 패턴&lt;/b&gt;이 강제된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜 분할이 막히는가 : 독립성 붕괴 징후&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 97px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.4031%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt; 징후 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54.6123%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt; 실제로 벌어지는 일 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.9845%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt; 결과 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.4031%; height: 21px; text-align: center;&quot;&gt;기능 경계 침범&lt;/td&gt;
&lt;td style=&quot;width: 54.6123%; height: 21px; text-align: center;&quot;&gt;한 클래스가 UI, 데이터, 게임로직, 네트워크까지 동시에 만짐&lt;/td&gt;
&lt;td style=&quot;width: 27.9845%; height: 21px; text-align: center;&quot;&gt;컴파일 의존성 폭증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.4031%; height: 21px; text-align: center;&quot;&gt;양방향 호출 습관&lt;/td&gt;
&lt;td style=&quot;width: 54.6123%; height: 21px; text-align: center;&quot;&gt;A가 B를 알고, B도 A를 직접 참조&lt;/td&gt;
&lt;td style=&quot;width: 27.9845%; height: 21px; text-align: center;&quot;&gt;asmdef 단방향 참조와 충돌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 17.4031%; height: 17px; text-align: center;&quot;&gt;전역 싱글톤 남용&lt;/td&gt;
&lt;td style=&quot;width: 54.6123%; height: 17px; text-align: center;&quot;&gt;어디서나 접근 가능한 매니저가 서로 뒤엉킴&lt;/td&gt;
&lt;td style=&quot;width: 27.9845%; height: 17px; text-align: center;&quot;&gt;테스트/교체/분리 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 17.4031%; height: 17px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; DTO에 로직 침투 &lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54.6123%; height: 17px; text-align: center;&quot;&gt;데이터 컨테이너가 서비스 호출까지 수행&lt;/td&gt;
&lt;td style=&quot;width: 27.9845%; height: 17px; text-align: center;&quot;&gt;Data asmdef 독립성 붕괴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;&quot;이건 편해서 넣었다&quot;&lt;/b&gt;&lt;/u&gt;는 이유로 참조를 추가했다면, 거의 항상 기술부채이다.&lt;/li&gt;
&lt;li&gt;asmdef 그래프를 그렸을 때 화살표가 복잡해지는 순간, 코드 책임이 잘못 배치된 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정의해본 asmdef 범주&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;&lt;b&gt; asmdef &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;&lt;b&gt; 책임(해야 할 일) &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;&lt;b&gt; 금지(하면 안 되는 일)&lt;br /&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;Hong.Core&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;공통 유틸, 도메인 공통 인터페이스, 이벤트 계약&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;UI/씬 전용 로직 직접 참조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;Hong.Data&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;순수&amp;nbsp;데이터&amp;nbsp;컨테이너,&amp;nbsp;직렬화&amp;nbsp;모델&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;Unity&amp;nbsp;컴포넌트/서비스&amp;nbsp;직접&amp;nbsp;호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;Hong.*(Feature)&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;기능별&amp;nbsp;유스케이스/오케스트레이션&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;Feature&amp;nbsp;간&amp;nbsp;순환&amp;nbsp;참조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;Hong.Presentation&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;View,&amp;nbsp;Presenter/Controller,&amp;nbsp;사용자&amp;nbsp;입력&amp;nbsp;연결&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;Data&amp;nbsp;레이어&amp;nbsp;내부&amp;nbsp;구현&amp;nbsp;침투&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1239%; text-align: center;&quot;&gt;Hong.Backend&lt;/td&gt;
&lt;td style=&quot;width: 50.4265%; text-align: center;&quot;&gt;네트워크 구현체&lt;/td&gt;
&lt;td style=&quot;width: 28.4495%; text-align: center;&quot;&gt;상위&amp;nbsp;레이어&amp;nbsp;역참조&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DrKJ8/dJMcadnIUFR/uJH30sLM5HAAXNqvDbfRi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DrKJ8/dJMcadnIUFR/uJH30sLM5HAAXNqvDbfRi1/img.png&quot; data-alt=&quot;개인적으로 그려본 asmdef 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DrKJ8/dJMcadnIUFR/uJH30sLM5HAAXNqvDbfRi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDrKJ8%2FdJMcadnIUFR%2FuJH30sLM5HAAXNqvDbfRi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1042&quot; height=&quot;579&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개인적으로 그려본 asmdef 그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;단방향 참조를 우회하는 3가지 패턴 &lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;1) 하위 공용 어셈블리에 인터페이스를 두는 방식&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;구현은 상위&lt;/b&gt;에, &lt;b&gt;계약(인터페이스)은 하위&lt;/b&gt;에 둔다.&lt;/li&gt;
&lt;li&gt;상위 기능은 하위 계약만 바라본다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;두 기능을 연결해주는 과정이 필요&lt;/b&gt;&lt;/u&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;namespace Hong.Core.Contracts {
    public interface IGoldService {
        public int CurrentGold { get; }
        public bool TrySpend(int amount);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1773733455550&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hong.Core
  - IGoldService
Hong.A
  - AManager (IGoldService를 사용)
Hong.B
  - BManager : IGoldService&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;2) 공통 이벤트(메시지) 기반 호출&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 참조 대신 이벤트를 발행/구독한다.&lt;/li&gt;
&lt;li&gt;호출 대상 존재 여부를 몰라도 동작하므로 결합도를 낮춘다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;using System;

namespace Hong.Core.Events {
    public sealed class GameEventBus {
        Action&amp;lt;int&amp;gt; goldChanged;
        public void PublishGoldChanged(int value) =&amp;gt; goldChanged?.Invoke(value);
        public void SubscribeGoldChanged(Action&amp;lt;int&amp;gt; handler) =&amp;gt; goldChanged += handler;
        public void UnsubscribeGoldChanged(Action&amp;lt;int&amp;gt; handler) =&amp;gt; goldChanged -= handler;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;3) Registry/Locator로 런타임 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 타임 참조를 줄이고 런타임에 구현체를 바인딩한다.&lt;/li&gt;
&lt;li&gt;단, &lt;b&gt;무분별한 서비스 로케이터 남용은 또 다른 전역 의존성&lt;/b&gt;이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;using System;
using System.Collections.Generic;

namespace Hong.Core.Runtime {
    public static class ServiceRegistry {
        static readonly Dictionary&amp;lt;Type, object&amp;gt; map = new Dictionary&amp;lt;Type, object&amp;gt;();

        public static void Register&amp;lt;T&amp;gt;(T service) where T : class {
            var key = typeof(T);
            map[key] = service;
        }

        public static bool TryResolve&amp;lt;T&amp;gt;(out T service) where T : class {
            var key = typeof(T);
            if (map.TryGetValue(key, out var value) == false) {
                service = null;
                return false;
            }

            service = value as T;
            return service != null;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제) &quot;상점 구매&quot; 흐름을 asmdef 친화적으로 나누기&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;A. 분할 전(문제 구조)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;ShopUI&lt;/code&gt;가 &lt;code&gt;InventoryManager&lt;/code&gt;, &lt;code&gt;SaveManager&lt;/code&gt;, &lt;code&gt;NetworkManager&lt;/code&gt;, &lt;code&gt;PlayerController&lt;/code&gt;를 직접 호출.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과 : &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;UI asmdef가 거의 모든 asmdef를 참조&lt;/b&gt;&lt;/span&gt;하게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;B. 분할 후(개선 구조)&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;Hong.Core.Contracts  &amp;lt;- 인터페이스/이벤트 계약
Hong.Data            &amp;lt;- ItemData, WalletData (순수 데이터)
Hong.Shop    		&amp;lt;- ShopPurchaseUseCase
Hong.Presentation    &amp;lt;- ShopViewPresenter
Hong.Infrastructure  &amp;lt;- WalletService, SaveRepository 구현&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;C. 의존성 방향 표&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 85px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt; From &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt; To &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt; 이유 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Presentation&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Core.Contracts, Feature.Shop&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;입력 전달/결과 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Feature.Shop&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Core.Contracts, Data&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;유스케이스 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Infrastructure&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Core.Contracts, Data&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;계약 구현/저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Data&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;(없음)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;순수 컨테이너 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;D. 핵심 유스케이스 예시 코드&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아래 코드는 &quot;UI는 유스케이스만 호출&quot;하고, &quot;유스케이스는 계약만 의존&quot;하도록 만든 최소 형태다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;using Hong.Core.Contracts;
using Hong.Data;

namespace Hong.Feature.Shop {
    public sealed class ShopPurchaseUseCase {
        readonly IGoldService goldService;
        readonly IInventoryService inventoryService;

        public ShopPurchaseUseCase(IGoldService goldService, IInventoryService inventoryService) {
            this.goldService = goldService;
            this.inventoryService = inventoryService;
        }

        public PurchaseResult Purchase(ItemData item) {
            if (item == null) return PurchaseResult.Fail(&quot;Item is null&quot;);
            if (goldService.TrySpend(item.Price) == false) return PurchaseResult.Fail(&quot;Not enough gold&quot;);

            inventoryService.Add(item.Id, 1);
            return PurchaseResult.Success();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실무 체크리스트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Data asmdef에 UnityEngine 참조가 없는가?&lt;/li&gt;
&lt;li&gt;Feature 계층이 UI 타입(MonoBehaviour, TMP_Text 등)을 모르는가?&lt;/li&gt;
&lt;li&gt;한 asmdef의 public API가 다른 asmdef 내부 구현 클래스를 노출하지 않는가?&lt;/li&gt;
&lt;li&gt;순환 참조를 인터페이스/이벤트/레지스트리로 해소했는가?&lt;/li&gt;
&lt;li&gt;&quot;편의상&quot; 추가한 참조를 근거와 함께 설명할 수 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;회고&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;독립성을 지키지 않으면 asmdef 분할은 사실상 불가능&lt;/b&gt;하다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;설계가 먼저고, asmdef는 그 결과를 검증하는 도구다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;asmdef 분할은 기존 코드의 책임을 다시 묻게 만든다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Core/Data/Feature 경계를 재정의하면서 불필요한 결합을 발견하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단방향 참조 제약은 귀찮지만, 결국 구조를 건강하게 만든다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인터페이스, 이벤트, 레지스트리 패턴은 선택이 아니라 필수에 가깝다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #0593d3;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;asmdef를 나눴더니 빌드가 빨라졌다&quot;는 결과는 부수효과&lt;/li&gt;
&lt;li&gt;진짜 성과는 &lt;b&gt;코드가 자기 책임을 지키도록 강제된 것&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;분할 경험은, 결국 아키텍처는 기술이 아니라 습관&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/개발일기</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/324</guid>
      <comments>https://liveforgame.tistory.com/entry/%ED%9A%8C%EA%B3%A0-Unity-asmdef-%EC%84%B8%EB%B6%84%ED%99%94-%ED%9A%8C%EA%B3%A0#entry324comment</comments>
      <pubDate>Tue, 17 Mar 2026 16:51:05 +0900</pubDate>
    </item>
    <item>
      <title>[Architech] 유니티로 배우는 MVC</title>
      <link>https://liveforgame.tistory.com/entry/Unity-%EC%9C%A0%EB%8B%88%ED%8B%B0%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-MVC</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity MVC 패턴 예제 &amp;ndash; Player Health System&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;학습 목적&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unity에서도 Model / View / Controller 를 명확히 분리할 수 있음을 이해한다.&lt;/li&gt;
&lt;li&gt;유지보수성과 확장성이 높은 구조를 경험한다.&lt;/li&gt;
&lt;li&gt;순수 C# 로직(Model) 과 Unity 엔진 요소(View) 의 역할 차이를 체험한다.&lt;/li&gt;
&lt;li&gt;UI 변경이 로직에 영향을 주지 않는 구조를 설계한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;MVC 핵심 개념 설명&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;MVC 패턴이란 무엇인가?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC(Model&amp;ndash;View&amp;ndash;Controller) 패턴은 소프트웨어를 구성할 때, 데이터(Model), 화면(View), 흐름 제어(Controller) 를 명확하게 분리하여 유지보수성을 높이고 확장성을 확보하는 대표적인 아키텍처 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity는 구조상 &amp;ldquo;MonoBehaviour 안에 모든 로직이 섞이는&amp;rdquo; 형태가 되기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그렇기 때문에 MVC를 의도적으로 적용하면 UI와 게임 로직의 결합을 최소화할 수 있고, 변경이 잦은 부분(UX/UI)과 안정적이어야 하는 부분(로직)을 분리할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;MVC를 나누는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임과 UI 개발은 다음과 같은 문제가 자주 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI가 바뀌면 게임 로직 코드도 함께 수정해야 한다.&lt;/li&gt;
&lt;li&gt;로직에 버그가 있어도 UI가 섞여 있어 디버깅이 어렵다.&lt;/li&gt;
&lt;li&gt;단위 테스트 작성이 불가능하다.&lt;/li&gt;
&lt;li&gt;여러 시스템이 하나의 클래스에서 서로 참조하며 높은 결합도가 생긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC는 이를 해결하기 위해 다음과 같은 목표를 갖는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관심사 분리(SoC: Separation of Concerns)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;데이터는 Model이 책임진다&quot;&lt;/li&gt;
&lt;li&gt;&quot;표시는 View가 책임진다&quot;&lt;/li&gt;
&lt;li&gt;&quot;흐름 제어는 Controller가 책임진다&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI 변경이 로직에 영향을 주지 않는 구조&lt;/li&gt;
&lt;li&gt;로직을 테스트 가능한 형태로 격리&lt;/li&gt;
&lt;li&gt;클래스 책임이 명확해져 유지보수성이 크게 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;MVC 구성 요소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Model&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;데이터와 규칙&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐릭터 체력, 공격력 같은 데이터&lt;/li&gt;
&lt;li&gt;데미지 계산 같은 비즈니스 로직&lt;/li&gt;
&lt;li&gt;체력이 변하면 이벤트(Action) 으로 외부에 알림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UnityEngine API를 사용하지 않음&lt;/li&gt;
&lt;li&gt;순수 C# 로직&lt;/li&gt;
&lt;li&gt;View나 Controller를 모름 (완전 독립적)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;View&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;화면 표시 전담&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI 요소(Text, Slider, Image 등)를 화면에 보여줌&lt;/li&gt;
&lt;li&gt;Model로부터 전달된 데이터를 시각적으로 표현&lt;/li&gt;
&lt;li&gt;로직 계산은 절대 하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MonoBehaviour 기반&lt;/li&gt;
&lt;li&gt;UI 변경만 담당&lt;/li&gt;
&lt;li&gt;Model&amp;middot;Controller 로직을 알 필요 없음&lt;/li&gt;
&lt;li&gt;View는 UI가 변경될 때에도 Model이나 Controller 수정 없이 교체가 가능해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Controller&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;입력과 흐름 제어 담당&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 처리&lt;/li&gt;
&lt;li&gt;Model 변경 &amp;rarr; 이벤트 수신 &amp;rarr; View 갱신&lt;/li&gt;
&lt;li&gt;전체 흐름을 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;View와 Model 간의 직접 연결을 관리&lt;/li&gt;
&lt;li&gt;게임 동작 전체의 orchestration 담당&lt;/li&gt;
&lt;li&gt;UI와 로직을 이어주는 Glue Layer&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;MVC 데이터 흐름&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;입력(Input)
     &amp;darr;
Controller
     &amp;darr;
Model (상태 변경)
     &amp;darr; 이벤트 발생
Controller (이벤트 수신)
     &amp;darr;
View (UI 갱신)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC는 이 구조 덕분에 다음과 같은 이점이 생긴다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 방식을 바꿔도 모델은 그대로 유지&lt;/li&gt;
&lt;li&gt;UI 스킨을 교체해도 로직은 그대로 유지&lt;/li&gt;
&lt;li&gt;Controller가 연결체계를 변경해도 각 레이어는 독립적으로 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장단점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; text-align: center;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center;&quot;&gt;구조가&amp;nbsp;단순하고&amp;nbsp;초기&amp;nbsp;구축이&amp;nbsp;&lt;b&gt;빠르다&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%;&quot;&gt;UI가&amp;nbsp;몇&amp;nbsp;개&amp;nbsp;없고&amp;nbsp;로직이&amp;nbsp;단순한&amp;nbsp;프로젝트에서는&amp;nbsp;MVC가&amp;nbsp;매우&amp;nbsp;빠르게&amp;nbsp;적용된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center;&quot;&gt;View 로직이 Controller에 몰림&lt;br /&gt;(초기 &lt;b&gt;학습곡선 낮음&lt;/b&gt;)&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%;&quot;&gt;&amp;lt;입력 &amp;rarr; Controller &amp;rarr; Model &amp;rarr; View&amp;gt; 이&amp;nbsp;구조만&amp;nbsp;이해하면&amp;nbsp;빠르게&amp;nbsp;개발할&amp;nbsp;수&amp;nbsp;있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center;&quot;&gt;Unity의 전통적 개발 방식과 어울림&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%;&quot;&gt;MonoBehaviour 안에 &amp;ldquo;입력 처리 + 로직 + UI 업데이트&amp;rdquo;가 섞이는 기본 Unity 스타일과 유사하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center;&quot;&gt;&lt;b&gt;아주&amp;nbsp;작은&amp;nbsp;게임&lt;/b&gt;,&amp;nbsp;UI가&amp;nbsp;적은&amp;nbsp;프로젝트에&amp;nbsp;최적&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;521&quot; data-end=&quot;584&quot;&gt;
&lt;li data-start=&quot;521&quot; data-end=&quot;533&quot;&gt;간단한 미니게임&lt;/li&gt;
&lt;li data-start=&quot;534&quot; data-end=&quot;560&quot;&gt;1~2개의 UI만 있는 간단한 프로토타입&lt;/li&gt;
&lt;li data-start=&quot;561&quot; data-end=&quot;584&quot;&gt;System 구조가 없는 개발 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 246px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center; height: 21px;&quot;&gt;단점&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; text-align: center; height: 21px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center; height: 21px;&quot;&gt;프로젝트&amp;nbsp;규모가&amp;nbsp;조금만&amp;nbsp;커져도&amp;nbsp;&lt;b&gt;Controller가&amp;nbsp;비대해진다&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 21px;&quot;&gt;&lt;span&gt;Controller가 다음 &lt;b&gt;&amp;lt;입력, 로직 호출, 모듈 변경/관리, 뷰 업데이트, 여러 UI 동기화&amp;gt; 전부 처리&lt;/b&gt;하게 됨&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center; height: 42px;&quot;&gt;&lt;b&gt;UI가&amp;nbsp;늘어날수록&lt;/b&gt;&amp;nbsp;로직&amp;nbsp;변경&amp;nbsp;비용이&amp;nbsp;폭증&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 42px;&quot;&gt;Controller가 View를 직접 갱신하므로 &lt;b&gt;UI가 여러 개일 때 깊이 결합&lt;/b&gt;되고 &lt;b&gt;UI&amp;nbsp;교체&amp;nbsp;시&amp;nbsp;Controller를&amp;nbsp;반드시&amp;nbsp;수정&lt;/b&gt;해야&amp;nbsp;함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; text-align: center; height: 42px;&quot;&gt;Model은 재사용하기 어렵고,&lt;br /&gt;테스트하기 매우 어렵다&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 42px;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1006&quot; data-start=&quot;975&quot;&gt;&lt;span&gt;Controller에 Model 흐름이 박혀 있음&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1035&quot; data-start=&quot;1007&quot;&gt;&lt;span&gt;UI가 없어도 Model을 테스트하기 어려움&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1073&quot; data-start=&quot;1036&quot;&gt;&lt;span&gt;UI 구조가 바뀌면 Model/Controller가 줄줄이 바뀜&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실행 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Canvas 아래에 Text + Slider 생성&lt;/li&gt;
&lt;li&gt;PlayerHealthView 를 추가하고 Text/Slider 연결&lt;/li&gt;
&lt;li&gt;빈 GameObject &amp;rarr; PlayerHealthController 추가&lt;/li&gt;
&lt;li&gt;View 레퍼런스를 Drag &amp;amp; Drop&lt;/li&gt;
&lt;li&gt;인풋매니저(신버젼 커스텀 설정 필요)에서 각 Damage/Heal이 동작할 키를 바인드&lt;/li&gt;
&lt;li&gt;실행:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Down/S &amp;rarr; 데미지&lt;/li&gt;
&lt;li&gt;Up/W &amp;rarr; 회복&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;컨트롤러&lt;/b&gt;&lt;/blockquote&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1764564621092&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.InputSystem;
using HUtil.Logger;
using HUtil.Inspector;

namespace SWU.Architech.MVC {
    public class MvcHealthController : MonoBehaviour {
        #region 필드
        [HTitle(&quot;Input&quot;)]
        [SerializeField]
        InputActionReference damageAction;
        [SerializeField]
        InputActionReference healAction;

        [HTitle(&quot;View Reference&quot;)]
        [SerializeField]
        MvcHealthView view;

        [HTitle(&quot;초기 체력 설정&quot;)]
        [SerializeField]
        int maxHealth = 100;

        [HTitle(&quot;테스트용 데미지/회복 값&quot;)]
        [SerializeField]
        int damagePerHit = 10;
        [SerializeField]
        int healPerKey = 5;

        MvcHealthModel model;
        #endregion

        #region 프로퍼티
        public MvcHealthModel Model =&amp;gt; model;
        private InputAction _DamageAction =&amp;gt; damageAction != null ? damageAction.action : null;
        private InputAction _HealAction =&amp;gt; healAction != null ? healAction.action : null;
        #endregion

        #region 생성자 / 초기화 함수
        private void _Initialize() {
            if (maxHealth &amp;lt;= 0) maxHealth = 1;

            model = new MvcHealthModel(maxHealth);
            model.OnHealthChanged += _OnHealthChanged;
            model.OnDead += _OnDead;

            if (view != null) view.Initialize(model.Current, model.Max);
        }

        private void _RegisterInput() {
            if (_DamageAction != null) {
                _DamageAction.performed += _OnDamagePerformed;
                _DamageAction.Enable();
            }

            if (_HealAction != null) {
                _HealAction.performed += _OnHealPerformed;
                _HealAction.Enable();
            }
        }

       private void _UnregisterInput() {
            if (_DamageAction != null) {
                _DamageAction.performed -= _OnDamagePerformed;
                _DamageAction.Disable();
            }

            if (_HealAction != null) {
                _HealAction.performed -= _OnHealPerformed;
                _HealAction.Disable();
            }
        }
        #endregion

        #region 유니티 라이프 사이클 함수
        private void Awake() {
            _Initialize();
        }

        private void OnEnable() {
            _RegisterInput();
        }

        private void OnDisable() {
            _UnregisterInput();
        }
        #endregion

        #region 멤버 함수
        public void ApplyDamage(int amount) {
            Assert.IsNotNull(model, &quot;Model shouldn't be null&quot;);
            model.Damage(amount);
        }

        public void ApplyHeal(int amount) {
            Assert.IsNotNull(model, &quot;Model shouldn't be null&quot;);
            model.Heal(amount);
        }

        private void _OnDamagePerformed(InputAction.CallbackContext context) {
            if (!context.performed) return;
            ApplyDamage(damagePerHit);
        }

        private void _OnHealPerformed(InputAction.CallbackContext context) {
            if (!context.performed) return;
            ApplyHeal(healPerKey);
        }

        private void _OnHealthChanged(int current, int max) {
            Assert.IsNotNull(view, &quot;view shouldn't be null&quot;);
            view.UpdateHealth(current, max);
        }

        private void _OnDead() {
            HLogger.Log(&quot;[MvcHealthController] MvcHealthView Dead&quot;);
        }
        #endregion

        #region 디버깅 변수 / 함수
    #if UNITY_EDITOR
        [ContextMenu(&quot;Test Damage&quot;)]
        public void TestDamage() {
            ApplyDamage(damagePerHit);
        }

        [ContextMenu(&quot;Test Heal&quot;)]
        public void TestHeal() {
            ApplyHeal(healPerKey);
        }
    #endif
        #endregion
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;뷰&lt;/b&gt;&lt;/blockquote&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1764564652072&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#if UNITY_EDITOR
/*
 * View는 &amp;ldquo;데이터가 주어졌을 때 어떻게 그릴지만&amp;rdquo; 알고 있음.
 * Model/Controller 로직은 전혀 모름 &amp;rarr; 교체/디자인 변경이 쉬움.
 */
#endif

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using HUtil.Logger;

namespace SWU.Architech.MVC {
    public class MvcHealthView : MonoBehaviour {
        #region 유니티 IMGUI 멤버 변수
        [SerializeField]
        TMP_Text healthText;
        [SerializeField]
        Slider healthSlider;
        #endregion

        #region 프로퍼티
        public TMP_Text HealthText =&amp;gt; healthText;
        public Slider HealthSlider =&amp;gt; healthSlider;
        #endregion

        #region 생성자 / 초기화 함수
        public void Initialize(int current, int max) {
            _UpdateHealthUi(current, max);
        }
        #endregion

        #region 멤버 함수
        public void UpdateHealth(int current, int max) {
            _UpdateHealthUi(current, max);
        }

        private void _UpdateHealthUi(int current, int max) {
            if (healthText != null) healthText.text = $&quot;{current} / {max}&quot;;
            if (healthSlider != null) {
                healthSlider.maxValue = max;
                healthSlider.value = current;
            }
        }
        #endregion

        #region 디버깅 변수 / 함수
#if UNITY_EDITOR
        [ContextMenu(&quot;Log Current Health UI&quot;)]
        public void LogCurrentHealthUi() {
            HLogger.Log($&quot;[MvcHealthView] text={healthText?.text}, slider={healthSlider?.value}&quot;);
        }
#endif
        #endregion
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;모델&lt;/b&gt;&lt;/blockquote&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1764564666441&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;

namespace SWU.Architech.MVC {
    public class MvcHealthModel {
        #region 프로퍼티
        public int Current { get; private set; }
        public int Max { get; private set; }
        #endregion

        #region 이벤트 대리자
        public Action&amp;lt;int, int&amp;gt; OnHealthChanged;
        public Action OnDead;
        #endregion

        #region 생성자 / 초기화 함수
        public MvcHealthModel(int max) {
            if (max &amp;lt;= 0) max = 1;
            Max = max;
            Current = max;
        }
        #endregion

        #region 멤버 함수
        public void Damage(int amount) {
            if (amount &amp;lt;= 0) return;

            int next = Math.Max(0, Current - amount);
            if (next == Current) return;

            Current = next;
            OnHealthChanged?.Invoke(Current, Max);

            if (Current &amp;lt;= 0) OnDead?.Invoke();
        }

        public void Heal(int amount) {
            if (amount &amp;lt;= 0) return;

            int next = Math.Min(Max, Current + amount);
            if (next == Current) return;

            Current = next;
            OnHealthChanged?.Invoke(Current, Max);
        }
        #endregion
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Computer/Architecture Pattern</category>
      <category>C#</category>
      <category>MVC</category>
      <category>unity</category>
      <category>공부</category>
      <category>아키텍쳐</category>
      <category>유니티</category>
      <category>패턴</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/322</guid>
      <comments>https://liveforgame.tistory.com/entry/Unity-%EC%9C%A0%EB%8B%88%ED%8B%B0%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-MVC#entry322comment</comments>
      <pubDate>Mon, 1 Dec 2025 13:56:44 +0900</pubDate>
    </item>
    <item>
      <title>[Git] 서브모듈 적용법</title>
      <link>https://liveforgame.tistory.com/entry/Git-%EC%84%9C%EB%B8%8C%EB%AA%A8%EB%93%88-%EC%A0%81%EC%9A%A9%EB%B2%95</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity 프로젝트에 Git Submodule 기반 UPM 패키지를 적용하는 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity에서 공용 유틸 패키지나 엔진 확장 기능을 여러 프로젝트에서 공유하려면, 단순히 파일을 복사하는 방식으로는 버전 관리가 유지되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위한 방법이 &lt;b&gt;Git Submodule + Unity Local UPM 패키지 조합&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 다음과 같은 사례를 기반으로 진행한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상위 프로젝트 : TestProject
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하위 공용 레포 : HCUP-Unity&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레포에 포함된 3개의 UPM 패키지 : HGame, HUI, HUtil&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764324574151&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;TestProject/
└── Assets/
└── HCUP-Unity/
     └── HoHong123/
         ├── HGame/
         ├── HUI/
         └── HUtil/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 단계에 따라 진행하면, 여러&amp;nbsp;Unity&amp;nbsp;프로젝트에서&amp;nbsp;하나의&amp;nbsp;공용&amp;nbsp;패키지를&amp;nbsp;버전별로&amp;nbsp;안정적으로&amp;nbsp;관리하는&amp;nbsp;구조를&amp;nbsp;갖출&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Submodule로 공용 레포 추가하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 버전의 레포를 Submodule로 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서브모듈 호출&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764324416830&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git submodule add https://github.com/HoHong123/HCUP-Unity.git HCUP-Unity&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 후 버전을 고정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브랜치 변경 &amp;rarr; 버전 변경&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764324432330&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd HCUP-Unity
git fetch --tags
git checkout v0.2.1
cd ..&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 상위 레포에 커밋한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;푸시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764324495862&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git add .gitmodules HCUP-Unity
git commit -m &quot;Add HCUP-Unity as submodule at v0.2.1&quot;
git push&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Submodule 도입은 여기까지로 완료된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp;Unity가&amp;nbsp;실제&amp;nbsp;패키지를&amp;nbsp;읽을&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;연결하는&amp;nbsp;작업이&amp;nbsp;필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity에서 Submodule 패키지 인식시키기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Unity는 Assets/ 폴더만 컴파일하는 것이 아니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Packages/&amp;nbsp;아래에&amp;nbsp;위치한&amp;nbsp;UPM&amp;nbsp;패키지도&amp;nbsp;모두&amp;nbsp;자동&amp;nbsp;컴파일된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Unity가 &amp;ldquo;이 경로가 패키지다&amp;rdquo;라고 인식하기 위해서는 반드시&amp;nbsp;Packages/manifest.json에&amp;nbsp;선언을&amp;nbsp;해&amp;nbsp;주어야&amp;nbsp;한다.&lt;br /&gt;이번 사례에서는 Submodule 내부에 3개의 패키지가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1764324567730&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HCUP-Unity/
 └── HoHong123/
     ├── HGame/
     │   └── package.json
     ├── HUI/
     │   └── package.json
     └── HUtil/
         └── package.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 패키지 루트에는 package.json이 존재하며, 그&amp;nbsp;&quot;name&quot;&amp;nbsp;필드가&amp;nbsp;패키지의&amp;nbsp;ID&amp;nbsp;역할을&amp;nbsp;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시(HUtil):&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764324664029&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;com.hohong123.hutil&quot;,
  &quot;displayName&quot;: &quot;Hohong123 HUtil&quot;,
  &quot;version&quot;: &quot;0.2.1&quot;,
  &quot;unity&quot;: &quot;2021.3&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;manifest.json에 패키지 경로 등록&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트/Packages/manifest.json&lt;/b&gt;을 열고 dependencies에 다음을 &lt;b&gt;추가&lt;/b&gt;한다:&lt;/p&gt;
&lt;pre id=&quot;code_1764324736117&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;com.hohong123.hgame&quot;: &quot;file:../HCUP-Unity/HoHong123/HGame&quot;,
&quot;com.hohong123.hui&quot;:   &quot;file:../HCUP-Unity/HoHong123/HUI&quot;,
&quot;com.hohong123.hutil&quot;: &quot;file:../HCUP-Unity/HoHong123/HUtil&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  중요:&lt;/b&gt;&lt;br /&gt;manifest.json의 key는 package.json의 &quot;name&quot;과 반드시 완전히 일치해야 한다.&lt;br /&gt;하나라도&amp;nbsp;다르면&amp;nbsp;Unity는&amp;nbsp;패키지를&amp;nbsp;불러올&amp;nbsp;수&amp;nbsp;없다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 로딩이 안 되면 대부분은&amp;nbsp;다음&amp;nbsp;중&amp;nbsp;하나이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;manifest.json 저장 안 함&lt;/li&gt;
&lt;li&gt;쉼표(,) 누락 또는 문법 에러&lt;/li&gt;
&lt;li&gt;&quot;name&quot; 불일치&lt;/li&gt;
&lt;li&gt;경로&amp;nbsp;오타&amp;nbsp;(HoHong123&amp;nbsp;/&amp;nbsp;hutil&amp;nbsp;등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Unity에서 패키지 로딩 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity를 다시 열거나 Package Manager를 열고&amp;nbsp;다음&amp;nbsp;위치에서&amp;nbsp;확인한다:&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Window &amp;rarr; Package Manager &amp;rarr; Packages: In Project&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hohong123 HGame&lt;/li&gt;
&lt;li&gt;Hohong123 HUI&lt;/li&gt;
&lt;li&gt;Hohong123 HUtil&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모두 뜨면 정상적으로 패키지가 인식된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJwj3t/dJMcacO5yyi/Lo3jPuKhDbZdPh3cm4MtaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJwj3t/dJMcacO5yyi/Lo3jPuKhDbZdPh3cm4MtaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJwj3t/dJMcacO5yyi/Lo3jPuKhDbZdPh3cm4MtaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJwj3t%2FdJMcacO5yyi%2FLo3jPuKhDbZdPh3cm4MtaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;361&quot; height=&quot;393&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;패키지가 뜨는 순간, 내부 C#은 자동으로 컴파일되고 네임스페이스로 조할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(단, Editor 전용 asmdef &amp;rarr; Runtime 참조 불가 같은 Unity 규칙은 그대로 적용된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;현재 방식의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 버전 고정이 가능하다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브모듈은 특정 태그 또는 커밋에 고정할 수 있으므로 &amp;ldquo;패키지가&amp;nbsp;갑자기&amp;nbsp;깨지는&amp;rdquo;&amp;nbsp;상황을&amp;nbsp;방지할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 여러 프로젝트에서 동일 버전을 안정적으로 공유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 A, B, C가 모두 v0.2.1 같은 동일 버전을 사용 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 디렉토리 복사 없이 즉시 패키지 업데이트 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 레포에 새로운 버전을 생성하면:&lt;/p&gt;
&lt;pre id=&quot;code_1764325188795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd HCUP-Unity
git fetch
git checkout v0.2.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게만 하면 상위 프로젝트의 패키지가 자동으로 업데이트된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) Unity의 UPM 시스템을 그대로 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 구조, asmdef 분리, Editor/Runtime 구성, 의존성 관리 등 Unity 표준 방식으로 유지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Submodule 제거하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Submodule을 잘못 추가하거나 충돌이 발생하면 .gitmodules, .git/modules/, 워킹트리 등 여러 곳에 잔여물이 남는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령으로 기존 흔적을 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1764324350055&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git rm -r HCUP-Unity          # 기존 폴더 제거
rm -rf .git/modules/HCUP-Unity&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&amp;nbsp;.gitmodules&amp;nbsp;파일을&amp;nbsp;열어&amp;nbsp;HCUP-Unity&amp;nbsp;관련&amp;nbsp;섹션이&amp;nbsp;있다면&amp;nbsp;삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;단계까지&amp;nbsp;마치면&amp;nbsp;상위&amp;nbsp;레포는&amp;nbsp;HCUP-Unity에&amp;nbsp;대한&amp;nbsp;어떠한&amp;nbsp;참조도&amp;nbsp;없는&amp;nbsp;&amp;ldquo;깨끗한&amp;nbsp;상태&amp;rdquo;가&amp;nbsp;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Submodule 공유하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀작업을 한다면 서브모듈을 업데이트하는 것으로 끝나지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃레포에 서브모듈을 올려놓아도 이를 다른사람이 클론(Clone)하거나 풀(Pull)하면 &lt;b&gt;서브모듈을 가져오는 것이 아닌&lt;/b&gt;,&amp;nbsp; 해당 모듈을 &lt;b&gt;다운받을 수 있는 링크가 .gitmodules에 등록되어 있는 상태&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 프로젝트를 받은 사람이 서브모듈을 사용하기 위해서는 다음 과정이 추가적으로 필요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1764556347235&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 처음 받는 경우(Clone) 1
git clone --recurse-submodules &amp;lt;repo-url&amp;gt;

# 처음 받는 경우(Clone) 2
git clone &amp;lt;repo-url&amp;gt;
git submodule update --init --recursive

# 업데이트 받을 때(Pull)
git pull
git submodule update --init --recursive&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer/Git</category>
      <category>git</category>
      <category>github</category>
      <category>module</category>
      <category>submodule</category>
      <category>unity</category>
      <category>깃</category>
      <category>서브모듈</category>
      <category>유니티</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/321</guid>
      <comments>https://liveforgame.tistory.com/entry/Git-%EC%84%9C%EB%B8%8C%EB%AA%A8%EB%93%88-%EC%A0%81%EC%9A%A9%EB%B2%95#entry321comment</comments>
      <pubDate>Fri, 28 Nov 2025 19:20:18 +0900</pubDate>
    </item>
    <item>
      <title>[Unity] 토스앱 빌드 (WebGL)</title>
      <link>https://liveforgame.tistory.com/entry/Unity-%ED%86%A0%EC%8A%A4%EC%95%B1-%EB%B9%8C%EB%93%9C-WebGL</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;토스앱 빌드 과정 정리&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 토스 미니앱(Toss MiniApp)에 Unity WebGL 게임을 올리기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스 미니앱(Toss MiniApp) 환경에 Unity WebGL 게임을 올리고, 모바일 환경에서 부드럽게 동작하도록 만드는 과정은 단순한 웹 배포보다 훨씬 까다롭다.&amp;nbsp; 토스는 브라우저가 아닌 &lt;b&gt;WebView + React Native 기반의 독립 실행 환경&lt;/b&gt;을 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;917&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vm4lA/dJMcahCMVhO/YKT5kjkvcmhT1Gk69Gqnf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vm4lA/dJMcahCMVhO/YKT5kjkvcmhT1Gk69Gqnf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vm4lA/dJMcahCMVhO/YKT5kjkvcmhT1Gk69Gqnf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvm4lA%2FdJMcahCMVhO%2FYKT5kjkvcmhT1Gk69Gqnf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;917&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;917&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1179&quot; data-start=&quot;1127&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Unity&amp;nbsp;게임을&amp;nbsp;바로&amp;nbsp;WebGL로&amp;nbsp;빌드하면&amp;nbsp;토스&amp;nbsp;앱에&amp;nbsp;그대로&amp;nbsp;넣을&amp;nbsp;수&amp;nbsp;없다.&amp;nbsp;필요한&amp;nbsp;작업은&amp;nbsp;다음과&amp;nbsp;같다.&lt;/p&gt;
&lt;p data-end=&quot;1272&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;프로젝트 빌드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;1. Unity&amp;nbsp;빌드&amp;nbsp;설정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-end=&quot;580&quot; data-start=&quot;537&quot; data-ke-style=&quot;style2&quot;&gt;Unity &amp;rarr; Project Settings &amp;rarr; Player &amp;rarr; WebGL&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz9g3t/dJMcain9Fcn/YS4p4MGpX5M93CcrL0bLmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz9g3t/dJMcain9Fcn/YS4p4MGpX5M93CcrL0bLmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz9g3t/dJMcain9Fcn/YS4p4MGpX5M93CcrL0bLmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz9g3t%2FdJMcain9Fcn%2FYS4p4MGpX5M93CcrL0bLmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;518&quot; height=&quot;508&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;프로젝트 세팅에 따라 WebGL 빌드 패키지를 다운받아야할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;2. WebGL 빌드에서 설정값을 변경해야한다.&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt;&amp;nbsp;&lt;b&gt;Publishing Settings&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1480&quot; data-start=&quot;1311&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Compression Format :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Disabled&lt;/b&gt;&lt;/span&gt;로 설정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://liveforgame.tistory.com/entry/Unity-WebGL-%EB%B9%8C%EB%93%9C&quot;&gt;(관련 포스트)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;토스 WebView는 Brotli/Gzip 압축을 잘 지원하지 않음.&lt;br /&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;49&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/luc9c/dJMcafycMQT/AtRGF5Y5rSylGIEFLsywxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/luc9c/dJMcafycMQT/AtRGF5Y5rSylGIEFLsywxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/luc9c/dJMcafycMQT/AtRGF5Y5rSylGIEFLsywxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fluc9c%2FdJMcafycMQT%2FAtRGF5Y5rSylGIEFLsywxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;49&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;49&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1448&quot; data-start=&quot;1413&quot;&gt;&lt;b&gt;WebGL Memory Size 넉넉하게 설정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. 빌드하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;File &amp;gt; Build Settings &amp;gt; &lt;b&gt;Build&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 파일을 확인하여 빌드파일 내부 버전 확인 및 압축 확장자 확인.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;필요에 따라 WebGLTemplate을 통해 개발자가 커스텀 빌드 세팅을 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;4. React 프로젝트 생성&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) VS Code로 신규 프로젝트 파일을 생성한다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜토리얼에는 스캐폴딩과 다양한 플러그인을 활용한 프로젝트 세팅부터 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요에 따라 바로 프로젝트를 만들수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인이 사용하는 패키지 매니저를 활용하여 프로젝트를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;프로젝트 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1763295880100&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# npm
npm create vite unity-webgl-wrapper --template react-ts
# yarn
yarn create vite unity-webgl-wrapper --template react-ts&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 패키지 매니저에 따라서 첫 생성시 선택하는 옵션의 수가 다를 수 있다. 별로 크게 중요한건 없다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;npm을 통한 생성&lt;/b&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vhvj5/dJMcaf52NGc/NcufMTGxp239OSN1kQbK81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vhvj5/dJMcaf52NGc/NcufMTGxp239OSN1kQbK81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vhvj5/dJMcaf52NGc/NcufMTGxp239OSN1kQbK81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVhvj5%2FdJMcaf52NGc%2FNcufMTGxp239OSN1kQbK81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;679&quot; height=&quot;534&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;yarn을 통한 생성&lt;/b&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img (1).png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K9mf6/dJMcahv1nCM/qLBbxiyoBXI2QsetAYv920/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K9mf6/dJMcahv1nCM/qLBbxiyoBXI2QsetAYv920/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K9mf6/dJMcahv1nCM/qLBbxiyoBXI2QsetAYv920/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK9mf6%2FdJMcahv1nCM%2FqLBbxiyoBXI2QsetAYv920%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;393&quot; data-filename=&quot;img (1).png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정을 통해 프로젝트 생성이 완료된다면 기본 리액트 프로젝트가 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deg7F2/dJMcabWSnCg/VgZzkuOPhkALAdmk3OSlZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deg7F2/dJMcabWSnCg/VgZzkuOPhkALAdmk3OSlZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deg7F2/dJMcabWSnCg/VgZzkuOPhkALAdmk3OSlZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdeg7F2%2FdJMcabWSnCg%2FVgZzkuOPhkALAdmk3OSlZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;292&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 프로젝트 디렉토리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성한 프로젝트 디렉토리로 이동하여 토스앱 관련 패키지를 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1763296421714&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd 프로젝트파일&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;패키지 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1763296029606&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# npm
npm install @apps-in-toss/framework
# yarn
yarn add @apps-in-toss/framework&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* VC 세팅에 따라 추가적인 플러그인 설치가 필요할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) WebGL 빌드파일 전달&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티에서 빌드한 WebGL 빌드파일 내부의 모든 값을 'root &amp;gt; public &amp;gt; unity' 디렉토리를 생성하여 넣는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHcWO/dJMcahbJ8JK/jQqADqIsxy6B0swkU24hkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHcWO/dJMcahbJ8JK/jQqADqIsxy6B0swkU24hkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHcWO/dJMcahbJ8JK/jQqADqIsxy6B0swkU24hkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHcWO%2FdJMcahbJ8JK%2FjQqADqIsxy6B0swkU24hkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;195&quot; height=&quot;173&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;5. Build - 번들 파일 생성하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번들 파일은 .ait 확장자를 가진 파일을 의미하며 빌드된 프로젝트를 패키징한 결과물이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드는 다음 명령어를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763448595240&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# npm
npm run build
# yarn
yarn build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;빌드 가이드&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스앱 게임 업로드에는 몇가지 규칙이 존재한다.&lt;/p&gt;
&lt;figure id=&quot;og_1763449768260&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;앱인토스 개발자센터&quot; data-og-description=&quot;&quot; data-og-host=&quot;developers-apps-in-toss.toss.im&quot; data-og-source-url=&quot;https://developers-apps-in-toss.toss.im/checklist/app-game.html&quot; data-og-url=&quot;https://developers-apps-in-toss.toss.im/checklist/app-game.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AXRTc/hyZNHlxVpH/O05kYVDcAtsEX7gKvwKl10/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170&quot;&gt;&lt;a href=&quot;https://developers-apps-in-toss.toss.im/checklist/app-game.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers-apps-in-toss.toss.im/checklist/app-game.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AXRTc/hyZNHlxVpH/O05kYVDcAtsEX7gKvwKl10/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;앱인토스 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers-apps-in-toss.toss.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;게임 미니앱은 &lt;b&gt;다크모드(Inverted) 설정&lt;/b&gt;을 권장
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;말이 권장이지 다크모드가 아니면 출시 검토에서 걸린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;앱 진입에 이름, 로고, 대표 색상 정상 동작 유무&lt;/li&gt;
&lt;li&gt;토스 로그인 사용시, 즉시 로그인 유도 불가&lt;/li&gt;
&lt;li&gt;과도한 로딩시간 불가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연령 등급 표기&lt;/b&gt; 필수
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;타 플렛폼에서 프로토타입 검수 후 받은 연령 등급 표기를 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;게임센터 적용시 정상 동작 확인 필수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;게임의 각종 사운드가 앱이 비활성화된 상태에서는 플레이되지 않도록 설정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내비게이션바 사용 필수&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략적으로 중요한 것들은 위와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;사용 파일&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정사항이 존재하는 파일들 위주로 작성.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;App.css&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763453480745&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}

.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
  filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: no-preference) {
  a:nth-of-type(2) .logo {
    animation: logo-spin infinite 20s linear;
  }
}

.card {
  padding: 2em;
}

.read-the-docs {
  color: #888;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;App.tsx&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763453491690&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import './App.css'
import UnityCanvas from './UnityCanvas.tsx';
import { useEffect } from 'react';

declare global {
  interface Window {
    unityInstance?: any;
  }
}

function App() {
  useEffect(() =&amp;gt; {
    const handler = () =&amp;gt; {
      if (!window.unityInstance) return;
      const isVisible = !document.hidden;
      window.unityInstance.SendMessage(
        '[BM] WebReceiver',
        'ReceiveString',
        isVisible.toString(), // &quot;true&quot; / &quot;false&quot;
      );
    };

    // 리스너 등록
    document.addEventListener('visibilitychange', handler);
    // 필요하다면 최초 상태도 한 번 Unity에 알려주고 싶으면
    handler();
    // 언마운트 시 정리
    return () =&amp;gt; { document.removeEventListener('visibilitychange', handler);};
  }, []);

  return (
    &amp;lt;div style={{
      position: 'fixed',
      inset: 0,
      display: 'grid',
      placeItems: 'center',
      background: '#000'
    }}&amp;gt;
      &amp;lt;div style={{
        width: 'min(100vw, calc(100vh * 9 / 16))',
        height: 'min(100vh, calc(100vw * 16 / 9))',
        aspectRatio: '9 / 16'
      }}&amp;gt;
        &amp;lt;UnityCanvas/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;index.css&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763453503026&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;:root {
  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  font-weight: 500;
  color: #646cff;
  text-decoration: inherit;
}
a:hover {
  color: #535bf2;
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
}

h1 {
  font-size: 3.2em;
  line-height: 1.1;
}

button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}
button:hover {
  border-color: #646cff;
}
button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UnityCanvas.tsx&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763453611506&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useEffect } from 'react';

declare global {
  interface Window {
    createUnityInstance: (
      canvas: HTMLCanvasElement,
      config: Record&amp;lt;string, unknown&amp;gt;
    ) =&amp;gt; Promise&amp;lt;unknown&amp;gt;;
  }
}

const UnityCanvas = () =&amp;gt; {
  useEffect(() =&amp;gt; {
    const script = document.createElement('script');
    script.src = '/unity/Build/{{{BUILD_LOADER}}}.loader.js';

    script.onload = () =&amp;gt; {
      const canvas = document.createElement('canvas');
      canvas.id = 'unity-canvas';
      canvas.style.width = '100%';
      canvas.style.height = '100%';

      const container = document.getElementById('unity-container');
      if (!container) return;
      container.appendChild(canvas);

      window.createUnityInstance(canvas, {
          dataUrl: '/unity/Build/{{{BUILD_DATA}}}.data',
          frameworkUrl: '/unity/Build/{{{BUILD_FRAMEWORK}}}.framework.js',
          codeUrl: '/unity/Build/{{{BUILD_CODE}}}.wasm',
          streamingAssetsUrl: '/unity/StreamingAssets',
          companyName: 'Company',
          productName: 'Game Name',
          productVersion: '0.1',
        })
        .then((instance: any) =&amp;gt; {
          window.unityInstance = instance;
        })
        .catch((err: any) =&amp;gt; {
          console.error('Unity 인스턴스 생성 실패:', err);
        });
    };

    document.body.appendChild(script);

    return () =&amp;gt; {
      document.removeEventListener('visibilitychange', () =&amp;gt; {});
      document.body.removeChild(script);
    };
  }, []);

  return (
    &amp;lt;div
      id=&quot;unity-container&quot;
      style={{ width: '100vw', height: '100vh', background: '#000' }}
    &amp;gt;&amp;lt;/div&amp;gt;
  );
};

export default UnityCanvas;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;tsconfig.app.json&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763453641995&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;include&quot;: [&quot;src/**/*.tsx&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;백그라운드 사운드 이슈&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스앱을 모바일에서 숨김으로 설정할때, WebGL이 백그라운드에서 계속 실행되어 BGM이 앱을 닫은 상태에서도 지속 플레이되는 이슈가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;앱실행&lt;/li&gt;
&lt;li&gt;무한반복 배경음 실행&lt;/li&gt;
&lt;li&gt;앱 숨김&lt;/li&gt;
&lt;li&gt;배경음 지속 재생&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스앱 자체가 웹뷰에 WebGL을 올린 것이기에 JS를 통한 통신으로 처리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 리액트 프로젝트에서 &lt;b&gt;앱의 가시성(Visibility)가 변화할때마다&lt;/b&gt; UnityCanvas.tsx에 설정된 &lt;b&gt;unityInstance 내부에 &lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;lt;특정 게임오브젝트 + 해당 오브젝트가 가진 스크립트 컴포넌트의 public 함수 + 보낼 문자열&amp;gt;&lt;/span&gt; 형태로 전달&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;유니티 웹메시지 리시버 설정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;우선 다음은 예시 코드들이기에 JS 통신규약이라는 정의 자체가 없다.&lt;br /&gt;실사용시 이에 대한 추가적인 규칙을 정하고 &lt;b&gt;JS통신은 최소화&lt;/b&gt;하는 방향으로 개발하는 것이 옳다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선 언제든 웹의 메시지를 받을 수 있는 싱글톤 매니저를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763455568703&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;namespace Util.Web {
    public class WebExternalReceiverManager : SingletonBehaviour&amp;lt;WebExternalReceiverManager&amp;gt; {
        [UnityEngine.SerializeField]
        BaseExternalReceiver[] receivers;

        public event System.Action OnReceiveMessage;
        public event System.Action&amp;lt;string&amp;gt; OnReceiveString;

        public void ReceiveMessage() =&amp;gt; OnReceiveMessage?.Invoke();
        public void ReceiveString(string message) =&amp;gt; OnReceiveString?.Invoke(message);


        private void Start() {
            foreach (var reciver in receivers) {
                Register(reciver);
            }
        }

        private void OnDestroy() {
            foreach (var reciver in receivers) {
                Unregister(reciver);
            }
        }


        public void Register(IWebReceiver receiver) {
            Unregister(receiver);
            OnReceiveMessage += receiver.ReceiveMessage;
            OnReceiveString += receiver.ReceiveString;
        }

        public void Unregister(IWebReceiver receiver) {
            OnReceiveMessage -= receiver.ReceiveMessage;
            OnReceiveString -= receiver.ReceiveString;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매니저에서 메시지를 수신 받으면 각자의 기능을 동작하는 에이전트 클래스 생성
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;확장성을 위한 인터페이스&lt;/li&gt;
&lt;li&gt;공통 함수를 모은 부모클래스&lt;/li&gt;
&lt;li&gt;이벤트가 활성화되면 각자 할일을 하는 파생클래스들...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763455611652&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;
using Util.Sound;
using Util.Web;

namespace Util.Web {
    public interface IWebReceiver {
        void ReceiveMessage();
        void ReceiveString(string message);
    }
}

namespace Util.Web {
    public class BaseExternalReceiver : MonoBehaviour, IWebReceiver {
        public virtual void ReceiveMessage() {}
        public virtual void ReceiveString(string message) {}
    }
}

namespace MA.Web {
    public class WebVisibilityReceiver : BaseExternalReceiver {
        private void Start() =&amp;gt; WebExternalReceiverManager.Instance.Register(this);
        private void OnDestroy() =&amp;gt; WebExternalReceiverManager.Instance.Unregister(this);

        #region BGM Control
        public override void ReceiveString(string boolean) {
            if (!bool.TryParse(boolean, out bool isVisible)) return;
            var sound = SoundManager.Instance;
            if (isVisible) {
                sound.ResumeBGM();
            }
            else {
                sound.PauseBGM();
            }
        }
        #endregion
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 적용하면 유니티 IMGUI, 에디터, 코드 등 다양한 방식으로 웹메시지 핸들링이 가능하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;RN&amp;nbsp;설정&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 유니티 WebGL에 메시지를 전달하는 이벤트를 등록해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위하여, App.tsx에서 useEffect를 사용하여 핸들러를 생성하고 이를 현재 앱에 리스너로 등록하는 방식을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;App.tsx&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1763456097377&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import './App.css'
import UnityCanvas from './UnityCanvas.tsx';
import { useEffect } from 'react';

declare global {
  interface Window {
    unityInstance?: any;
  }
}

function App() {
  useEffect(() =&amp;gt; {
    const handler = () =&amp;gt; {
      if (!window.unityInstance) return;
      const isVisible = !document.hidden;
      window.unityInstance.SendMessage(
        '[BM] WebReceiver',
        'ReceiveString',
        isVisible.toString(), // &quot;true&quot; / &quot;false&quot;
      );
    };

    // 리스너 등록
    document.addEventListener('visibilitychange', handler);
    // 필요하다면 최초 상태도 한 번 Unity에 알려주고 싶으면
    handler();
    // 언마운트 시 정리
    return () =&amp;gt; { document.removeEventListener('visibilitychange', handler);};
  }, []);

  return (
    &amp;lt;div style={{
      position: 'fixed',
      inset: 0,
      display: 'grid',
      placeItems: 'center',
      background: '#000'
    }}&amp;gt;
      &amp;lt;div style={{
        width: 'min(100vw, calc(100vh * 9 / 16))',
        height: 'min(100vh, calc(100vw * 16 / 9))',
        aspectRatio: '9 / 16'
      }}&amp;gt;
        &amp;lt;UnityCanvas/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;사운드 컨트롤&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 이슈에서 시도해본 해결방안들은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;오디오소스들 볼륨 최소화&lt;/li&gt;
&lt;li&gt;오디오소스들 데시벨 최소화&lt;/li&gt;
&lt;li&gt;오디오소스들 Pause/Unpause&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 볼륨 및 데시벨과 같은 각 컴포넌트의 변수값 설정 변경은 Visibility 변경으로 설정이 변경되지 않는 이슈가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 오디오소스 자체를 Pause/Unpause하는 부분은 정상동작하는 것으로 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, SendMessage는 문자열 값만 전달이 가능한 것으로 isVisible이 boolean이라도 string으로 파싱하여 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;참조&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1763294657737&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;앱인토스 개발자센터&quot; data-og-description=&quot;&quot; data-og-host=&quot;developers-apps-in-toss.toss.im&quot; data-og-source-url=&quot;https://developers-apps-in-toss.toss.im/tutorials/webview.html&quot; data-og-url=&quot;https://developers-apps-in-toss.toss.im/tutorials/webview.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bZJFUU/hyZN06MuMH/bkm4kCZlbnBZE8Z63gmH7K/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170&quot;&gt;&lt;a href=&quot;https://developers-apps-in-toss.toss.im/tutorials/webview.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers-apps-in-toss.toss.im/tutorials/webview.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bZJFUU/hyZN06MuMH/bkm4kCZlbnBZE8Z63gmH7K/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;앱인토스 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers-apps-in-toss.toss.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1763250317212&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;앱인토스 개발자센터&quot; data-og-description=&quot;&quot; data-og-host=&quot;developers-apps-in-toss.toss.im&quot; data-og-source-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/unity.html&quot; data-og-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/unity.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/x0YaN/hyZN0emclv/Rxl5mMLi9gR2h9PskHBivk/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170&quot;&gt;&lt;a href=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/unity.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/unity.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/x0YaN/hyZN0emclv/Rxl5mMLi9gR2h9PskHBivk/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;앱인토스 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers-apps-in-toss.toss.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1763449297294&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;앱인토스 개발자센터&quot; data-og-description=&quot;&quot; data-og-host=&quot;developers-apps-in-toss.toss.im&quot; data-og-source-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/vite_unity.html&quot; data-og-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/vite_unity.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VvpWy/hyZNOMHspD/kSiGfuA2cHgCmnejWZs4Vk/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170&quot;&gt;&lt;a href=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/vite_unity.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers-apps-in-toss.toss.im/porting_tutorials/vite_unity.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VvpWy/hyZNOMHspD/kSiGfuA2cHgCmnejWZs4Vk/img.png?width=2340&amp;amp;height=1170&amp;amp;face=0_0_2340_1170');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;앱인토스 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers-apps-in-toss.toss.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Unity</category>
      <category>unity</category>
      <category>VS</category>
      <category>vscode</category>
      <category>WebGL</category>
      <category>빌드</category>
      <category>유니티</category>
      <category>토스앱</category>
      <author>HONGGG</author>
      <guid isPermaLink="true">https://liveforgame.tistory.com/320</guid>
      <comments>https://liveforgame.tistory.com/entry/Unity-%ED%86%A0%EC%8A%A4%EC%95%B1-%EB%B9%8C%EB%93%9C-WebGL#entry320comment</comments>
      <pubDate>Tue, 18 Nov 2025 18:02:56 +0900</pubDate>
    </item>
  </channel>
</rss>