<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>안녕하세요, 손사장(sonsazang)입니다!</title>
    <link>https://sonsazang.tistory.com/</link>
    <description>손사장(sonsazang)
개발 블로그</description>
    <language>ko</language>
    <pubDate>Thu, 6 Aug 2026 05:51:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>sonsazang</managingEditor>
    <image>
      <title>안녕하세요, 손사장(sonsazang)입니다!</title>
      <url>https://tistory1.daumcdn.net/tistory/4800264/attach/cde02d5726ae4e9da4cf5edf824166c5</url>
      <link>https://sonsazang.tistory.com</link>
    </image>
    <item>
      <title>Windows 창 투명도 조절기</title>
      <link>https://sonsazang.tistory.com/144</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b54VOR/dJMcabpfG1F/JyKCWcJrDFrz21vsfeDOOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b54VOR/dJMcabpfG1F/JyKCWcJrDFrz21vsfeDOOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b54VOR/dJMcabpfG1F/JyKCWcJrDFrz21vsfeDOOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb54VOR%2FdJMcabpfG1F%2FJyKCWcJrDFrz21vsfeDOOk%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;452&quot; height=&quot;632&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;632&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;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&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;오랜만에 하나 있으면 좋겠다 생각이 들어서 만들어보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows에서 원하는 창의 투명도를 0~100%로 조절할 수 있는 무료 툴입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 EXE 파일만 실행하면 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;/li&gt;
&lt;li&gt;클릭으로 창 선택: 버튼 클릭 후 원하는 창을 클릭해 선택&lt;/li&gt;
&lt;li&gt;투명도 슬라이더: 0~100% 조절 (0=완전 투명, 100=불투명)&lt;/li&gt;
&lt;li&gt;초기화 버튼: 한 번에 100%로 복구 (텍스트/슬라이더/실제 투명도 동시 초기화)&lt;/li&gt;
&lt;li&gt;블로그 배너: 하단 배너에서 개발자 블로그로 이동&lt;/li&gt;
&lt;li&gt;Notion 스타일 UI: 밝은 톤, 통일된 블루 포인트 컬러&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;실행&lt;/b&gt;: &lt;code&gt;창투명도조절기.exe&lt;/code&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;&amp;ldquo;창 선택하기&amp;rdquo; 버튼 클릭&lt;/li&gt;
&lt;li&gt;원하는 창 위로 마우스 이동 &amp;rarr; 녹색 테두리 확인&lt;/li&gt;
&lt;li&gt;그 창을 클릭하면 선택됨 (ESC로 취소 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;투명도 조절&lt;/b&gt;: 슬라이더로 0~100% 조절&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기화&lt;/b&gt;: &amp;ldquo;투명도 초기화&amp;rdquo; 버튼으로 즉시 100% 복귀&lt;/li&gt;
&lt;li&gt;&lt;b&gt;창 정보 새로고침&lt;/b&gt;: 선택된 창의 제목 갱신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;블로그 방문&lt;/b&gt;: 하단 배너의 &amp;ldquo;손사장 블로그 방문하기&amp;rdquo; 버튼 클릭&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 요구사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Windows 7 이상&lt;/li&gt;
&lt;li&gt;추가 설치 불필요 (단일 EXE 실행)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다운로드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배포용 EXE만 업로드 예정&lt;/li&gt;
&lt;li&gt;링크: &lt;a href=&quot;https://drive.google.com/file/d/1NeUhsBS3K-4AxmB9Vo8qm2Hz_h2bIuc7/view?usp=sharing&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://drive.google.com/file/d/1NeUhsBS3K-4AxmB9Vo8qm2Hz_h2bIuc7/view?usp=sharing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;/li&gt;
&lt;li&gt;서명되지 않은 EXE이므로 최초 실행 시 Windows Defender 경고가 뜰 수 있습니다.&lt;/li&gt;
&lt;li&gt;프로그램 종료 후에도 마지막 투명도 값은 적용된 창에 남아 있을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FAQ&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;창이 바로 선택돼요&lt;/b&gt;: 버튼 클릭 후 원하는 창을 새로 클릭해야 선택됩니다. (버튼 클릭 위치는 무시하도록 개선됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하이라이트가 안 보일 때&lt;/b&gt;: 다른 오버레이 프로그램이 있다면 잠시 종료 후 시도해 주세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제작 정보&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Python, Windows API (pywin32), CustomTkinter 기반&lt;/li&gt;
&lt;li&gt;UI 테마: Notion 스타일 (라이트 모드, 블루 포인트 컬러)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;면책 조항&lt;/b&gt;: 본 프로그램은 개인 사용 목적의 무료 소프트웨어이며, 사용 중 발생하는 문제에 대한 책임을 지지 않습니다.&lt;/p&gt;</description>
      <category>끄적끄적</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/144</guid>
      <comments>https://sonsazang.tistory.com/144#entry144comment</comments>
      <pubDate>Tue, 23 Dec 2025 19:25:34 +0900</pubDate>
    </item>
    <item>
      <title>[Unity 6.1 WEB] Uncaught TypeError: Module.dynCall_viiiii is not a function 에러 해결하기</title>
      <link>https://sonsazang.tistory.com/143</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&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;Unity 6.1 (6000.1.9 f1) 버전에서는 WebGL 할당 메모리가 증가되었다는 이야기를 듣고 빌드를 시도했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드는 정상적으로 되었지만 WebRequest를 호출하는 부분에서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751346541621&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Invoking error handler due to
TypeError: Module.dynCall_viiiii is not a function
at XMLHttpRequest.http_onload (http://localhost:8000/Build/NEW.framework.js:9497:31)
NEW.framework.js:9497 Uncaught TypeError: Module.dynCall_viiiii is not a function
    at XMLHttpRequest.http_onload (NEW.framework.js:9497:31)&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;/p&gt;
&lt;pre id=&quot;code_1751346708030&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function _XHR_SetResponseHandler(request, onresponse, onerror, ontimeout, onaborted)
  	{
  		if (_best_http_request_bridge_global.loglevel &amp;lt;= 1) /*information*/
  			console.log(request + ' XHR_SetResponseHandler');
  
  		var http = _best_http_request_bridge_global.requestInstances[request];
  		// LOAD
  		http.onload = function http_onload(e) {
  			if (_best_http_request_bridge_global.loglevel &amp;lt;= 1) /*information*/
  				console.log(request + '  - onload ' + http.status + ' ' + http.statusText);
  
  			if (onresponse)
  			{
  				var responseLength = 0;
  				if (!!http.response)
  					responseLength = http.response.byteLength;
  	
    			// 여기서 발생
  				Module['dynCall_viiiii'](onresponse, request, http.status, 0, responseLength, 0);
  			}
  		};
  
  		if (onerror)
  		{
  			http.onerror = function http_onerror(e) {
  				function HandleError(err)
  				{
  					var length = lengthBytesUTF8(err) + 1;
  					var buffer = _malloc(length);
  
  					stringToUTF8Array(err, HEAPU8, buffer, length);
  
  					// 여기도 발생
  					Module['dynCall_vii'](onerror, request, buffer);
  
  					_free(buffer);
  				}
  
  				if (e.error)
  					HandleError(e.error);
  				else
  					HandleError(&quot;Unknown Error! Maybe a CORS porblem?&quot;);
  			};
  		}
  
  		if (ontimeout)
  			http.ontimeout = function http_onerror(e) {
            	// 여기도 발생
  				Module['dynCall_vi'](ontimeout, request);
  			};
  
  		if (onaborted)
  			http.onabort = function http_onerror(e) {
            	// 여기도 발생
  				Module['dynCall_vi'](onaborted, request);
  			};
  	}&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통적인 에러 발생 부분을 확인해 본 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dynCall 메서드를 실행하지 못하는 에러가 발생한 것으로 확인되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티 에디터 버전의 업데이트에 따라서 패키지의 업데이트 누락인지 아니면 에디터 버그인지&amp;nbsp;&lt;br /&gt;해당 dynCall 메서드를 불러오지를 못해서 발생하게 된 에러입니다.&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;h3 data-ke-size=&quot;size23&quot;&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;&lt;a href=&quot;https://discussions.unity.com/t/makedyncall-replacing-dyncall-in-unity-6/1543088/28&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://discussions.unity.com/t/makedyncall-replacing-dyncall-in-unity-6/1543088/28&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/hecomi/uLipSync/issues/93&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/hecomi/uLipSync/issues/93&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1751346845296&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;[WebGL][WebAssembly] Enable WebAssembly.Table in Unity 6000.0.xx occur Uncaught TypeError: Module.dynCall_v when click web page &quot; data-og-description=&quot;Module.dynCall_v(uLipSync.unityCsharpCallback); Occur Error:Uncaught TypeError: Module.dynCall_v is not a function. This error disapper when disable WebAssembly.Table option.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hecomi/uLipSync/issues/93&quot; data-og-url=&quot;https://github.com/hecomi/uLipSync/issues/93&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b0w7Ov/hyZf2cpPN1/8zVChKTPB3Lp5RJ2NfD6fK/img.png?width=1200&amp;amp;height=600&amp;amp;face=980_127_1073_228,https://scrap.kakaocdn.net/dn/IuKEV/hyZf60cOQn/KjoEVxkDgeSWH384cWY3S0/img.png?width=1200&amp;amp;height=600&amp;amp;face=980_127_1073_228&quot;&gt;&lt;a href=&quot;https://github.com/hecomi/uLipSync/issues/93&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hecomi/uLipSync/issues/93&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b0w7Ov/hyZf2cpPN1/8zVChKTPB3Lp5RJ2NfD6fK/img.png?width=1200&amp;amp;height=600&amp;amp;face=980_127_1073_228,https://scrap.kakaocdn.net/dn/IuKEV/hyZf60cOQn/KjoEVxkDgeSWH384cWY3S0/img.png?width=1200&amp;amp;height=600&amp;amp;face=980_127_1073_228');&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;[WebGL][WebAssembly] Enable WebAssembly.Table in Unity 6000.0.xx occur Uncaught TypeError: Module.dynCall_v when click web page&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Module.dynCall_v(uLipSync.unityCsharpCallback); Occur Error:Uncaught TypeError: Module.dynCall_v is not a function. This error disapper when disable WebAssembly.Table option.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-end=&quot;288&quot; data-start=&quot;256&quot; data-ke-size=&quot;size16&quot;&gt;Unity 6 (Emscripten 최신 버전 기반)부터:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;431&quot; data-start=&quot;289&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;344&quot; data-start=&quot;289&quot;&gt;Module.dynCall_viiiii 같은 함수들이 &lt;b&gt;더 이상 자동으로 생성되지 않는다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;431&quot; data-start=&quot;345&quot;&gt;대신 &lt;b&gt;Module.makeDynCall(&quot;viiiii&quot;)&lt;/b&gt; 또는 &lt;b&gt;Module.wasmTable.get(pointer)&lt;/b&gt; 방식으로 대체된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 dynCall을 대체할 메서드를 임시로 Jspre 파일을 통해서 선언하면 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 프로젝트에서 Plugins 폴더에 WebGL폴더를 생성합니다.&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;357&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QtrLr/btsO0dozktm/hktfgl5RkYCFEOczYlM79K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QtrLr/btsO0dozktm/hktfgl5RkYCFEOczYlM79K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QtrLr/btsO0dozktm/hktfgl5RkYCFEOczYlM79K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQtrLr%2FbtsO0dozktm%2Fhktfgl5RkYCFEOczYlM79K%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;357&quot; height=&quot;332&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 안쪽에 test.jspre (이름은 자유) 파일을 생성하고 다음 스크립트를 첨부합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751347050966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Licensed under the MIT License. See LICENSE in the project root for license information.

/**
 * Initializes the dynCall_* function table lookups.
 * Thanks to @De-Panther for the following code snippet.
 * Checks if specific dynCall functions exist,
 * if not, it will create them using the getWasmTableEntry function.
 * @see https://discussions.unity.com/t/makedyncall-replacing-dyncall-in-unity-6/1543088
*/
Module['preRun'].push(function () {
  if (typeof getWasmTableEntry !== &quot;undefined&quot;) {
    Module.dynCall_vi = Module.dynCall_vi || function (cb, arg1) {
      return getWasmTableEntry(cb)(arg1);
    }
    Module.dynCall_vii = Module.dynCall_vii || function (cb, arg1, arg2) {
      return getWasmTableEntry(cb)(arg1, arg2);
    }
    Module.dynCall_viii = Module.dynCall_viii || function (cb, arg1, arg2, arg3) {
      return getWasmTableEntry(cb)(arg1, arg2, arg3);
    }
    Module.dynCall_viiii = Module.dynCall_viiii || function (cb, arg1, arg2, arg3, arg4) {
      return getWasmTableEntry(cb)(arg1, arg2, arg3, arg4);
    }
    // 저는 dynCall_Viiiii도 있어서 추가했습니다.
    Module.dynCall_viiiii = Module.dynCall_viiiii || function (cb, arg1, arg2, arg3, arg4, arg5) {
      return getWasmTableEntry(cb)(arg1, arg2, arg3, arg4, arg5);
    }
  }
});&lt;/code&gt;&lt;/pre&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;빌드된 WebGL 폴더 -&amp;gt; Build -&amp;gt; framework.js 파일을 확인하면 해당 코드가 삽입된 것을 확인 할 수 있습니다.&lt;/p&gt;</description>
      <category>Unity/ERROR</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/143</guid>
      <comments>https://sonsazang.tistory.com/143#entry143comment</comments>
      <pubDate>Tue, 1 Jul 2025 14:18:39 +0900</pubDate>
    </item>
    <item>
      <title>UI Toolkit : UI Document 활용하기</title>
      <link>https://sonsazang.tistory.com/142</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지난번에는 UI Toolkit을 소개했으면 오늘은 프로그래머가 어떤 식으로 사용하는지에 대해 정리하는 시간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 다음과 같은 순서로 진행됩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;UI Builder를 활용해서 테스트 UI Document(.uxml) 작성하기&lt;/li&gt;
&lt;li&gt;작성한 UI Document를 기반으로 C# 코드 작성하기&lt;/li&gt;
&lt;li&gt;씬에서 컴포넌트를 연결 한 후 직접 테스트해보기&lt;/li&gt;
&lt;/ol&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;1. UI Builder를 활용해서 UI Document(. uxml) 작성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Project 우클릭 &amp;rarr; Create &amp;rarr; UI Toolkit &amp;rarr; UI Document를 선택해서 새로운 UI Document를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 TestUIDocument로 설정하겠습니다. (자유입니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;911&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY2rsl/btsNQWJm3Nd/trkzFscxBMkD8otcV9TSYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY2rsl/btsNQWJm3Nd/trkzFscxBMkD8otcV9TSYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY2rsl/btsNQWJm3Nd/trkzFscxBMkD8otcV9TSYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY2rsl%2FbtsNQWJm3Nd%2FtrkzFscxBMkD8otcV9TSYk%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;800&quot; height=&quot;690&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;911&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 TestUIDocument를 클릭하면 UI Builder 가 열리면서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서는 Style Sheet는 따로 설정하지 않겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hierarchy에서 TestUIDocument.uxml를 클릭 &amp;rarr; Inspector에서 Canvas Size를 설정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 1920, 1080으로 설정했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1927&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o9Hnk/btsNRQICJTj/u2K8j9JFl9KGZpW4Lx0HsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o9Hnk/btsNRQICJTj/u2K8j9JFl9KGZpW4Lx0HsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o9Hnk/btsNRQICJTj/u2K8j9JFl9KGZpW4Lx0HsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo9Hnk%2FbtsNRQICJTj%2Fu2K8j9JFl9KGZpW4Lx0HsK%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;800&quot; height=&quot;428&quot; data-origin-width=&quot;1927&quot; data-origin-height=&quot;1032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Library에서 테스트로 사용해 볼 UI 요소들을 하이라키로 가지고 옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Containers &amp;rarr; Visual Element 선택해서 하이라키에 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 #test-main-window로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 그 안쪽으로 다양한 UI 요소들을 추가하겠습니다.&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;Controls &amp;rarr; Dropdown을 추가 후 이름은 &lt;b&gt;#test-dropdown&lt;/b&gt;으로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controls &amp;rarr; Label을 추가 후 이름은 &lt;b&gt;#test-label&lt;/b&gt;으로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controls &amp;rarr; Button을 추가 후 이름은 &lt;b&gt;#test-button&lt;/b&gt;으로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Containers &amp;rarr; Visual Element를 추가 후 이름은 &lt;b&gt;#test-window&lt;/b&gt;로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#test-window는 Inspector에서 Inlined Styles &amp;rarr; Background &amp;rarr; Image에 이미지를 연결합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controls &amp;rarr; Toggle을 추가 후 이름은 &lt;b&gt;#test-toggle&lt;/b&gt;으로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controls &amp;rarr; Progress Bar을 추가 후 이름은 &lt;b&gt;#test-progressbar&lt;/b&gt;으로 설정하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controls &amp;rarr; Text Field을 추가 후 이름은 &lt;b&gt;#test-textfield&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;모든 항목 Inspector에서 Inlined Styles &amp;rarr; Text &amp;rarr; Size만 50으로 변경했습니다. (보기 좋은 용도)&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; 이름 변경은 F2(이름 변경 단축키)를 통해서 하거나 UI 요소를 선택한 후 Inspector 최상단에서 수정 가능합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완성된 TestUIDocument의 모습입니다. &amp;rarr; 저와 다르게 원하시는 항목을 추가로 테스트해보세요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;1033&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhBOBR/btsNSIJCwzF/DcaYV9JidBS3zFPJwWR4c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhBOBR/btsNSIJCwzF/DcaYV9JidBS3zFPJwWR4c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhBOBR/btsNSIJCwzF/DcaYV9JidBS3zFPJwWR4c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhBOBR%2FbtsNSIJCwzF%2FDcaYV9JidBS3zFPJwWR4c1%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;800&quot; height=&quot;428&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;1033&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;2. 작성한 UI Document를 기반으로 C# 코드 작성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 C#으로 UI 요소를 제어하기 위해 스크립트를 작성하는 시간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 C# 스크립트를 하나 생성합니다. 이름은 TestUI로 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트의 상단부에는 앞서 UI Document에서 선언한 UIElement 들을 선언합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;기존 유니티 생명주기와 다르게 UI Element 초기화 및 값을 설정하는 부분은 OnEnable()에서 진행합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OnEnable() 안에서 Root Visual Element를 찾아서 가져온 후 해당 Root 안에 있는 요소들을 찾아서 선언한 UI Element와 연결합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 연결 된 UI Element의 값을 수정하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(*해당 글에서는 예외처리 부분 포함하지 않았습니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1746778457994&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class TestUI : MonoBehaviour
{
    // root 요소 선언
    VisualElement root;

    // UI 요소 선언
    Label testLabel;
    Button testButton;
    VisualElement testWindow;
    Toggle testToggle;
    ProgressBar testProgressBar;
    DropdownField testChoice;
    TextField input_test;

    private void OnEnable()
    {   
        // root 요소 찾아서 연결
        root = GetComponent&amp;lt;UIDocument&amp;gt;().rootVisualElement;

        // ui 요소 바인딩
        testLabel = root.Q&amp;lt;Label&amp;gt;(&quot;test-label&quot;);
        
        testButton = root.Q&amp;lt;Button&amp;gt;(&quot;test-button&quot;);
        
        testWindow = root.Q&amp;lt;VisualElement&amp;gt;(&quot;test-window&quot;);
        
        testToggle = root.Q&amp;lt;Toggle&amp;gt;(&quot;test-toggle&quot;);

        testProgressBar = root.Q&amp;lt;ProgressBar&amp;gt;(&quot;test-progressbar&quot;);
        testProgressBar.value = 0;

        testChoice = root.Q&amp;lt;DropdownField&amp;gt;(&quot;test-dropdown&quot;);
        
        input_test = root.Q&amp;lt;TextField&amp;gt;(&quot;test-textfield&quot;);

        // ui 요소 설정
        testLabel.text = &quot;Test Label !!!&quot;;

        testButton.text = &quot;Test Button !!!&quot;;
        testButton.RegisterCallback&amp;lt;ClickEvent&amp;gt;(ev =&amp;gt;
        {
            Debug.LogWarning(&quot;Test Button Clicked !!!&quot;);

            Debug.LogWarning(&quot;Input Test Value : &quot; + input_test.value);
        });

        testToggle.value = true;
        testToggle.RegisterValueChangedCallback(evt =&amp;gt;
        {
            Debug.LogWarning(&quot;Test Toggle Value : &quot; + evt.newValue);
            testWindow.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
        });

        for (int i = 0; i &amp;lt; 100; i++)
        {
            testProgressBar.value = i % 100;
        }

        List&amp;lt;string&amp;gt; testChoiceList = new List&amp;lt;string&amp;gt;();
        testChoiceList.Add(&quot;Test_01&quot;);
        testChoiceList.Add(&quot;Test_02&quot;);
        testChoiceList.Add(&quot;Test_03&quot;);
        testChoice.choices = testChoiceList;

        testChoice.index = 0;

        testChoice.RegisterValueChangedCallback(ev =&amp;gt;
        {
            Debug.LogWarning(&quot;Current Test Choice Index is &quot; + ev.newValue);
        });

        input_test.value = &quot;Input Test Field !!&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드를 확인하면 초반 부분에 Root에서 연결할 때 다음과 같은 코드를 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1746778486417&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;`testLabel = root.Q&amp;lt;Label&amp;gt;(&quot;test-label&quot;);`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 풀어서 설명하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;testLabel에 root에서 Q &amp;rarr; Query 쿼리를 통해서 &amp;lt;Label&amp;gt; 타입의 &amp;ldquo;test-label&amp;rdquo; 이름을 가진 UI 요소를 가져와서 할당한다입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중반부에 보면 testButton, testToggle, testChoice 에는 Register~~ 하는 코드가 있는데 람다식으로 이벤트를 연결하는 코드로 생각하시면 쉽게 이해할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 UGUI에서 OnValueChanged 같은 개념입니다.&lt;/p&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;3. 씬에서 컴포넌트를 연결한 후 직접 테스트해보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다 왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성한 UI Document와 TestUI 스크립트를 통해서 씬에서 직접 확인해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Project에서 Create &amp;rarr; UI Toolkit &amp;rarr; Panel Settings Asset을 통해서 Panel Settings를 하나 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;씬에서 빈 GameObject를 생성한 후 UI Document와 Test UI 컴포넌트를 Add Component 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 사진처럼 UI Document에 Panel Settings와 TestUIDocument.uxml를 연결합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x87z4/btsNRJJxDPA/4iXgPg4tKZN5LLigYcQaxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x87z4/btsNRJJxDPA/4iXgPg4tKZN5LLigYcQaxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x87z4/btsNRJJxDPA/4iXgPg4tKZN5LLigYcQaxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx87z4%2FbtsNRJJxDPA%2F4iXgPg4tKZN5LLigYcQaxK%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;800&quot; height=&quot;505&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;398&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pJogN/btsNQqc4xUw/5KlPbQR3mhaXUwPnPPmuTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pJogN/btsNQqc4xUw/5KlPbQR3mhaXUwPnPPmuTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pJogN/btsNQqc4xUw/5KlPbQR3mhaXUwPnPPmuTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpJogN%2FbtsNQqc4xUw%2F5KlPbQR3mhaXUwPnPPmuTk%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;398&quot; height=&quot;239&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&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;감사합니다.&lt;/p&gt;</description>
      <category>Unity/Function</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/142</guid>
      <comments>https://sonsazang.tistory.com/142#entry142comment</comments>
      <pubDate>Fri, 9 May 2025 17:16:46 +0900</pubDate>
    </item>
    <item>
      <title>Unity Eidtor 실행시 Finish Loading Project에서 로딩창 종료 안되는 현상</title>
      <link>https://sonsazang.tistory.com/141</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PCKFX/btsNQaH5YDH/fDLTQDY6KGsgoIbLU2D7YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PCKFX/btsNQaH5YDH/fDLTQDY6KGsgoIbLU2D7YK/img.png&quot; data-alt=&quot;해당 사진은 구글에서 가져왔습니다. 유니티 버전도 상황도 동일합니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PCKFX/btsNQaH5YDH/fDLTQDY6KGsgoIbLU2D7YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPCKFX%2FbtsNQaH5YDH%2FfDLTQDY6KGsgoIbLU2D7YK%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;800&quot; height=&quot;500&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해당 사진은 구글에서 가져왔습니다. 유니티 버전도 상황도 동일합니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UnityHub : 3.12.1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity : 2022.3.23 f1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity Hub에서 프로젝트 실행 시 100%는 아니지만 빈번하게 발생하는 현상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 현상일 때 모니터 상단부의 일부 영역을 가리는 검은색 박스가 노출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 관리자를 통해서 확인하면 Ram이 많이 올라간다.&lt;/p&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;/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;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;&lt;a href=&quot;https://discussions.unity.com/t/unity-gets-stuck-on-white-loading-screen-on-startup/194799&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Unity gets stuck on white loading screen on startup?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity Discussions에 저와 비슷한 상황인 글을 발견했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글에 있는 다양한 해결 방법을 하나씩 시도할 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 경우 Kaelcoke가 작성한 AppData 안에서 몇몇의 파일을 제거하는 것에서 해결되었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1746766129607&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Kaelcoke - Oct 2017
I&amp;rsquo;ve got the same problem and after a little research I came to an answear.
Before anything, backup your projects.
Open any folder and go to %AppData%
Then, a &amp;ldquo;Roaming&amp;rdquo; folder will open. Search for Unity and delete this folder.
Go up one folder (AppData) and do the same to Local/Unity and LocalLow/Unity.
Hope it works.&lt;/code&gt;&lt;/pre&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;AppData/Roaming/Unity&lt;/li&gt;
&lt;li&gt;AppData/Local/Unity&lt;/li&gt;
&lt;li&gt;AppData/LocalLow/Unity&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 3개의 폴더를 제거하면 해결된다 라는 내용입니다.&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;이전보다 에디터 로딩시간도 많이 개선되었고 5번 정도 프로젝트를 왔다 갔다 실행해 보았는데 문제가 해결되었습니다.&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;감사합니다.&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;</description>
      <category>Unity/ERROR</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/141</guid>
      <comments>https://sonsazang.tistory.com/141#entry141comment</comments>
      <pubDate>Fri, 9 May 2025 13:49:30 +0900</pubDate>
    </item>
    <item>
      <title>UI Builder Viewport에서 Canvas Size 설정하기</title>
      <link>https://sonsazang.tistory.com/140</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티 에디터를 실행한 이후 처음으로 uxml 파일을 선택해서 UI Builder를 실행하면 아래 화면처럼 비율이 깨져있는 Canvas를 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVt35q/btsNQXAskgx/xG32dU9FJkArYwyJNmP8pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVt35q/btsNQXAskgx/xG32dU9FJkArYwyJNmP8pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVt35q/btsNQXAskgx/xG32dU9FJkArYwyJNmP8pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVt35q%2FbtsNQXAskgx%2FxG32dU9FJkArYwyJNmP8pk%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;800&quot; height=&quot;503&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;671&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Builder &amp;rarr; Hierarchy에서 최상위 uxml 파일을 클릭합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inspector를 확인하면 다음과 같이 Width : 350, Height : 450 이렇게 이상한 값으로 설정되어 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 Size 바로 아래쪽에 위치한 토글인 Match Game View를 클릭하면 UnityEditor &amp;rarr; GameView에서 설정한 사이즈로 적용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;만약 기본 Canvas Size를 변경하고 싶다면?&lt;/h3&gt;
&lt;pre id=&quot;code_1746756565369&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

#if UNITY_EDITOR

internal class PatchUIBuilderSize
{
    const int UIBUILDER_CANVAS_WIDTH = 1920;
    const int UIBUILDER_CANVAS_HEIGHT = 1080;

    [InitializeOnLoadMethod]
    private static void SetUIBuilderConstants()
    {
        var t = Type.GetType(&quot;Unity.UI.Builder.BuilderConstants, UnityEditor.UIBuilderModule&quot;);
        if (t == null)
        {
            Debug.LogWarning(&quot;Couldn't patch UI Builder default size. BuilderConstants type not found.&quot;);
            return;
        }

        FieldInfo initialWidth = t.GetField(&quot;CanvasInitialWidth&quot;, BindingFlags.Static | BindingFlags.Public);
        if (initialWidth == null)
        {
            Debug.LogWarning(&quot;Couldn't patch UI Builder default size. CanvasInitialWidth field not found.&quot;);
            return;
        }

        FieldInfo initialHeight = t.GetField(&quot;CanvasInitialHeight&quot;, BindingFlags.Static | BindingFlags.Public);
        if (initialHeight == null)
        {
            Debug.LogWarning(&quot;Couldn't patch UI Builder default size. CanvasInitialHeight field not found.&quot;);
            return;
        }

        initialWidth.SetValue(t, UIBUILDER_CANVAS_WIDTH);
        initialHeight.SetValue(t, UIBUILDER_CANVAS_HEIGHT);
        Debug.Log(&quot;(PatchUIBuilderSize) Patched UI Builder to set initial dimensions to 1920 * 1080&quot;);
    }
}

#endif&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 스크립트를 사용하면 에디터를 실행할 때 설정한 사이즈 ( 1920, 1080 )로 자동 적용 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*uxml 에서 루트 Visual Element가 있어야 작동합니다.&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;&lt;a href=&quot;https://discussions.unity.com/t/default-canvas-size/932687/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://discussions.unity.com/t/default-canvas-size/932687/4&lt;/a&gt;&lt;/p&gt;</description>
      <category>Unity/Function</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/140</guid>
      <comments>https://sonsazang.tistory.com/140#entry140comment</comments>
      <pubDate>Fri, 9 May 2025 11:10:04 +0900</pubDate>
    </item>
    <item>
      <title>Unity UI Toolkit</title>
      <link>https://sonsazang.tistory.com/139</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Unity의 사용자 인터페이스 설계 및 구현 - 공식 홈페이지 E-Book을 참조했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://unity.com/kr/resources/user-interface-design-and-implementation-in-unity&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://unity.com/kr/resources/user-interface-design-and-implementation-in-unity&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746686655866&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;Unity의 사용자 인터페이스 설계 및 구현&quot; data-og-description=&quot;Unity의 UI 시스템으로 정교한 인터페이스를 만드는 방법을 알아보세요.&quot; data-og-host=&quot;unity.com&quot; data-og-source-url=&quot;https://unity.com/kr/resources/user-interface-design-and-implementation-in-unity&quot; data-og-url=&quot;https://unity.com/resources/user-interface-design-and-implementation-in-unity&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/F3WIe/hyYPh9Feut/6AFwFBBxcijzuWkms0o53K/img.jpg?width=320&amp;amp;height=414&amp;amp;face=0_0_320_414,https://scrap.kakaocdn.net/dn/nWXnX/hyYRzaAqDi/UMesQKMP0pynU2g3ptd0N1/img.jpg?width=320&amp;amp;height=414&amp;amp;face=0_0_320_414&quot;&gt;&lt;a href=&quot;https://unity.com/kr/resources/user-interface-design-and-implementation-in-unity&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://unity.com/kr/resources/user-interface-design-and-implementation-in-unity&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/F3WIe/hyYPh9Feut/6AFwFBBxcijzuWkms0o53K/img.jpg?width=320&amp;amp;height=414&amp;amp;face=0_0_320_414,https://scrap.kakaocdn.net/dn/nWXnX/hyYRzaAqDi/UMesQKMP0pynU2g3ptd0N1/img.jpg?width=320&amp;amp;height=414&amp;amp;face=0_0_320_414');&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;Unity의 사용자 인터페이스 설계 및 구현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Unity의 UI 시스템으로 정교한 인터페이스를 만드는 방법을 알아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;unity.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최고의 UI는 바로 &amp;lsquo;눈에 띄지 않는&amp;rsquo; UI입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI &amp;rarr; 게임의 몰입도를 유도하기 위한 디자인 장치 &amp;rarr; 플레이어의 시간을 낭비하면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity UI(UGUI) : 게임 오브젝트 기반 UI 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Toolkit : 웹 기술에서 아이디어를 얻어 개발된 UI 시스템&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UI Toolkit&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Toolkit은 본질적으로 기능적인 구현과 UI 디자인을 분리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자와 UI 아티스트의 역할이 구분 &amp;rarr; 각 팀의 전문 분야에 집중할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UI Toolkit 워크플로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Toolkit으로 만든 각 인터페이스는 다음과 같이 서로 연동하는 여러 부분으로 구성된다.&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;UI 문서(UXML)&lt;/b&gt; : 이 에셋은 UXML(Unity Extensibel Markup Language)을 참조합니다. HTML, XAML, XML을 기반으로 활용한 이 UI 문서는 &lt;b&gt;사용자 인터페이스 구조를 정의&lt;/b&gt;하고 &lt;b&gt;레이아웃의 계층 구조에 대한 정보&lt;/b&gt;를 담고 있습니다. 인라인 스타일 규칙과 스타일 시트를 사용하여 스타일을 지정할 수 있습니다.&lt;br /&gt;Assets &amp;rarr; Create &amp;rarr; UI Toolkit &amp;rarr; UI Document에서 에셋을 생성하며 이 에셋은 프로젝트 폴더에 추가되며 UI Builder에서 열 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스타일 시트(USS)&lt;/b&gt; : 이 에셋은 USS(Unity Style Sheet)를 참조합니다. HTML의 CSS(캐스케이딩 스타일 시트)에서 영감을 받은 이 스타일 시트에는 &lt;b&gt;UXML의 시각적 레이아웃에 영향&lt;/b&gt;을 줄 수 있는 &lt;b&gt;스타일 프로퍼티에 대한 캐스케이딩 규칙이 포함&lt;/b&gt;됩니다. &lt;br /&gt;Assets &amp;rarr; Create &amp;rarr; UI Toolkit &amp;rarr; Style Sheet에서 에셋을 생성하며 이 에셋은 프로젝트 폴더에 추가되며 UI Builder에 열려 있는 UXML 파일에 추가될 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TSS(테마 스타일 시트)&lt;/b&gt; : 이 에셋은 사용할 Panel Settings를 정하는 TSS 및 USS 파일 모음입니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI Document 컴포넌트&lt;/b&gt; : 이 컴포넌트는 &lt;b&gt;표시할 UXML을 정의&lt;/b&gt;하고 &lt;b&gt;해당 UI Toolkit에셋을 게임 오브젝트에 연결&lt;/b&gt;합니다. 에디터 계층 구조에 있는 게임 오브젝트에 추가 될 수 있고, &lt;b&gt;어떤 Panel Settings를 사용할지 지정&lt;/b&gt;할 수 있습니다. &lt;br /&gt;Sort Order 필드는 이 문서가 동일한 Panel Settings를 사용하는 다른 UI Document와 관련하여 표시되는 방식을 결정합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Panel Settings :&lt;/b&gt; 이 에셋은 런타임에 UI Document 컴포넌트가 인스턴스화되고 시각화되는 방식을 정의합니다. 여러 Panel Settings를 사용하여 UI에 다양한 스타일을 사용할 수 있습니다. 게임에 HUD나 미니맵이 있는 경우, 이러한 특수 UI에 각각 고유한 Panel Settings를 사용할 수 있습니다.&lt;br /&gt;Assets &amp;rarr; Create &amp;rarr; UI Toolkit &amp;rarr; Panel Settings Asset에서 생성할 수 있으며 프로젝트 폴더에 추가 및 게임 오브젝트의 UI Document 컴포넌트에 추가할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아티스트와 디자이너는 UI Builder(Window &amp;rarr; UI Toolkit &amp;rarr; UI Builder)에서 Assets 폴더에 저장한 UXML 및 UCSS 파일을 사용하여 작업할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Builder는 크리에이터가 코드를 작성하지 않고도 인터페이스를 만들고 편집하도록 지원하는 시각적 툴입니다.&lt;/p&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;Flexbox 기초&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Toolkit은 Flexbox의 하위 집합을 구현하는 HTML/CSS 레이아웃 엔진인 Yoga를 기반으로 시각적 요소의 위치를 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flexbox 아키텍처는 복잡하고 체계적인 레이아웃 개발에 적합하다.&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;반응형 UI&lt;/b&gt; : &lt;b&gt;Flexbox는 모든 요소를 상자 또는 컨테이너 네트워크로 구성&lt;/b&gt;한다. 이러한 요소를 부모 - 자식 관계로 중첩하고 간단한 규칙을 사용하여 화면에서 효율적으로 정렬할 수 있다. &lt;b&gt;자식은 부모 컨테이너가 변경되면 자동으로 반응&lt;/b&gt;합니다. &lt;b&gt;반응형 레이아웃은 다양한 화면 해상도와 크기에 맞게 조정&lt;/b&gt;되므로, 더 쉽게 &lt;b&gt;여러 플랫폼을 타게팅&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;체계적인 복잡도&lt;/b&gt; : 스타일은 시각적 요소의 미적 가치를 제어하는 간단한 규칙을 정의한다. &lt;b&gt;스타일 하나를 동시에 수백 개의 요소에 적용&lt;/b&gt;할 수 있으며, &lt;b&gt;변경 사항은 전체 UI에 즉시 반영&lt;/b&gt;된다. 따라서 개별적인 요소의 외관을 작업하는 것이 아니라 &amp;rarr; &lt;b&gt;일관되고 재사용 가능한&lt;/b&gt; 스타일 위주로 UI를 디자인할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분리된 로직 및 디자인&lt;/b&gt; : &lt;b&gt;UI 레이아웃과 스타일이 코드로 분리&lt;/b&gt;되어 있습니다. &amp;rarr; &lt;b&gt;디자이너와 개발자가 종속성을 해치지 않고 원활하게 병렬로 작업할&lt;/b&gt; 수 있다.&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UI Toolkit에서 각 인터페이스의 기본 구성 요소&lt;/b&gt;는 &lt;b&gt;시각적 요소&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각적 요소는 모든 UI Toolkit 요소(버튼, 이미지, 텍스트 등)의 기본 클랙스 &amp;rarr; &lt;b&gt;UI Toolkit에서 사용하는 게임 오브젝트라고 생각하자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하나 이상의 시각적 요소로 구성된 UI 계층 구조 &amp;rarr; 시각적 트리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UI Toolkit에서 여러 시각적 요소의 조합 &amp;rarr;. uxml인 UI 문서 파일에 저장&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UXML 파일에는 계층 구조와 관련된 정보뿐만 아니라 스타일이나 시각적 요소의 레이아웃도 포함되어 있다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI 목업을 만들 때는 각 화면을 별도의 시각적 요소 그룹으로 보고 접근한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zl2r7/btsNOVDkVlO/u0g6GLEba8Rhv2OZCi0040/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zl2r7/btsNOVDkVlO/u0g6GLEba8Rhv2OZCi0040/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zl2r7/btsNOVDkVlO/u0g6GLEba8Rhv2OZCi0040/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzl2r7%2FbtsNOVDkVlO%2Fu0g6GLEba8Rhv2OZCi0040%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;1304&quot; height=&quot;397&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 이미지는 공식 홈페이지에서 제공되는 &lt;b&gt;Unity의 사용자 인터페이스 설계 및 구현 PDF에서&lt;/b&gt; 가져왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 시각 요소를 정의할 때 UI Builder는 다음 두 가지 위치 지정 옵션을 제공합니다.&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;Relative Position&lt;/b&gt; : 새로운 시각적 요소의 기본 설정. 자식 요소는 부모 컨테이너의 Flexbox 규칙을 따른다. 예를 들어 부모 요소의 Direction이 Row로 설정되어 있으면, 자식 시각 요소는 왼쪽에서 오른쪽으로 정렬된다.
&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Toolkit은 부모 요소와 자식 요소 간의 충돌을 처리 &amp;rarr; 컨테이너에 포함된 자식 요소의 최소 너비가 컨테이너보다 넓으면 오버플로우 발생&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;Absolute Position&lt;/b&gt; : 시각적 요소의 위치는 UGUI가 작동하는 방식과 유사하게 부모 컨테이너에 고정된다. 마진이나 최대 크기 등 규칙은 적용되지만, 부모의 Flexbox 규칙은 따르지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 내용 말고도 다양하게 기본적인 시각적 요소에 대한 설정 값이 나와 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS를 사용해 본 경험이 있으면 이해하는데 어려움이 없어서 해당 부분은 넘어가도록 하겠습니다.&lt;/p&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;UI Toolkit : 스타일링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각적 요소로 와이어프레임 레이아웃 목업을 만들었으면, 이제 스타일을 지정할 차례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USS 파일은 웹 CSS 파일에 해당되는 Unity 파일이며, 동일한 규칙 기반 형식을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USS 파일은 요소의 크기, 컬러, 폰트, 줄 간격, 테두리, 위치 등을 정의한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UI Builder&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI Builder 인터페이스를 사용하면 아티스트와 디자이너가 제작 중인 UI를 시각화할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;USS Selector (USS 선택자)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일 시트는 여러 요소와 UI문서(UXML)에서 USS 선택자를 통해 스타일을 공유하고 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USS Selector는 다음을 기준으로 요소를 일치시킨다.&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;C# 클래스 이름&lt;/b&gt; : 이 선택자는 유형별(버튼, 레이블, 스크롤러 등)로 작동한다. 선택자는 Library 창에서 특수 문자를 포함하지 않는 유형 이름에 해당한다. 클래스 선택자는 흰색으로 표시된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;할당된 이름 프로퍼티 :&lt;/b&gt; 이 선택자는 똑같은 이름의 모든 요소에 스타일을 적용할 수 있다. 이름 선택자 앞에 &lt;b&gt;&amp;lsquo;#&amp;rsquo;&lt;/b&gt; 해시 기호가 붙으며 파란색으로 표시된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;USS 스타일 클래스&lt;/b&gt; : 스타일 클래스 선택자는 모든 시각적 요소에 임의로 적용할 수 있다. 이름 앞에 &lt;b&gt;&amp;lsquo;.&amp;rsquo;&lt;/b&gt; 기호가 붙으며 노락색으로 표시된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능하면 이름이나 C# 클래스로 요소를 매치하는 것보다 스타일 클래스 선택자를 사용하는 것이 좋다.&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;선택자는 특정 상태의 요소를 타기팅하는 유사(pseudo) 클래스도 지원한다. &amp;rarr; &lt;b&gt;&amp;lsquo;:&amp;rsquo;으로&lt;/b&gt; 표시되며 기존 선택자를 수정한다. 예시로는 &lt;b&gt;Button:hover, #button-play:hover&lt;/b&gt; 이런 식이다.&lt;/p&gt;</description>
      <category>Unity/Function</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/139</guid>
      <comments>https://sonsazang.tistory.com/139#entry139comment</comments>
      <pubDate>Thu, 8 May 2025 15:48:49 +0900</pubDate>
    </item>
    <item>
      <title>Unity 2D 직교 카메라 설정에 따른 해상도별 PPU 계산 가이드</title>
      <link>https://sonsazang.tistory.com/138</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Unity 2D 카메라 설정과 스프라이트 PPU 계산법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity에서 2D 게임을 개발할 때는 &lt;span data-token-index=&quot;1&quot;&gt;직교 카메라(Orthographic Camera)를 를&lt;/span&gt; 주로 사용합니다. 이때 카메라의 Size&amp;nbsp;설정과 해상도에 맞는 &lt;span data-token-index=&quot;5&quot;&gt;PPU(Pixels Per Unit)&lt;/span&gt; 값을 잘 설정해야 스프라이트가 선명하게 보이고 원하는 크기로 출력됩니다.&lt;/p&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;카메라의 Size란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직교 카메라의 Size 값은 &lt;span data-token-index=&quot;3&quot;&gt;화면 중심에서 위쪽까지의 거리(유닛)를 를&lt;/span&gt; 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값은 Unity 유닛 단위이며, 일반적으로 1 유닛 = 1미터로 가정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-&amp;nbsp; Size = 2 &amp;rarr; 전체 세로 시야 : 4 유닛&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;1319&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds65n7/btsNN4UclMN/wQcVkqKdYOwYP5IH1ZAOl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds65n7/btsNN4UclMN/wQcVkqKdYOwYP5IH1ZAOl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds65n7/btsNN4UclMN/wQcVkqKdYOwYP5IH1ZAOl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fds65n7%2FbtsNN4UclMN%2FwQcVkqKdYOwYP5IH1ZAOl0%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;800&quot; height=&quot;275&quot; data-origin-width=&quot;1319&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-&amp;nbsp; Size = 5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 전체 세로 시야 : 10 유닛&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;1384&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezBPSA/btsNNdqPRG8/7dQfNf4pFkdCLyMR3axgo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezBPSA/btsNNdqPRG8/7dQfNf4pFkdCLyMR3axgo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezBPSA/btsNNdqPRG8/7dQfNf4pFkdCLyMR3axgo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezBPSA%2FbtsNNdqPRG8%2F7dQfNf4pFkdCLyMR3axgo1%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;800&quot; height=&quot;262&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전체 새로 유닛 = Size * 2&lt;/p&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;해상도와 FOV(Field of View)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;4K 해상도 (3840 &amp;times; 2160)를&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;화면의 세로 해상도: &lt;b&gt;2160픽셀&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;카메라 Size: &lt;b&gt;5&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;세로 시야(FOV): &lt;b&gt;10 유닛&lt;/b&gt;&lt;/li&gt;
&lt;/ul&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;PPU 계산 공식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해상도에 맞는 PPU는 아래 공식으로 계산할 수 있어요:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PPU = 세로 해상도 / 세로 유닛 &amp;rarr; 2160 / 10 = 216&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 즉, 4K 해상도에 최적화된 스프라이트를 만들려면 &lt;b&gt;216 PPU를&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;520&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Te3VB/btsNMgaHpUP/INr2p53iP8Ey41F3a2LBxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Te3VB/btsNMgaHpUP/INr2p53iP8Ey41F3a2LBxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Te3VB/btsNMgaHpUP/INr2p53iP8Ey41F3a2LBxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTe3VB%2FbtsNMgaHpUP%2FINr2p53iP8Ey41F3a2LBxK%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;520&quot; height=&quot;245&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;Size/해상도별 PPU 계산 예시&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;카메라 Size&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;세로 유닛(FOV)&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;해상도(세로)&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;적절한 PPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;4&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2160&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;540&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2160&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;216&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;20&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;2160&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;108&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;너무 높은 PPU는 &lt;b&gt;메모리/성능 부담&lt;/b&gt;을 줄 수 있으니, 타겟&amp;nbsp;플랫폼과 해상도에 따라 적절하게 조절하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1080p 해상도&lt;/b&gt;에서 Size = 5인 경우, PPU = 1080 / 10 = 108로 설정하면 적절합니다.&lt;/li&gt;
&lt;li&gt;UI나 배경 스프라이트는 상황에 따라 다른 PPU를 사용할 수도 있어요.&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity 2D에서 선명한 스프라이트 표현을 위해선:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;카메라의 Size 값 확인&lt;/li&gt;
&lt;li&gt;타겟 해상도 확인&lt;/li&gt;
&lt;li&gt;공식에 따라 &lt;b&gt;PPU = 해상도 &amp;divide; (Size &amp;times; 2)&lt;/b&gt; 계산&lt;/li&gt;
&lt;li&gt;스프라이트 리소스를 해당 PPU에 맞춰 제작&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Unity</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/138</guid>
      <comments>https://sonsazang.tistory.com/138#entry138comment</comments>
      <pubDate>Thu, 8 May 2025 10:31:40 +0900</pubDate>
    </item>
    <item>
      <title>2025년 5월 7일, 첫 출근을 마치고 나서</title>
      <link>https://sonsazang.tistory.com/137</link>
      <description>&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-end=&quot;302&quot; data-start=&quot;211&quot; data-ke-size=&quot;size16&quot;&gt;유니티에서 약 3년간 실무를 경험하고, 게임 회사 이직을 목표로 언리얼 엔진 학습을 시작했지만, 결과적으로 다시 유니티 엔진을 사용하는 회사로 돌아오게 되었습니다.&lt;/p&gt;
&lt;p data-end=&quot;413&quot; data-start=&quot;304&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;413&quot; data-start=&quot;304&quot; data-ke-size=&quot;size16&quot;&gt;지난해 10월 퇴사 후, 한 달 정도 충분히 쉰 뒤 12월부터는 하루 12시간씩 몰입하며 공부했습니다.&lt;br /&gt;그때의 집중적인 학습이 지금의 프로그래밍 감각을 유지시켜 준 중요한 시간이었다고 생각합니다.&lt;/p&gt;
&lt;p data-end=&quot;559&quot; data-start=&quot;415&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;559&quot; data-start=&quot;415&quot; data-ke-size=&quot;size16&quot;&gt;최근 채용 시장은 제가 처음 유니티로 취업을 준비하던 3년 전과는 분위기가 크게 달랐습니다.&lt;br /&gt;이번 이직은 오랜 시간이 걸릴 수도 있겠다고 예상했지만, 목표로 했던 2025년 4~5월 사이에 다시 취업에 성공할 수 있어서 개인적으로 매우 만족스럽습니다.&lt;/p&gt;
&lt;p data-end=&quot;693&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;693&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;메타버스 관련 경력만 3년이라 유니티 엔진 기반의 게임 회사 취업은 쉽지 않을 거라 생각했지만,&lt;br /&gt;첫 회사에서의 WebGL 프로젝트, 두 번째 회사에서의 실무 경험이 긍정적으로 작용해 운 좋게도 게임 회사에 입사하게 되었습니다.&lt;/p&gt;
&lt;p data-end=&quot;788&quot; data-start=&quot;695&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;788&quot; data-start=&quot;695&quot; data-ke-size=&quot;size16&quot;&gt;그리고 오늘, 2025년 5월 7일.&lt;br /&gt;한 번쯤 가보고 싶었던 판교에서, 한 번쯤 일해보고 싶었던 게임회사에 첫 출근을 무사히 마치고 돌아왔습니다.&lt;/p&gt;
&lt;p data-end=&quot;947&quot; data-start=&quot;790&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;947&quot; data-start=&quot;790&quot; data-ke-size=&quot;size16&quot;&gt;기분 좋게 하루를 마무리하며, 앞으로의 학습 방향도 정리해보려 합니다.&lt;br /&gt;그동안 메타버스 실무 프로젝트에서 두 번의 출시 경험을 통해 전체적인 프로세스는 잘 익혔지만,&lt;br /&gt;정작 &lt;b&gt;게임 콘텐츠 개발&lt;/b&gt; 경험은 부족한 편이라 올해 하반기에는 이 부분에 집중해서 성장해보고자 합니다.&lt;/p&gt;
&lt;hr data-end=&quot;952&quot; data-start=&quot;949&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1022&quot; data-start=&quot;954&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;힘든 시기였지만, 결국 길은 있었습니다.&lt;/b&gt;&lt;br /&gt;이 글을 우연히 보게 된 누군가에게도 분명히 좋은 일이 찾아올 거라 믿습니다.&lt;/p&gt;
&lt;p data-end=&quot;1043&quot; data-start=&quot;1024&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1043&quot; data-start=&quot;1024&quot; data-ke-size=&quot;size16&quot;&gt;모두 화이팅입니다.&lt;br /&gt;감사합니다.&lt;/p&gt;</description>
      <category>끄적끄적</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/137</guid>
      <comments>https://sonsazang.tistory.com/137#entry137comment</comments>
      <pubDate>Wed, 7 May 2025 20:49:14 +0900</pubDate>
    </item>
    <item>
      <title>20250411 - 전투/아이템 시스템 구조화</title>
      <link>https://sonsazang.tistory.com/136</link>
      <description>&lt;p data-end=&quot;277&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;이번 주에는 언리얼 기반 게임 프로젝트에서 캐릭터 관련 로직을 &lt;b&gt;컴포넌트 단위로 구조화하고 리팩토링 하는&lt;/b&gt; 작업을 진행했다.&lt;/p&gt;
&lt;p data-end=&quot;277&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;주요 목표는 다음과 같다:&lt;/p&gt;
&lt;h3 data-end=&quot;287&quot; data-start=&quot;279&quot; data-ke-size=&quot;size23&quot;&gt;목표&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;367&quot; data-start=&quot;288&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;304&quot; data-start=&quot;288&quot;&gt;캐릭터 로직의 복잡도 해소&lt;/li&gt;
&lt;li data-end=&quot;334&quot; data-start=&quot;305&quot;&gt;전투 / 아이템 로직의 기능 분리 및 확장성 확보&lt;/li&gt;
&lt;li data-end=&quot;367&quot; data-start=&quot;335&quot;&gt;파티 애니멀즈 스타일의 무기 획득 &amp;amp; 교체 시스템 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;389&quot; data-start=&quot;374&quot; data-ke-size=&quot;size23&quot;&gt;시스템 분리 구조&lt;/h3&gt;
&lt;h4 data-end=&quot;429&quot; data-start=&quot;391&quot; data-ke-size=&quot;size20&quot;&gt;1. CombatComponent - 전투 관련 처리 전담&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;591&quot; data-start=&quot;430&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;455&quot; data-start=&quot;430&quot;&gt;&lt;b&gt;공격 실행&lt;/b&gt;, &lt;b&gt;애니몽타주 재생&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;479&quot; data-start=&quot;456&quot;&gt;&lt;b&gt;데미지 계산&lt;/b&gt;, &lt;b&gt;넉백 처리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;503&quot; data-start=&quot;480&quot;&gt;&lt;b&gt;GameplayEffect 적용&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;545&quot; data-start=&quot;504&quot;&gt;GAS 태그 기반 공격 불가 상태 (State.Stunned) 대응&lt;/li&gt;
&lt;li data-end=&quot;591&quot; data-start=&quot;546&quot;&gt;AnimNotify에서 호출되는 HandleAttackNotify() 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;627&quot; data-start=&quot;593&quot; data-ke-size=&quot;size20&quot;&gt;2. ItemComponent - 아이템 처리 전담&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;791&quot; data-start=&quot;628&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;628&quot;&gt;&lt;b&gt;월드에서 아이템 획득 &amp;amp; 장착&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;677&quot; data-start=&quot;651&quot;&gt;장착 중인 아이템은 &lt;b&gt;무기 소켓에 부착&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;725&quot; data-start=&quot;678&quot;&gt;새 무기 획득 시 기존 무기는 &lt;b&gt;월드에 드랍 (DropItemToWorld)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;757&quot; data-start=&quot;726&quot;&gt;아이템 사용 처리 (UseEquippedItem)&lt;/li&gt;
&lt;li data-end=&quot;791&quot; data-start=&quot;758&quot;&gt;드랍 아이템에 &lt;b&gt;Physics 적용 &amp;amp; 충돌 활성화&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;796&quot; data-start=&quot;793&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;817&quot; data-start=&quot;798&quot; data-ke-size=&quot;size23&quot;&gt;게임 플레이 스타일 변화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;900&quot; data-start=&quot;819&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;834&quot; data-start=&quot;819&quot;&gt;&lt;b&gt;기본 상태: 맨손&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;861&quot; data-start=&quot;835&quot;&gt;&lt;b&gt;월드에서 무기를 획득하면 무기로 공격&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;900&quot; data-start=&quot;862&quot;&gt;&lt;b&gt;새 무기 획득 시 이전 무기는 월드에 물리 오브젝트로 드랍&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;905&quot; data-start=&quot;902&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;922&quot; data-start=&quot;907&quot; data-ke-size=&quot;size23&quot;&gt;리팩토링 포인트&lt;/h3&gt;
&lt;h4 data-end=&quot;922&quot; data-start=&quot;907&quot; data-ke-size=&quot;size20&quot;&gt;CharacterBase 단순화&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1152&quot; data-start=&quot;948&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;988&quot; data-start=&quot;948&quot;&gt;Attack(), UseItem() 등은 각각 컴포넌트로 위임&lt;/li&gt;
&lt;li data-end=&quot;1064&quot; data-start=&quot;989&quot;&gt;CombatComponent와 ItemComponent 모두 BeginPlay 시 Init(this)로 캐릭터 참조 주입&lt;/li&gt;
&lt;li data-end=&quot;1152&quot; data-start=&quot;1065&quot;&gt;StatusEffect 위젯 처리 (ShowStatusWidget, HideStatusWidget)은 아직 CharacterBase에 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1175&quot; data-start=&quot;1154&quot; data-ke-size=&quot;size20&quot;&gt;블루프린트 호환성 문제 해결&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1316&quot; data-start=&quot;1176&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1269&quot; data-start=&quot;1176&quot;&gt;C++에서 RootComponent = ItemMesh 설정했으나, 기존 블루프린트에서는 여전히 SceneComponent가 루트로 잡혀버리는 문제 발생&lt;/li&gt;
&lt;li data-end=&quot;1316&quot; data-start=&quot;1270&quot;&gt;블루프린트에서 &lt;b&gt;직접 루트 컴포넌트 변경&lt;/b&gt; 필요 (또는 새 블루프린트 생성)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1707&quot; data-start=&quot;1698&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-end=&quot;1850&quot; data-start=&quot;1709&quot; data-ke-size=&quot;size16&quot;&gt;이번 리팩토링을 통해 캐릭터의 &lt;b&gt;전투/아이템 관리 기능을 모듈화&lt;/b&gt;하여 유지보수성과 확장성이 대폭 향상되었다.&lt;/p&gt;
&lt;p data-end=&quot;1850&quot; data-start=&quot;1709&quot; data-ke-size=&quot;size16&quot;&gt;GAS 기반 스테이터스 처리, 아이템 드랍 및 장착 구조, 클라이언트와 서버 간 상호작용 처리에 대해 좋은 구조적 기반을 마련한 한 주였다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/136</guid>
      <comments>https://sonsazang.tistory.com/136#entry136comment</comments>
      <pubDate>Fri, 11 Apr 2025 21:26:20 +0900</pubDate>
    </item>
    <item>
      <title>[level 3] 단어 변환 - 43163</title>
      <link>https://sonsazang.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[level&amp;nbsp;3]&amp;nbsp;단어&amp;nbsp;변환&amp;nbsp;-&amp;nbsp;43163&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43163&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1743580772870&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;SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UnHZ3/hyYBiUfq1l/RH1A7ueMtbijlPYKhky3v0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UnHZ3/hyYBiUfq1l/RH1A7ueMtbijlPYKhky3v0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 시도한 3 레벨 문제이지만 사실문제를 다 풀고 나서 3 레벨인걸 확인했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS 원리를 이해하고 있으면 생각보다 쉽게 접근이 가능했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[level 3] 단어 변환 - 43163 풀이코드&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_1743580812019&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

string s;
int cnt;
int solution(string begin, string target, vector&amp;lt;string&amp;gt; words) {
    int answer = 0;
    
    bool isExist = false;
    for (string i : words) 
    {
        if (i == target) 
        {
            isExist = true;
            break;
        }
    }
    
    if (!isExist) return 0;
    
    queue&amp;lt;pair&amp;lt;string, int&amp;gt;&amp;gt; q;
    q.push({begin, 0});
    while(q.size())
    {
        tie(s, cnt) = q.front(); q.pop();
        for (int i = 0; i &amp;lt; words.size(); i++) 
        {
            int temp = 0;
            for (int j = 0; j &amp;lt; s.length(); j++)
            {
                if (s[j] != words[i][j]) temp++;
                if (temp &amp;gt; 1) break;
            }
            
            if (temp == 1)
            {
                if (words[i] == target) return cnt + 1;
                else q.push({words[i], cnt + 1});
            }
        }
    }
    
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>코딩테스트/백준</category>
      <author>sonsazang</author>
      <guid isPermaLink="true">https://sonsazang.tistory.com/135</guid>
      <comments>https://sonsazang.tistory.com/135#entry135comment</comments>
      <pubDate>Wed, 2 Apr 2025 17:00:22 +0900</pubDate>
    </item>
  </channel>
</rss>