<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>덴바의 노트</title>
    <link>https://denbacodingnote.tistory.com/</link>
    <description>게임, 모델링, 작곡 등 다양한 장르를 공부해보고 메모하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Sat, 8 Aug 2026 15:48:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>덴바</managingEditor>
    <image>
      <title>덴바의 노트</title>
      <url>https://tistory1.daumcdn.net/tistory/7025911/attach/4336f3147ef548829ddbfb2660598dc3</url>
      <link>https://denbacodingnote.tistory.com</link>
    </image>
    <item>
      <title>[유니티 기능] TMP Material Preset</title>
      <link>https://denbacodingnote.tistory.com/53</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MHeq5/dJMcadiI1XS/Kmyu7dtfc7rL1PE60EQyn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MHeq5/dJMcadiI1XS/Kmyu7dtfc7rL1PE60EQyn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MHeq5/dJMcadiI1XS/Kmyu7dtfc7rL1PE60EQyn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMHeq5%2FdJMcadiI1XS%2FKmyu7dtfc7rL1PE60EQyn1%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;1200&quot; height=&quot;630&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&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;style3&quot;&gt;키워드&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TMP Text&lt;/li&gt;
&lt;li&gt;Material Presets&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;안녕하세요 오늘은 TMP_Text 컴포넌트의 마테리얼 프리셋에 대해서 포스팅 하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;생각치고 이 기능을 어떻게 생성하고 활용하는지 모릅니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;693&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFHnv4/dJMcahk8WkJ/XwL0DFkZcKBAw60L7ZkNzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFHnv4/dJMcahk8WkJ/XwL0DFkZcKBAw60L7ZkNzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFHnv4/dJMcahk8WkJ/XwL0DFkZcKBAw60L7ZkNzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFHnv4%2FdJMcahk8WkJ%2FXwL0DFkZcKBAw60L7ZkNzK%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;620&quot; height=&quot;781&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;TextMeshPro 컴포넌트를 보면 Material Presets라는 것이 존재합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;기본적으로 Text는 Vertex Color와 Color Gradient, Font Style을 활용해서 다양하게 표현할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;680&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2A1Yq/dJMcagzFDMI/lQJwYHuQh723kWu3Jh9JYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2A1Yq/dJMcagzFDMI/lQJwYHuQh723kWu3Jh9JYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2A1Yq/dJMcagzFDMI/lQJwYHuQh723kWu3Jh9JYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2A1Yq%2FdJMcagzFDMI%2FlQJwYHuQh723kWu3Jh9JYK%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;680&quot; height=&quot;802&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;802&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;그런데 스크롤링해서 아래를 보시면 마테리얼에서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;Face(표면에 보이는 부분), Outline, Underlay를 조절할 수 있는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;1547&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pWe0E/dJMcaaGjQWU/E9rGd4yLkyN0K6ZQ8Uw8Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pWe0E/dJMcaaGjQWU/E9rGd4yLkyN0K6ZQ8Uw8Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pWe0E/dJMcaaGjQWU/E9rGd4yLkyN0K6ZQ8Uw8Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpWe0E%2FdJMcaaGjQWU%2FE9rGd4yLkyN0K6ZQ8Uw8Jk%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;1547&quot; height=&quot;770&quot; data-origin-width=&quot;1547&quot; data-origin-height=&quot;770&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;해당 프로퍼티를 이용하면 이와 같이 폰트의 다양성을 추가할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;(포토샵, 프리미어 프로 등에서도 자주 사용하는 프로퍼티인거 같습니다)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;035&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/035.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/035.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;하지만 여기서 문제가 하나 있습니다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아무 생각 없이 저 수치를 변경하면 큰 문제가 생겨 버립니다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;800&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHc57U/dJMcaazv1Gk/5T6UrQzlzAMkkDIOAxhDf0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHc57U/dJMcaazv1Gk/5T6UrQzlzAMkkDIOAxhDf0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHc57U/dJMcaazv1Gk/5T6UrQzlzAMkkDIOAxhDf0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cHc57U/dJMcaazv1Gk/5T6UrQzlzAMkkDIOAxhDf0/img.gif&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;424&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;424&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;영상에서 보시는 바와 같이 텍스트 오브젝트를 하나 생성 했는데, 아까 조절했던 효과가 적용이 되어 나옵니다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 이유는 조금만 생각해보면 간단합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TextMeshPro에서는 Font 파일을 이용해서 TMP_Font Asset 파일을 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 이는 Material을 이용해서 시각적으로 Text를 표현하는 형태입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런데 그 기본이 되는 Default Material의 수치를 건들였기 때문에, &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;새로 생성한 Text 오브젝트도 동일한 효과가 적용이 되어버립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;009&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/009.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/009.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;그럼 도대체 저 프리셋을 어떻게 만드는지가 중요합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;'그냥 아무 생각 없이 Material을 생성하는건가?' 싶겠지만,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;정말 어이없게도 해당 프리셋을 만드는 방법은 꽁꽁 숨겨져 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;TMP Font Material Preset 생성&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mAemM/dJMcacKUaYe/RUL6Nk5g9ZjXugadkHN4Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mAemM/dJMcacKUaYe/RUL6Nk5g9ZjXugadkHN4Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mAemM/dJMcacKUaYe/RUL6Nk5g9ZjXugadkHN4Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmAemM%2FdJMcacKUaYe%2FRUL6Nk5g9ZjXugadkHN4Nk%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;661&quot; height=&quot;442&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;442&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;1. 먼저 TMP Font Asset을 생성하면서 만들어진 Default Material을 찾아줍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;1213&quot; data-origin-height=&quot;1622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CCqa6/dJMcaf1Np6Q/Bli7Ik8pkHAiKig72bmFl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CCqa6/dJMcaf1Np6Q/Bli7Ik8pkHAiKig72bmFl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CCqa6/dJMcaf1Np6Q/Bli7Ik8pkHAiKig72bmFl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCCqa6%2FdJMcaf1Np6Q%2FBli7Ik8pkHAiKig72bmFl1%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;620&quot; height=&quot;829&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;1622&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;2. 해당 Material을 클릭하고 Inspector의 우측 상단에 세로로 점 3개의 아이콘(Context Menu)을 클릭하거나,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;우클릭을 통해서 Context Menu를 띄우면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;Create Material Preset&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt; 메뉴가 존재합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;해당 메뉴를 클릭합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;1202&quot; data-origin-height=&quot;1583&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cN7sBK/dJMcadiI3Md/dKYaZdjAUPsYzkaMuMvU71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cN7sBK/dJMcadiI3Md/dKYaZdjAUPsYzkaMuMvU71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cN7sBK/dJMcadiI3Md/dKYaZdjAUPsYzkaMuMvU71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcN7sBK%2FdJMcadiI3Md%2FdKYaZdjAUPsYzkaMuMvU71%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;620&quot; height=&quot;817&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;1583&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;3. 그럼 자연스럽게 Material이 생성됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;해당 Material에 명칭을 적절하게 바꾸고 프로퍼티를 변경해줍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;716&quot; data-origin-height=&quot;687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKM9r6/dJMcaalRJkN/dKX0pgNKVrg1FDUf8euGZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKM9r6/dJMcaalRJkN/dKX0pgNKVrg1FDUf8euGZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKM9r6/dJMcaalRJkN/dKX0pgNKVrg1FDUf8euGZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKM9r6%2FdJMcaalRJkN%2FdKX0pgNKVrg1FDUf8euGZk%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;620&quot; height=&quot;595&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;687&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;4. TMP 컴포넌트의 Material Preset Dropdown을 눌러보면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;아까 생성한 Red Outline이 추가된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;1622&quot; data-origin-height=&quot;789&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Dtqk/dJMcabE6uqi/O6EH8t1kvFzr3PoY68k5Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Dtqk/dJMcabE6uqi/O6EH8t1kvFzr3PoY68k5Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Dtqk/dJMcabE6uqi/O6EH8t1kvFzr3PoY68k5Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Dtqk%2FdJMcabE6uqi%2FO6EH8t1kvFzr3PoY68k5Rk%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;1622&quot; height=&quot;789&quot; data-origin-width=&quot;1622&quot; data-origin-height=&quot;789&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;5. 해당 프리셋으로 변경해보면 빨간색 아웃라인이 자연스럽게 적용된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;자 여기 까지 TMP Font Asset의 Material Preset 생성 및 사용 방법에 대해서 적어봤습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;'그래서 이걸 어디에 사용해?' 라고 생각하실 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;간단히 생각하면, 매 번 공통적으로 사용되는 Text의 프로퍼티를 미리 저장해둔다면,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;딸깍 한 번으로 처리가 되고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;A, B의 Title Text의 디자인이 같아야 하는데, 각 담당자가 서로 다르게 나올 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;하지만 해당 프리셋을 저장해둔다면, 이에 대해서 정보 공유만 해두었을 때 이런 트러블이 발생하지 않겠죠?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;이상 TMP Material Preset 포스팅이었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;감사합니다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;008&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/008.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/008.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 노트/유니티 기능</category>
      <category>개발</category>
      <category>게임 개발</category>
      <category>공부</category>
      <category>독학</category>
      <category>유니티</category>
      <category>취미</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/53</guid>
      <comments>https://denbacodingnote.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 4 Aug 2026 14:28:10 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 버튼 연타 방지 확장 메소드 구현</title>
      <link>https://denbacodingnote.tistory.com/52</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GEQRo/dJMcaak6Svr/dWjV9xIGXda6HkeoaqwSAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GEQRo/dJMcaak6Svr/dWjV9xIGXda6HkeoaqwSAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GEQRo/dJMcaak6Svr/dWjV9xIGXda6HkeoaqwSAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGEQRo%2FdJMcaak6Svr%2FdWjV9xIGXda6HkeoaqwSAK%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;600&quot; height=&quot;315&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&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;style3&quot;&gt;오늘의 키워드&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UniRx&lt;/li&gt;
&lt;li&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;버튼 연속 클릭 방지 코드&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779849834866&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static IObservable&amp;lt;Unit&amp;gt; OnClickAsObservableWithThrottle(
  this Button button, float intervalSeconds, Action onWaitAction = null)
{
  var cooldownEnd = DateTimeOffset.MinValue;
  return button.OnClickAsObservable()
    .Do(_ =&amp;gt; {
      if (DateTimeOffset.UtcNow &amp;lt; cooldownEnd)
        onWaitAction?.Invoke(); // 대기 중 액션 실행
    })
    .Where(_ =&amp;gt; {
      var now = DateTimeOffset.UtcNow;
      if (now &amp;lt; cooldownEnd) return false; // 쿨다운 중 차단
      cooldownEnd = now.AddSeconds(intervalSeconds);
      return true;
    }).AsUnitObservable();
}​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 노트</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/52</guid>
      <comments>https://denbacodingnote.tistory.com/52#entry52comment</comments>
      <pubDate>Wed, 27 May 2026 11:45:52 +0900</pubDate>
    </item>
    <item>
      <title>[유니티 알고리즘] 슬라이딩 윈도우 알고리즘 활용</title>
      <link>https://denbacodingnote.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVoW35/dJMcahkggLo/aR9TFn14o5kfnbx73TqizK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVoW35/dJMcahkggLo/aR9TFn14o5kfnbx73TqizK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVoW35/dJMcahkggLo/aR9TFn14o5kfnbx73TqizK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVoW35%2FdJMcahkggLo%2FaR9TFn14o5kfnbx73TqizK%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;640&quot; height=&quot;336&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: center;&quot;&gt;안녕하세요, 오늘은 슬라이딩 윈도우 알고리즘을&lt;br&gt;&amp;nbsp;&lt;br&gt;게임에서 어떻게 활용하면 좋을지에 대해서 포스팅하고자 합니다.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;blockquote data-ke-style=&quot;style3&quot;&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;/ul&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;슬라이딩 윈도우 알고리즘&lt;/h3&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F2RTn/dJMcadB1hN7/CmWV1zED9237N8NGQDcKL0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F2RTn/dJMcadB1hN7/CmWV1zED9237N8NGQDcKL0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F2RTn/dJMcadB1hN7/CmWV1zED9237N8NGQDcKL0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/F2RTn/dJMcadB1hN7/CmWV1zED9237N8NGQDcKL0/img.gif&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;304&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: center;&quot;&gt;슬라이딩 윈도우 알고리즘이란 배열 내에서 연속된 구간의 범위를 순회하는 알고리즘 입니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #666666;&quot;&gt;위 그림처럼 배열에서 연속된 3개의 구간의 합이 가장 큰 부분을 찾는 과정과 같습니다.&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #666666;&quot;&gt;윈도우 슬라이딩 알고리즘을 사용해야 하는 이유는 바로 &lt;b&gt;&lt;u&gt;시간 복잡도O(n)&lt;/u&gt;&lt;/b&gt; 이라는 이점이 있기 때문입니다.&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #666666;&quot;&gt;만약, 윈도우 슬라이딩 알고리즘을 사용하지 않고 직관적으로 코드를 구현한다면 어떤 코드가 나올까요?&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;int maxSum = 0;

for (int i = 0; i &amp;lt; arr.Length - 2; i++)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int sum = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int j = i; j &amp;lt; i + 3; j++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sum += arr[j];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (sum &amp;gt; maxSum)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxSum = sum;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;br&gt;이와 같이 반복문을 2번 사용하여&lt;b&gt;&lt;u&gt; O(3n) 의 시간복잡도&lt;/u&gt;&lt;/b&gt;가 나오게 구현하고 말 것입니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;윈도우 슬라이딩 알고리즘의 경우, 연속된 구간의 윈도우를 구하고 이를 마치 슬라이딩 하듯이 구현합니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;int maxSum = 0;
int sum = 0;

// 첫 번째 윈도우 초기화
for (int i = 0; i &amp;lt; 3; i++)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sum += arr[i];
}
maxSum = sum;

// 윈도우 슬라이딩
for (int i = 1; i &amp;lt;= arr.Length - 3; i++)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sum = sum - arr[i - 1] + arr[i + 2];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (sum &amp;gt; maxSum)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxSum = sum;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;br&gt;위 코드와 같이 연속된 구간을 유지한 채 시작 부분을 끝 부분으로 이동시키는 방식입니다.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: center;&quot;&gt;이 알고리즘을 게임 개발에서는 어떻게 활용하면 좋을까요?&lt;br&gt;&amp;nbsp;&lt;br&gt;DPS 계산&lt;br&gt;&amp;nbsp;&lt;br&gt;MVP&amp;nbsp;계산&lt;br&gt;&amp;nbsp;&lt;br&gt;적&amp;nbsp;AI가&amp;nbsp;일정&amp;nbsp;간격&amp;nbsp;플레이어로&amp;nbsp;부터&amp;nbsp;피격&amp;nbsp;횟수를&amp;nbsp;이용해서&amp;nbsp;위험도&amp;nbsp;계산&lt;br&gt;&amp;nbsp;&lt;br&gt;Combo 판정 등&lt;br&gt;&amp;nbsp;&lt;br&gt;슬라이딩 윈도우 기법을 활용해서 다양한 기능을 구현할 수 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;게임 외에도 채팅 도배 감지 등에서도 사용할 수 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이 중 DPS 계산을 구현해보겠습니다.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;DPS 계산&lt;/h2&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sOAti/dJMcabdb4kf/cd8DHlFxhKFykbuzDsDMKK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sOAti/dJMcabdb4kf/cd8DHlFxhKFykbuzDsDMKK/img.gif&quot; data-alt=&quot;미리보기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sOAti/dJMcabdb4kf/cd8DHlFxhKFykbuzDsDMKK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/sOAti/dJMcabdb4kf/cd8DHlFxhKFykbuzDsDMKK/img.gif&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;447&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미리보기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;public class DPSExample : MonoBehaviour
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private TMP_Text dpsText;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private Slider dpsSlider;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private Button attackButton;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private float damage;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private float Window = 1f;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[SerializeField] private float dpsLerpTime = 0.1f;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private float _displayDPS = 0f;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private float _totalDamage = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private float _maxDps = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private readonly List&amp;lt;(float time, float damage)&amp;gt; _damages = new();


&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void Start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;attackButton.OnClickAsObservable().Subscribe(OnDamage).AddTo(this);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void Update()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float now = Time.time;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float removedDamage = 0;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_damages.RemoveAll(d =&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bool isExpired = now - d.time &amp;gt; Window;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (isExpired)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;removedDamage += d.damage;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return isExpired;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_totalDamage -= removedDamage;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float dps = _totalDamage / Window;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(dps &amp;gt; _maxDps)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_maxDps = dps;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsSlider.maxValue = _maxDps;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_displayDPS = Mathf.Lerp(_displayDPS, dps, dpsLerpTime * Time.deltaTime);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsSlider.value = _displayDPS;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsText.text = _displayDPS.ToString(&quot;N0&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void OnDamage(Unit _)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float now = Time.time;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_damages.Add((now, damage));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_totalDamage += damage;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&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;size18&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;br&gt;이게 왜 윈도우 슬라이딩 알고리즘인가 생각할 수 있지만,&lt;br&gt;&amp;nbsp;&lt;br&gt;윈도우의 중심이 배열의 Index가 아닌,&lt;br&gt;&amp;nbsp;&lt;br&gt;Time으로 변경되었을 뿐이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;값을 추가하고 시간을 중심으로 Window를 이용한 이전 값을 삭제하는 방식이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;하지만 위 코드는 약간 단점이 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;RemoveAll을 사용했기 때문이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;RemoveAll 함수는 배열 내 모든 요소를 탐색하기 때문에 무조건 최소 &lt;b&gt;&lt;u&gt;시간 복잡도O(N)&lt;/u&gt;&lt;/b&gt;가 나옵니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;시간 복잡도를 낮추기 위해서는 Queue를 활용하는 것이 좋습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void Update()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float now = Time.time;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(_damages.Count &amp;gt; 0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var oldest = _damages.Peek(); // 가장 오래된 데이터를 가져옴

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (now - oldest.time &amp;gt; Window)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_totalDamage -= oldest.damage; // 전체 데미지 감소
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_damages.Dequeue(); // Dequeue로 데이터 제거
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;float dps = _totalDamage / Window;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(dps &amp;gt; _maxDps)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_maxDps = dps;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsSlider.maxValue = _maxDps;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_displayDPS = Mathf.Lerp(_displayDPS, dps, dpsLerpTime * Time.deltaTime);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsSlider.value = _displayDPS;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dpsText.text = _displayDPS.ToString(&quot;N0&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&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;size18&quot; style=&quot;text-align: center;&quot;&gt;Queue는 먼저 들어온 값을 먼저 내보내는 FIFO 방식이고, 오래된 순의 데이터를 관리하기 좋습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이로 인해 &lt;b&gt;&lt;u&gt;최대 시간복잡도O(N)&lt;/u&gt;&lt;/b&gt;으로 최적화를 할 수 있습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: center;&quot;&gt;이상으로 윈도우 슬라이딩 알고리즘에 대해서 포스팅을 마치겠습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;figure data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;001&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/001.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/001.gif&quot; width=&quot;150&quot;&gt;&lt;/figure&gt;</description>
      <category>프로그래밍 노트/유니티 알고리즘</category>
      <category>게임 개발</category>
      <category>알고리즘</category>
      <category>유니티</category>
      <category>취미</category>
      <category>코딩</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/51</guid>
      <comments>https://denbacodingnote.tistory.com/51#entry51comment</comments>
      <pubDate>Sat, 23 May 2026 01:42:48 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트 : 프로그래머스] 노란불 신호등 C#</title>
      <link>https://denbacodingnote.tistory.com/50</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 내용&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;1366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s7sq4/dJMb99TR7i4/G9Qk0MuUOpOsje5kaqIOD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s7sq4/dJMb99TR7i4/G9Qk0MuUOpOsje5kaqIOD0/img.png&quot; data-alt=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/468371&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s7sq4/dJMb99TR7i4/G9Qk0MuUOpOsje5kaqIOD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs7sq4%2FdJMb99TR7i4%2FG9Qk0MuUOpOsje5kaqIOD0%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;1713&quot; height=&quot;1366&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;1366&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://school.programmers.co.kr/learn/courses/30/lessons/468371&lt;/figcaption&gt;
&lt;/figure&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;/h4&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;1. LCM을 활용해서 신호등 전체의 한 사이클 범위를 분석.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 나머지 계산(%)을 통해서 노란색이 사이클 내에 몇 번인지 파악하고, 이를 활용해서 노란색이 겹치는 타이밍을 계산&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;필요한 알고리즘 - LCM, GCD&lt;/h4&gt;
&lt;pre id=&quot;code_1778490738838&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // 유클리드 호제법 최대 공약수
    private int GCD(int a, int b)
    {
        while(b != 0)
        {
            int temp = a % b;
            a = b;
            b = temp;
        }
        return a;
    }

    private int LCM(int a, int b)
    {
        return a / GCD(a, b) * b;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778491695799&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	public class Solution
	{
    	public int solution(int[,] signals)
        {
        	int row = signals.GetLength(0);
            int lcm = 1;
            
            for(int i = 0; i &amp;lt; row; i++)
            {
            	int cycle = signals[i, 0] + signals[i, 1] + signals[i, 2];
                lcm = LCM(cycle, lcm); // 신호등 전체의 한 사이클을 최소 공배수로 계산
            }
            
            for(int t = 1; t &amp;lt;= lcm; t++)
            {
            	bool isAllYellow = true;
            	for(int i = 0; i &amp;lt; row; i++)
                {
                	int green = signals[i, 0];
                    int yellow = signals[i, 1];
                    int red = signals[i, 2];
                    
                    int yellowStart = green + 1;
                    int yellowEnd = green + yellow;
                    
                    int cycle = green + yellow + red;
                    int pos = t % cycle; // 각 신호등의 사이클 내에서 몇 번째인지 추출
                    if(pos == 0) // 한 사이클을 다 돌음
                    	pos = cycle;
                    
                    if(pos &amp;lt; yellowStart || pos &amp;gt; yellowEnd) // 노란색 범위 밖일 경우
                    {
                    	isAllYellow = false;
                        break;
                    }
                }
                
                if(isAllYellow) return t; // 정전 시간 반환
            }
            return -1; // 해당하지 않는 경우
        }
    }&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>프로그래밍 노트/코딩 테스트</category>
      <category>공부</category>
      <category>취미</category>
      <category>코딩</category>
      <category>코테</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/50</guid>
      <comments>https://denbacodingnote.tistory.com/50#entry50comment</comments>
      <pubDate>Mon, 11 May 2026 18:29:18 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 3D FPS 게임 구현 1  - 이동 구현 (Locomotion)</title>
      <link>https://denbacodingnote.tistory.com/49</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/du7HRh/dJMb99TDNbp/3kq21tywJTWkIIiJhKKpQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/du7HRh/dJMb99TDNbp/3kq21tywJTWkIIiJhKKpQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/du7HRh/dJMb99TDNbp/3kq21tywJTWkIIiJhKKpQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdu7HRh%2FdJMb99TDNbp%2F3kq21tywJTWkIIiJhKKpQ0%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;720&quot; height=&quot;378&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스트&lt;/p&gt;
&lt;figure id=&quot;og_1776806462251&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[유니티] 3D FPS 게임 구현 0 - 에셋 준비&quot; data-og-description=&quot;최근 원신, 명조 등의 장르 구현에만 너무 몰두한 나머지 다른 장르 구현 실력이 바닥을 치는 것을 느꼈습니다.이번에는 오랜만에 FPS 게임의 일부를 구현해볼까 합니다. 오늘의 키워드에셋 준비&quot; data-og-host=&quot;denbacodingnote.tistory.com&quot; data-og-source-url=&quot;https://denbacodingnote.tistory.com/48&quot; data-og-url=&quot;https://denbacodingnote.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f4xWP/dJMb88F7ayr/L5a2H1BUQsomSYscuK1OSk/img.png?width=800&amp;amp;height=420&amp;amp;face=0_0_800_420,https://scrap.kakaocdn.net/dn/6JtYU/dJMb88e2TVI/g5m4H7bSXnfwbDbvUWMMv1/img.png?width=800&amp;amp;height=420&amp;amp;face=0_0_800_420,https://scrap.kakaocdn.net/dn/cMGfFl/dJMb84X0YSH/EJn0jvLPU7jR8ACRhtz1h0/img.png?width=1124&amp;amp;height=764&amp;amp;face=0_0_1124_764&quot;&gt;&lt;a href=&quot;https://denbacodingnote.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://denbacodingnote.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f4xWP/dJMb88F7ayr/L5a2H1BUQsomSYscuK1OSk/img.png?width=800&amp;amp;height=420&amp;amp;face=0_0_800_420,https://scrap.kakaocdn.net/dn/6JtYU/dJMb88e2TVI/g5m4H7bSXnfwbDbvUWMMv1/img.png?width=800&amp;amp;height=420&amp;amp;face=0_0_800_420,https://scrap.kakaocdn.net/dn/cMGfFl/dJMb84X0YSH/EJn0jvLPU7jR8ACRhtz1h0/img.png?width=1124&amp;amp;height=764&amp;amp;face=0_0_1124_764');&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;[유니티] 3D FPS 게임 구현 0 - 에셋 준비&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최근 원신, 명조 등의 장르 구현에만 너무 몰두한 나머지 다른 장르 구현 실력이 바닥을 치는 것을 느꼈습니다.이번에는 오랜만에 FPS 게임의 일부를 구현해볼까 합니다. 오늘의 키워드에셋 준비&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;denbacodingnote.tistory.com&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;p data-ke-size=&quot;size16&quot;&gt;지난번에 에셋 준비를 모두 마쳤으니 이번에는 캐릭터 이동을 구현해보도록 하겠습니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&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;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;br /&gt;1. 이용할 모델링 파일 배치&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; 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;먼저 준비한 캐릭터 에셋을 맵에 배치해둡니다. Transform은 Scale 빼고 모두 0으로 초기화 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;954&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJ3Sw/dJMcahjSMvK/h2pwizG1z6gMdHdxyZTGr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJ3Sw/dJMcahjSMvK/h2pwizG1z6gMdHdxyZTGr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJ3Sw/dJMcahjSMvK/h2pwizG1z6gMdHdxyZTGr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJ3Sw%2FdJMcahjSMvK%2Fh2pwizG1z6gMdHdxyZTGr0%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;720&quot; height=&quot;569&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;954&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;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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;플레이어 기능 스크립트 설계 및 구현&lt;/h2&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;564&quot; data-origin-height=&quot;1204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crpVhj/dJMcadBFgil/Pq9zJ8kUVXudsQpfC19Pq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crpVhj/dJMcadBFgil/Pq9zJ8kUVXudsQpfC19Pq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crpVhj/dJMcadBFgil/Pq9zJ8kUVXudsQpfC19Pq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrpVhj%2FdJMcadBFgil%2FPq9zJ8kUVXudsQpfC19Pq1%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;240&quot; height=&quot;512&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;1204&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;pre id=&quot;code_1776807718760&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;InputSystem : 플랫폼/디바이스에 상관없이 입력을 추상화해서, 이벤트 기반으로 처리하는 유니티 시스템
InputManager : Input System의 입력을 받아 Observable 스트림으로 배포하는 기능
FPSPlayerController : 입력을 받아서 해석 후 각 기능으로 전파 및 관리하는 기능 
PlayerLocomotion : 플레이어의 움직임을 담당&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;INPUT SYSTEM의 Generate C# Class를 생성합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;2470&quot; data-origin-height=&quot;1060&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHgx7t/dJMcaiwf9DV/oNnDJWMgoOfKTmhZSEwBY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHgx7t/dJMcaiwf9DV/oNnDJWMgoOfKTmhZSEwBY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHgx7t/dJMcaiwf9DV/oNnDJWMgoOfKTmhZSEwBY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHgx7t%2FdJMcaiwf9DV%2FoNnDJWMgoOfKTmhZSEwBY1%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;720&quot; height=&quot;309&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsRs9c/dJMcaaLNKZ2/XGWdAIFAo5mhT7V1H1r6S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsRs9c/dJMcaaLNKZ2/XGWdAIFAo5mhT7V1H1r6S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsRs9c/dJMcaaLNKZ2/XGWdAIFAo5mhT7V1H1r6S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsRs9c%2FdJMcaaLNKZ2%2FXGWdAIFAo5mhT7V1H1r6S0%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;720&quot; height=&quot;90&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpa5zD/dJMcaaLNKZ5/kIlxYYKBGRKQGemcdiwYP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpa5zD/dJMcaaLNKZ5/kIlxYYKBGRKQGemcdiwYP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpa5zD/dJMcaaLNKZ5/kIlxYYKBGRKQGemcdiwYP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdpa5zD%2FdJMcaaLNKZ5%2FkIlxYYKBGRKQGemcdiwYP1%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;1428&quot; height=&quot;178&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;178&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;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;InputManager 구현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 InputManager는 싱글톤으로 구현해줍니다. 특히 MonoBehaviour를 상속하는 싱글톤이 아닌, 일반 class, new()의 Singleton으로 구현합니다.&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;이유는 Update, FixedUpdate 등의 함수를 이용할 이유가 없기 때문입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1776808338226&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public class InputManager : Singleton&amp;lt;InputManager&amp;gt;
    {
        private GameInput_Actions m_Actions;
        private Subject&amp;lt;Vector2&amp;gt; onMove = new();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InputSystem의 Actions를 C# 클래스로 생성했기에, 해당 클래스를&amp;nbsp; InputManager에 필드로 선언해둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 UniRx를 이용해서 Move Action의 입력값을 외부해서 받을 수 있게 OnMove Subject를 생성해둡니다.&lt;/p&gt;
&lt;pre id=&quot;code_1776808299485&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;        private void Bind(InputAction action, Action&amp;lt;InputAction.CallbackContext&amp;gt; callback, bool performed = true, bool canceled = false, bool started = false)
        {
            if (performed) action.performed += callback;
            if (canceled) action.canceled += callback;
            if (started) action.started += callback;
        }
        
        private void Unbind(InputAction action, Action&amp;lt;InputAction.CallbackContext&amp;gt; callback)
        {
            action.performed -= callback;
            action.canceled -= callback;
            action.started -= callback;
        }&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;우리가 등록한 Action에는 started, performed, canceled가 존재하기는데, 새로운 액션을 추가할 때 마다 위 내용을 다 넣기에는 반복적이고 귀찮기에 이를 함수로 묶어둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1776808462529&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        private void OnMoveInput(InputAction.CallbackContext context)
        {
            var move = context.ReadValue&amp;lt;Vector2&amp;gt;();
            onMove?.OnNext(move);
        }&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;이제 이동의 입력값을 InputAction.CallbackContext 파라미터를 통해서 받고, 이를 Vector2로 받아서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 구현한 onMove에 발행할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1776808616800&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public override UniTask Initialize()
    {
        m_Actions?.Enable();
        m_Actions?.AddTo(this);

        if (m_Actions != null)
        {
            Bind(m_Actions.Player.Move, OnMoveInput, started: false, performed: true, canceled: true);
        }
    }&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;해당 InputManager를 초기화할 때 Actions를 Enable()를 반드시 호출해줍니다. 이를 활성화하지 않으면, Input 하드웨어로 부터의 입력에 대해서 Action이 일어나지 않는다고 판단해주시면 됩니다.&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;그리고 아까 구현한 기능을 Bind해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 performed로 실시간으로 입력과 입력이 끝날 때에 대해서 액션을 구독해둡니다.&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;플레이어 컨트롤러&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;611&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OFR4w/dJMcabqp5rC/EvZgAJZG8woiHPSiziXm3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OFR4w/dJMcabqp5rC/EvZgAJZG8woiHPSiziXm3K/img.png&quot; data-alt=&quot;.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OFR4w/dJMcabqp5rC/EvZgAJZG8woiHPSiziXm3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOFR4w%2FdJMcabqp5rC%2FEvZgAJZG8woiHPSiziXm3K%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;720&quot; height=&quot;305&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;611&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;PlayerController는 MonoBehaviour를 상속하는 스크립트로 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Start 함수에서 아까 호출했던 InputManager에 접근해서 OnMove에 OnMove를 구독합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;967&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCIbR4/dJMcaib0RnK/zJMZEcApS2EzfTLG4LMm91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCIbR4/dJMcaib0RnK/zJMZEcApS2EzfTLG4LMm91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCIbR4/dJMcaib0RnK/zJMZEcApS2EzfTLG4LMm91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCIbR4%2FdJMcaib0RnK%2FzJMZEcApS2EzfTLG4LMm91%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;720&quot; height=&quot;617&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;967&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;p data-ke-size=&quot;size16&quot;&gt;InputContext를 struct로 가볍게 만들어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 PlayerController에 필요한 필드를 하나씩 만들어 갔지만, 이렇게 하면 막상 필요한 필드를 하나씩 가져와야 하는 불편함이 있습니다.&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;그래서 위와 같이 Context로서 하나로 묶고 각 기능의 로직으로 이를 전달하는 방식을 채택했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;PlayerLocomotion&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;787&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rQCB9/dJMb99MQMbz/cEHf1iFklFo3KxzDR7iZkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rQCB9/dJMb99MQMbz/cEHf1iFklFo3KxzDR7iZkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rQCB9/dJMb99MQMbz/cEHf1iFklFo3KxzDR7iZkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrQCB9%2FdJMb99MQMbz%2FcEHf1iFklFo3KxzDR7iZkk%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;720&quot; height=&quot;638&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;787&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 방식은 진짜 구현하는 방법이 다양하지만 대표적으로는 &lt;b&gt;Rigidbody&lt;/b&gt;와 &lt;b&gt;CharacterController&lt;/b&gt;가 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 굳이 물리적인 처리가 크게 필요하지 않기 때문에 CharacterController를 사용하겠습니다.&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;PlayerLocomotion&lt;/b&gt;은 MonoBehaviour를 상속하지 않고 일반 C# 클래스로 구현했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간 기반 호출을 하려면 Update, FixedUpdate, LateUpdate 등을 사용해야 하지만, MonoBehaviour를 상속시켜 해당 스크립트 내에서 처리하면, 각 기능별 호출 타이밍을 개발자가 마음대로 조절할 수 없습니다.&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;예를들어서, Locomotion의 Update 함수가 맨마지막에 호출되고 StateMachine의 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Update&lt;span&gt; &lt;/span&gt;&lt;/span&gt;함수가 호출되게 하고 싶을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MonoBehaviour 내의 Update 함수로 제어를 가능한가? 라고 질문하면 그건 운적으로 그렇게 호출될 가능성은 있어도 제어는 불가능합니다.&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;Script Execution Order&lt;/b&gt;를 사용하면 제어는 할 수 있지만, 복잡하고 확장성이 떨어진다고 생각합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-turn-start-message=&quot;true&quot; data-message-model-slug=&quot;gpt-5-3&quot; data-message-id=&quot;b1e12cc0-ecde-4232-bf16-3adcabbbbd5a&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;88&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;하지만 PlayerController의 Update 내부에서 실행할 함수를 직접 지정하도록 구성하면, 실행 순서를 비교적 간단하게 제어할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1776810450290&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void Update()
    {
        _stateMachine?.LogicUpdate();
    	_weapon?.LogicUpdate();    
    	_locomotion?.LogicUpdate(deltaTime, _inputContext);
    }&lt;/code&gt;&lt;/pre&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;937&quot; data-origin-height=&quot;1546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b89HGx/dJMcafM8ieR/9pQZC1VrFCzFiAl5kiAjY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b89HGx/dJMcafM8ieR/9pQZC1VrFCzFiAl5kiAjY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b89HGx/dJMcafM8ieR/9pQZC1VrFCzFiAl5kiAjY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb89HGx%2FdJMcafM8ieR%2F9pQZC1VrFCzFiAl5kiAjY0%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;720&quot; height=&quot;1188&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;1546&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;스크립트 구현이 완료되었으니 캐릭터 오브젝트에 해당 컴포넌트를 부착하고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;CharacterController 필드를 할당해줍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&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;639&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m74c6/dJMcaiXjoGw/LxOK5D0tNZmRQ47uQ7UcC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m74c6/dJMcaiXjoGw/LxOK5D0tNZmRQ47uQ7UcC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m74c6/dJMcaiXjoGw/LxOK5D0tNZmRQ47uQ7UcC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm74c6%2FdJMcaiXjoGw%2FLxOK5D0tNZmRQ47uQ7UcC0%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;720&quot; height=&quot;967&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;858&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;결과 확인&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;move.gif&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQos2q/dJMcafTSxbm/V6AJBmMr1nWR9ZPDElWp1k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQos2q/dJMcafTSxbm/V6AJBmMr1nWR9ZPDElWp1k/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQos2q/dJMcafTSxbm/V6AJBmMr1nWR9ZPDElWp1k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dQos2q/dJMcafTSxbm/V6AJBmMr1nWR9ZPDElWp1k/img.gif&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;962&quot; height=&quot;538&quot; data-filename=&quot;move.gif&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;538&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;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;</description>
      <category>프로그래밍 노트</category>
      <category>개발</category>
      <category>게임</category>
      <category>공부</category>
      <category>유니티</category>
      <category>취미</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/49</guid>
      <comments>https://denbacodingnote.tistory.com/49#entry49comment</comments>
      <pubDate>Wed, 22 Apr 2026 07:46:17 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 3D FPS 게임 구현 0 - 에셋 준비</title>
      <link>https://denbacodingnote.tistory.com/48</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QGvO0/dJMcaib0Qq4/dDqQoPXEyES5shzCkipDvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QGvO0/dJMcaib0Qq4/dDqQoPXEyES5shzCkipDvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QGvO0/dJMcaib0Qq4/dDqQoPXEyES5shzCkipDvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQGvO0%2FdJMcaib0Qq4%2FdDqQoPXEyES5shzCkipDvK%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;720&quot; height=&quot;378&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&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;p data-ke-size=&quot;size16&quot;&gt;최근 원신, 명조 등의 장르 구현에만 너무 몰두한 나머지 다른 장르 구현 실력이 바닥을 치는 것을 느꼈습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 오랜만에 FPS 게임의 일부를 구현해볼까 합니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&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;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&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;/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;1124&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dH0uEl/dJMcajaRbVK/Lcdh7VC0KcybGOx7E1LVh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dH0uEl/dJMcajaRbVK/Lcdh7VC0KcybGOx7E1LVh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dH0uEl/dJMcajaRbVK/Lcdh7VC0KcybGOx7E1LVh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdH0uEl%2FdJMcajaRbVK%2FLcdh7VC0KcybGOx7E1LVh0%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;720&quot; height=&quot;489&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;764&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;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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BIPER 라는 분이 제작하는 에셋을 즐겨 사용하며, 이번 세일에 구입했기에 사용했습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7cAny/dJMcagFgLqp/xBdKfc7TvtnRbKnT18bBkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7cAny/dJMcagFgLqp/xBdKfc7TvtnRbKnT18bBkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7cAny/dJMcagFgLqp/xBdKfc7TvtnRbKnT18bBkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7cAny%2FdJMcagFgLqp%2FxBdKfc7TvtnRbKnT18bBkK%2Fimg.jpg&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;720&quot; height=&quot;480&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776805722796&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;CombatGirls_RifleCharacterPack | 캐릭터 | Unity Asset Store&quot; data-og-description=&quot;Get the CombatGirls_RifleCharacterPack package from BIPER and speed up your game development process. Find this &amp;amp; other 캐릭터 options on the Unity Asset Store.&quot; data-og-host=&quot;assetstore.unity.com&quot; data-og-source-url=&quot;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&quot; data-og-url=&quot;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJVYxk/dJMb9b3UhXa/6bYlJPi1x4hcB2a8KfexRk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bYsjYk/dJMb9cBKkgp/Z09RqoCvAj04VJXVKfsT1K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assetstore.unity.com/packages/3d/characters/humanoids/humans/combatgirls-riflecharacterpack-305180&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJVYxk/dJMb9b3UhXa/6bYlJPi1x4hcB2a8KfexRk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bYsjYk/dJMb9cBKkgp/Z09RqoCvAj04VJXVKfsT1K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;CombatGirls_RifleCharacterPack | 캐릭터 | Unity Asset Store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get the CombatGirls_RifleCharacterPack package from BIPER and speed up your game development process. Find this &amp;amp; other 캐릭터 options on the Unity Asset Store.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assetstore.unity.com&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;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발사 시 보이는 총구 섬광(Muzzle Flash)과 피격 시 발생하는 Hit Effect (Blood)는 놀랍게도 구매해둔 에셋이 없기에 무료 에셋을 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;피격 이펙트&lt;/h4&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;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kTk0x/dJMcacbLMz1/veJLj7w7fsb3DCXD0Aayqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTk0x/dJMcacbLMz1/veJLj7w7fsb3DCXD0Aayqk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTk0x/dJMcacbLMz1/veJLj7w7fsb3DCXD0Aayqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTk0x%2FdJMcacbLMz1%2FveJLj7w7fsb3DCXD0Aayqk%2Fimg.jpg&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;720&quot; height=&quot;480&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776805962860&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;VFX - Impact and Hit - Light Version | 시각 효과 파티클 | Unity Asset Store&quot; data-og-description=&quot;Add depth to your next project with VFX - Impact and Hit - Light Version from Cartoon VFX by Wallcoeur. Find this &amp;amp; more 시각 효과 파티클 on the Unity Asset Store.&quot; data-og-host=&quot;assetstore.unity.com&quot; data-og-source-url=&quot;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&quot; data-og-url=&quot;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6Pk4Q/dJMb8XR7U88/zqdRlF0CWsZPcLcptT122k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/4vN3E/dJMb8SpKbPk/FIJ6stf9ZAHIGEiklBjrK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assetstore.unity.com/packages/vfx/particles/vfx-impact-and-hit-light-version-335800&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6Pk4Q/dJMb8XR7U88/zqdRlF0CWsZPcLcptT122k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/4vN3E/dJMb8SpKbPk/FIJ6stf9ZAHIGEiklBjrK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;VFX - Impact and Hit - Light Version | 시각 효과 파티클 | Unity Asset Store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Add depth to your next project with VFX - Impact and Hit - Light Version from Cartoon VFX by Wallcoeur. Find this &amp;amp; more 시각 효과 파티클 on the Unity Asset Store.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assetstore.unity.com&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;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;총구 섬광(Muzzle Flash)&lt;/h4&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;1280&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U8dzS/dJMcaib0QDw/mmLZlcIVDA0iIJ6GXyos7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U8dzS/dJMcaib0QDw/mmLZlcIVDA0iIJ6GXyos7k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U8dzS/dJMcaib0QDw/mmLZlcIVDA0iIJ6GXyos7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU8dzS%2FdJMcaib0QDw%2FmmLZlcIVDA0iIJ6GXyos7k%2Fimg.jpg&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;720&quot; height=&quot;480&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776806051926&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;Free Quick Effects Vol. 1 | 시각 효과 파티클 | Unity Asset Store&quot; data-og-description=&quot;Add depth to your next project with Free Quick Effects Vol. 1 from Gabriel Aguiar Prod. Find this &amp;amp; more 시각 효과 파티클 on the Unity Asset Store.&quot; data-og-host=&quot;assetstore.unity.com&quot; data-og-source-url=&quot;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&quot; data-og-url=&quot;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jd1eZ/dJMb9hC3wd8/RwOmmennnKqPWSK6CxOgH0/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300,https://scrap.kakaocdn.net/dn/bsMovy/dJMb9lMdJyg/duSzRsvsNhdDdBPKyiyviK/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assetstore.unity.com/packages/vfx/particles/free-quick-effects-vol-1-304424&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jd1eZ/dJMb9hC3wd8/RwOmmennnKqPWSK6CxOgH0/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300,https://scrap.kakaocdn.net/dn/bsMovy/dJMb9lMdJyg/duSzRsvsNhdDdBPKyiyviK/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300');&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;Free Quick Effects Vol. 1 | 시각 효과 파티클 | Unity Asset Store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Add depth to your next project with Free Quick Effects Vol. 1 from Gabriel Aguiar Prod. Find this &amp;amp; more 시각 효과 파티클 on the Unity Asset Store.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assetstore.unity.com&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;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;총 사운드&lt;/h4&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;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CNYwB/dJMcaffiVJ3/MS82gOynxX6K4fKiBnNYT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CNYwB/dJMcaffiVJ3/MS82gOynxX6K4fKiBnNYT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CNYwB/dJMcaffiVJ3/MS82gOynxX6K4fKiBnNYT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCNYwB%2FdJMcaffiVJ3%2FMS82gOynxX6K4fKiBnNYT1%2Fimg.jpg&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;720&quot; height=&quot;480&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776806216264&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;Sci-Fi Weapons: Bullet Hell Sound Effects Pack | 음향 효과음 | Unity Asset Store&quot; data-og-description=&quot;Layer in the sounds of Sci-Fi Weapons: Bullet Hell Sound Effects Pack from SwishSwoosh for your next project. Browse all audio options on the Unity Asset Store.&quot; data-og-host=&quot;assetstore.unity.com&quot; data-og-source-url=&quot;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&quot; data-og-url=&quot;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WiMvH/dJMb8U8VOAx/HhuKiO2j68sqe0iWWfGQA1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/doMJyz/dJMb8SXz0ox/5NzezKH2YXnLf3HOLRQiB0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assetstore.unity.com/packages/audio/sound-fx/sci-fi-weapons-bullet-hell-sound-effects-pack-271305&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WiMvH/dJMb8U8VOAx/HhuKiO2j68sqe0iWWfGQA1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/doMJyz/dJMb8SXz0ox/5NzezKH2YXnLf3HOLRQiB0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;Sci-Fi Weapons: Bullet Hell Sound Effects Pack | 음향 효과음 | Unity Asset Store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Layer in the sounds of Sci-Fi Weapons: Bullet Hell Sound Effects Pack from SwishSwoosh for your next project. Browse all audio options on the Unity Asset Store.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assetstore.unity.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;해당 에셋들을 가지고 3D FPS 게임 기능을 일부 구현해보겠습니다.&lt;/p&gt;</description>
      <category>프로그래밍 노트</category>
      <category>FPS</category>
      <category>게임 개발</category>
      <category>공부</category>
      <category>유니티</category>
      <category>취미</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/48</guid>
      <comments>https://denbacodingnote.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 22 Apr 2026 06:19:17 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 컴파일링(Compiling)과 어셈블리 정의 (Assembly Definition)</title>
      <link>https://denbacodingnote.tistory.com/47</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP5ZDv/dJMcaibWlhz/AR2mGNV8XacI5jhMJR3KiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP5ZDv/dJMcaibWlhz/AR2mGNV8XacI5jhMJR3KiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP5ZDv/dJMcaibWlhz/AR2mGNV8XacI5jhMJR3KiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP5ZDv%2FdJMcaibWlhz%2FAR2mGNV8XacI5jhMJR3KiK%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;720&quot; height=&quot;378&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&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;li&gt;Assembly&lt;/li&gt;
&lt;li&gt;IL&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;p style=&quot;text-align: center;&quot; 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;b&gt;Assembly Definition&lt;/b&gt;에 대해서 공부해보고자 합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; 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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;컴파일링&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일링이란 우리가 고급 언어(C#, C++, Java 등)로 작성한 &lt;b&gt;소스코드&lt;/b&gt;를 컴퓨터가 실행할 수 있는 (IL/DLL)로 변환하는 작업입니다.&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-filename=&quot;image.gif&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I8IaY/dJMcahD3l9O/Pz7WPV4kNoFE9Kd2ZUOhk1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I8IaY/dJMcahD3l9O/Pz7WPV4kNoFE9Kd2ZUOhk1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I8IaY/dJMcahD3l9O/Pz7WPV4kNoFE9Kd2ZUOhk1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/I8IaY/dJMcahD3l9O/Pz7WPV4kNoFE9Kd2ZUOhk1/img.gif&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;628&quot; data-filename=&quot;image.gif&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;628&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caMayG/dJMcaaLJiyn/1fqJvTNZJKclSPhbCKfdfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caMayG/dJMcaaLJiyn/1fqJvTNZJKclSPhbCKfdfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caMayG/dJMcaaLJiyn/1fqJvTNZJKclSPhbCKfdfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaMayG%2FdJMcaaLJiyn%2F1fqJvTNZJKclSPhbCKfdfk%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;1248&quot; height=&quot;117&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;117&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;p data-ke-size=&quot;size16&quot;&gt;참고로 유니티에서의 컴파일링 방식은 2가지가 존재합니다.&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MONO&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwHB4h/dJMcadO9rk5/Dg3qzmazksNFC3DeADQ3a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwHB4h/dJMcadO9rk5/Dg3qzmazksNFC3DeADQ3a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwHB4h/dJMcadO9rk5/Dg3qzmazksNFC3DeADQ3a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwHB4h%2FdJMcadO9rk5%2FDg3qzmazksNFC3DeADQ3a0%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;720&quot; height=&quot;95&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;IL2CPP&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLye9j/dJMcacQiHzz/rRzmkkT4PdkGZEQNrFDTS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLye9j/dJMcacQiHzz/rRzmkkT4PdkGZEQNrFDTS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLye9j/dJMcacQiHzz/rRzmkkT4PdkGZEQNrFDTS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLye9j%2FdJMcacQiHzz%2FrRzmkkT4PdkGZEQNrFDTS0%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;720&quot; height=&quot;95&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;244&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;p data-ke-size=&quot;size16&quot;&gt;또한 위 프로세스 다이얼로그를 살펴보면 크게 &lt;b&gt;4가지 정도&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;1848&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bivWMw/dJMcagrCUes/nhOy0CMvmkAYVIPXwjXeLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bivWMw/dJMcagrCUes/nhOy0CMvmkAYVIPXwjXeLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bivWMw/dJMcagrCUes/nhOy0CMvmkAYVIPXwjXeLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbivWMw%2FdJMcagrCUes%2FnhOy0CMvmkAYVIPXwjXeLK%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;720&quot; height=&quot;97&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;248&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;컴파일을 통해 C# 코드를 IL 코드와 메타데이터를 포함한 어셈블리(DLL)로 생성하고, 이를 로드하여 메모리에 올립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후, 유니티의 도메인 환경을 초기화합니다.&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;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;어셈블리&lt;/h2&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;/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;390&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1X7O/dJMcad2G4b7/VRl8eZltIlEB0mluSzzwe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1X7O/dJMcad2G4b7/VRl8eZltIlEB0mluSzzwe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1X7O/dJMcad2G4b7/VRl8eZltIlEB0mluSzzwe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv1X7O%2FdJMcad2G4b7%2FVRl8eZltIlEB0mluSzzwe0%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;390&quot; height=&quot;399&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;399&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;p data-ke-size=&quot;size16&quot;&gt;유니티에서의 어셈블리는 .NET 환경의 코드 묶음을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 코드를 하나로 묶은 배포 단위 (DLL / EXE) 라고 생각하면 됩니다.&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;Assembly-CSharp.dll&lt;/b&gt;에 합쳐져서 어셈블리 단위로 컴파일링이 일어납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, Editor 라는 폴더를 생성하고 해당 폴더에서 작성한 스크립트는 기본적으로 &lt;b&gt;Assembly-CSharp.Editor.dll&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;Editor 관련 코드는 빌드할 수 없기 때문에, 툴을 개발할 때는 기본적으로 Editor 폴더를 만들면 빌드 시 걱정이 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 시 &lt;b&gt;Assembly-CSharp.Editor.dll 컴파일링&lt;/b&gt;은 동작하지 않기 때문입니다.&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;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;어셈블리 정의 (Assembly Definition)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급했듯이, 개발자가 Editor 폴더 또는 그 외에 생성한 스크립트는 모두 &lt;b&gt;Assembly-CSharp.dll&lt;/b&gt;과&lt;b&gt;Assembly-CSharp.Editor.dll&lt;/b&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;작은 프로젝트의 경우에는 크게 영향이 없지만, 큰 프로젝트의 경우는 대량의 게임 로직, 데이터 로직, 툴 등의 스크립트가 존재하기 합니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스크립트가 많을 수록 컴파일링 시간은 길어집니다&lt;/b&gt;&lt;/span&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;예를 들어, 유저가 단순히 변수명을 변경하는 것과 같은 작은 수정만 하더라도, Assembly-CSharp.dll과 Assembly-CSharp-Editor.dll에 포함된 모든 코드가 다시 컴파일됩니다. 이로 인해 컴파일 시간이 길어지고, 전체적인 작업 속도가 저하되는 문제가 발생할 수 있습니다.&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는 기본적으로 모든 스크립트를 하나의 어셈블리로 자동으로 묶지만,&lt;b&gt; Assembly Definition Asset&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;890&quot; data-origin-height=&quot;1060&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEYOwC/dJMcafGgYpw/ZwzhOlWEbaImmewpJNviO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEYOwC/dJMcafGgYpw/ZwzhOlWEbaImmewpJNviO0/img.png&quot; data-alt=&quot;어셈블리 정의 생성 위치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEYOwC/dJMcafGgYpw/ZwzhOlWEbaImmewpJNviO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEYOwC%2FdJMcafGgYpw%2FZwzhOlWEbaImmewpJNviO0%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;720&quot; height=&quot;858&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;1060&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;유니티 6 기준으로 Create -&amp;gt; Scripting -&amp;gt; Assembly Definition을 통해서 어셈블리 정의 에셋을 생성할 수 있습니다.&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;929&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFUwYx/dJMcagSIg3L/7eDVdU718kpy1BpeWVOo91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFUwYx/dJMcagSIg3L/7eDVdU718kpy1BpeWVOo91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFUwYx/dJMcagSIg3L/7eDVdU718kpy1BpeWVOo91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFUwYx%2FdJMcagSIg3L%2F7eDVdU718kpy1BpeWVOo91%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;929&quot; height=&quot;33&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;1217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qG1hW/dJMcahD3nlM/CCN3IgCmaHoTcpacMgJzG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qG1hW/dJMcahD3nlM/CCN3IgCmaHoTcpacMgJzG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qG1hW/dJMcahD3nlM/CCN3IgCmaHoTcpacMgJzG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqG1hW%2FdJMcahD3nlM%2FCCN3IgCmaHoTcpacMgJzG1%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;720&quot; height=&quot;1210&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;1217&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;p data-ke-size=&quot;size16&quot;&gt;어셈블리 정의 에셋을 생성하면 Inspector에서 &lt;b&gt;어셈블리명&lt;/b&gt;과 &lt;b&gt;NameSpace의 Root명&lt;/b&gt;, &lt;b&gt;참조 가능한 Assembly Definition&lt;/b&gt;, &lt;b&gt;사용 범위를 정하는 Platforms&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;이를 사용해서 스크립트들을 어셈블리 정의를 통해서 분리하면 컴파일링 속도, 의존성 관리, Editor / Runtime 분리가 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;주의점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Assembly Definition References에 각 정의를 참조시킬 때, 의존성을 고려하여 연결해야 합니다.&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;예를 들어서 Assembly Definition을 3가지 생성했다고 가정해보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Editor&lt;/li&gt;
&lt;li&gt;Runtime&lt;/li&gt;
&lt;li&gt;Data&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Editor -&amp;gt; Runtime, Data&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime -&amp;gt; Data&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data -&amp;gt; Editor, Runtime&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;209&quot; data-start=&quot;66&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 참조를 설정할 경우, Data &amp;rarr; Editor &amp;rarr; Runtime &amp;rarr; Data와 같은 순환 참조가 발생하게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;209&quot; data-start=&quot;66&quot; data-ke-size=&quot;size16&quot;&gt;이러한 순환 구조는 컴파일 순서를 결정할 수 없게 만들어, 컴파일 에러를 유발하거나 예상치 못한 동작을 일으킬 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;375&quot; data-start=&quot;216&quot; data-ke-size=&quot;size16&quot;&gt;따라서 Assembly Definition을 설계할 때는 의존성이 한 방향으로만 흐르도록 구성하는 것이 중요합니다.&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 노트</category>
      <category>공부</category>
      <category>유니티</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/47</guid>
      <comments>https://denbacodingnote.tistory.com/47#entry47comment</comments>
      <pubDate>Thu, 16 Apr 2026 00:01:07 +0900</pubDate>
    </item>
    <item>
      <title>[유니티 셰이더] 툰셰이더 기초 1 - Lambert BRDF</title>
      <link>https://denbacodingnote.tistory.com/46</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJq3Ub/dJMcaiv84eM/ztUjJFXvZqZ6HHAkG0urvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJq3Ub/dJMcaiv84eM/ztUjJFXvZqZ6HHAkG0urvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJq3Ub/dJMcaiv84eM/ztUjJFXvZqZ6HHAkG0urvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJq3Ub%2FdJMcaiv84eM%2FztUjJFXvZqZ6HHAkG0urvK%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;720&quot; height=&quot;378&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&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;style3&quot;&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;Lambert&lt;/li&gt;
&lt;li&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;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;또한 이러한 툰 셰이더를 활용한 버튜버 또한 매우 인기가 있죠.&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;a title=&quot;닐로툰&quot; href=&quot;https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;닐로툰&lt;/a&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;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cspEC1/dJMcadBytaJ/OgghTpPEKsmMXnTJDhzds0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cspEC1/dJMcadBytaJ/OgghTpPEKsmMXnTJDhzds0/img.jpg&quot; data-alt=&quot;닐로툰 깃허브 소개 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cspEC1/dJMcadBytaJ/OgghTpPEKsmMXnTJDhzds0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcspEC1%2FdJMcadBytaJ%2FOgghTpPEKsmMXnTJDhzds0%2Fimg.jpg&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;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;게임 개발에 있어서 데이터 관리, 로직 구현도 중요하지만, 시각적인 부분도 빠질 수 없는 만큼, 셰이더에 대해서 공부하기 해볼까 합니다.&lt;/p&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;style3&quot;&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;a href=&quot;https://www.youtube.com/watch?v=6qCYaGne8H8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이득우 님의 셰이더 강의 영상&lt;/a&gt;을 참고해서 공부를 했습니다.&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;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;툰 셰이더 Toon Shader&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;툰 셰이더는 Lambert 방식으로 계산된 빛을 단순하게 나눠서(계단화해서), 만화처럼 딱 끊기는 명암을 만드는 방식입니다.&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;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzSpSB/dJMcac3LSmN/1u8jc6weBrQ77oK8sClE4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzSpSB/dJMcac3LSmN/1u8jc6weBrQ77oK8sClE4K/img.png&quot; data-alt=&quot;유니티 툰 셰이더 설명 페이지 공식 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzSpSB/dJMcac3LSmN/1u8jc6weBrQ77oK8sClE4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzSpSB%2FdJMcac3LSmN%2F1u8jc6weBrQ77oK8sClE4K%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;361&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;361&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;&lt;br /&gt;따라서 툰 셰이더는 현실처럼 부드러운 빛과 그림자가 표현되지 않고, 밝은 부분과 어두운 부분이 명확하게 나뉘어 표현됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1517&quot; data-origin-height=&quot;487&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LyVBv/dJMcac3LSCx/GkwqsVsVmDQTDzAZ1kie11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LyVBv/dJMcac3LSCx/GkwqsVsVmDQTDzAZ1kie11/img.png&quot; data-alt=&quot;(좌)Lil Toon Shader (우)URP Lit Shader&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LyVBv/dJMcac3LSCx/GkwqsVsVmDQTDzAZ1kie11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLyVBv%2FdJMcac3LSCx%2FGkwqsVsVmDQTDzAZ1kie11%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;1517&quot; height=&quot;487&quot; data-origin-width=&quot;1517&quot; data-origin-height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(좌)Lil Toon Shader (우)URP Lit Shader&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;Lambert (람베르트) 반사&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRbjc2/dJMcaarn9Wu/ajZxE8y0S8MZds5lA6YVlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRbjc2/dJMcaarn9Wu/ajZxE8y0S8MZds5lA6YVlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRbjc2/dJMcaarn9Wu/ajZxE8y0S8MZds5lA6YVlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRbjc2%2FdJMcaarn9Wu%2FajZxE8y0S8MZds5lA6YVlK%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;1024&quot; height=&quot;486&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;486&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람베르트(Lambert) 반사&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;Lambert BRDF&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;1096&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK2Btp/dJMcagyk0M6/rvXxyc2IkRpf7xNoLDQRE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK2Btp/dJMcagyk0M6/rvXxyc2IkRpf7xNoLDQRE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK2Btp/dJMcagyk0M6/rvXxyc2IkRpf7xNoLDQRE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK2Btp%2FdJMcagyk0M6%2FrvXxyc2IkRpf7xNoLDQRE0%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;1096&quot; height=&quot;741&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;밝기 = N &amp;middot; L = cos &amp;theta;&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;앞서 살펴봤듯이, Lambert 반사에서 표면의 밝기는 빛이 닿는 각도, 즉 &lt;b&gt;법선 벡터 N과 빛 방향 벡터 L의 내적&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;theta;값을 알기 위해서 Acos을 이용하여 계산을 하지만, Acos는 연산 비용이 크기 때문에, 게임에서는 이를 위해서 내적 (Dot)을 사용합니다.&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;Shader Graph&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;1116&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DoLwv/dJMb99TwTQ6/QYP6pemAXxT8RFCnNhEzd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DoLwv/dJMb99TwTQ6/QYP6pemAXxT8RFCnNhEzd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DoLwv/dJMb99TwTQ6/QYP6pemAXxT8RFCnNhEzd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDoLwv%2FdJMb99TwTQ6%2FQYP6pemAXxT8RFCnNhEzd1%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;1116&quot; height=&quot;642&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;642&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;오브젝트 -&amp;gt; 빛 방향 계산&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uLUDv/dJMcah47nzo/tAXfgJCLTYZWtnpBPgxkGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uLUDv/dJMcah47nzo/tAXfgJCLTYZWtnpBPgxkGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uLUDv/dJMcah47nzo/tAXfgJCLTYZWtnpBPgxkGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuLUDv%2FdJMcah47nzo%2FtAXfgJCLTYZWtnpBPgxkGK%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;769&quot; height=&quot;287&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;287&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;p data-ke-size=&quot;size16&quot;&gt;빛의 방향을 출력하는 Main Light Direction 노드가 있지만, 이는 빛 -&amp;gt; 오브젝트의 방향을 출력하기에, Negate를 이용해서 해당값을 반전시켜줍니다.&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;gt; 빛의 방향을 계산해낼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;법선 벡터 N&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZmQ6o/dJMcahKOQfH/a60JnKpLEY5KRh4CMmDSb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZmQ6o/dJMcahKOQfH/a60JnKpLEY5KRh4CMmDSb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZmQ6o/dJMcahKOQfH/a60JnKpLEY5KRh4CMmDSb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZmQ6o%2FdJMcahKOQfH%2Fa60JnKpLEY5KRh4CMmDSb1%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;651&quot; height=&quot;331&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;331&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;p data-ke-size=&quot;size16&quot;&gt;법선 벡터 N의 경우, Normal Vector 노드를 통해서 출력해낼 수 있습니다.&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;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;Dot(N, L)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qpJwZ/dJMcagrAn5x/KaKvBCqWC6rjZH5C0wP95K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qpJwZ/dJMcagrAn5x/KaKvBCqWC6rjZH5C0wP95K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qpJwZ/dJMcagrAn5x/KaKvBCqWC6rjZH5C0wP95K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqpJwZ%2FdJMcagrAn5x%2FKaKvBCqWC6rjZH5C0wP95K%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;978&quot; height=&quot;485&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;485&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;p data-ke-size=&quot;size16&quot;&gt;두 벡터의 내적을 계산해냅니다. 내적 계산은 Dot Product 노드를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;색 반영&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XaIKA/dJMcabcIRLI/LXGQRBW5kH1165QzA78nm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XaIKA/dJMcabcIRLI/LXGQRBW5kH1165QzA78nm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XaIKA/dJMcabcIRLI/LXGQRBW5kH1165QzA78nm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXaIKA%2FdJMcabcIRLI%2FLXGQRBW5kH1165QzA78nm1%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;804&quot; height=&quot;387&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;387&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;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Dot 출력 값과 프로퍼티로 뺀 컬러의 출력값을 Multiply 노드로 곱해서 BaseColor에 반영해줍니다.&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;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;결과&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;778&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQ6yfR/dJMcahRyAiN/BcLpZ6IEp5W52zdNrKiSaK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQ6yfR/dJMcahRyAiN/BcLpZ6IEp5W52zdNrKiSaK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQ6yfR/dJMcahRyAiN/BcLpZ6IEp5W52zdNrKiSaK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cQ6yfR/dJMcahRyAiN/BcLpZ6IEp5W52zdNrKiSaK/img.gif&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;1116&quot; height=&quot;778&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;778&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 노트/셰이더</category>
      <category>셰이더</category>
      <category>유니티</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/46</guid>
      <comments>https://denbacodingnote.tistory.com/46#entry46comment</comments>
      <pubDate>Sun, 12 Apr 2026 21:59:43 +0900</pubDate>
    </item>
    <item>
      <title>유니티 VirtualCamera가 Live 상태로 변하지 않는 문제</title>
      <link>https://denbacodingnote.tistory.com/45</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcV6qA/dJMcab3GXto/GYTLgk861aWz3hoKHPzz81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcV6qA/dJMcab3GXto/GYTLgk861aWz3hoKHPzz81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcV6qA/dJMcab3GXto/GYTLgk861aWz3hoKHPzz81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcV6qA%2FdJMcab3GXto%2FGYTLgk861aWz3hoKHPzz81%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;1200&quot; height=&quot;630&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;오늘의 키워드&lt;/blockquote&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; 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;CinemachineVirtualCamera&lt;/li&gt;
&lt;li&gt;CinemachineBrain&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;h4 data-ke-size=&quot;size20&quot;&gt;발생한 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CinemachineVirtualCamera의 상태가 Standby가 아닌 Live로 변하지 않아서 CinemachineBrain이 해당 VirtualCamera를 따라가지 않는 문제가 발생&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;CinemachineBrain이 있는 오브젝트에 부착된 Camera Component의 CullingMask에 Default가 체크되지 않으면 VirtualCamera가 켜져도 인식을 못하는 것을 발견&lt;/p&gt;</description>
      <category>프로그래밍 노트</category>
      <category>유니티</category>
      <category>트러블슈팅</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/45</guid>
      <comments>https://denbacodingnote.tistory.com/45#entry45comment</comments>
      <pubDate>Sun, 23 Nov 2025 23:54:09 +0900</pubDate>
    </item>
    <item>
      <title>유니티 C#, C++ 그리고 Null</title>
      <link>https://denbacodingnote.tistory.com/44</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G8FTI/btsOWFTtb0W/cA4tlQUA7dyVSC2glI5FT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G8FTI/btsOWFTtb0W/cA4tlQUA7dyVSC2glI5FT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G8FTI/btsOWFTtb0W/cA4tlQUA7dyVSC2glI5FT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG8FTI%2FbtsOWFTtb0W%2FcA4tlQUA7dyVSC2glI5FT0%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;1200&quot; height=&quot;630&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&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;유니티와 C++의 관계&lt;/li&gt;
&lt;li&gt;Null 처리의 중요성&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;유니티와 C++의 관계&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기본적으로 유니티는 C#을 사용하기 때문에 당연하게 C++과는 관계 없을 거라고 생각할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 Unity 엔진의 코어(렌더링, 물리, 오디오, 메모리 관리 등)은 C++로 구현되어 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 왜 우리는 C++로 이루어진 엔진을 C#으로 코딩을 할까? 라는 의문이 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이유는 C#이 생산성, 유지보수, 개발 속도가 매우 높은 반면,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;C++은 메모리 버그가 많고, 개발 속도가 느리며, 가독성 생산성이 낮다고 판단되기 때문입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;특히, C++은 컴파일과 링크 시간이 길기 때문에 게임 엔진 개발로서는 부적합하다고 판단했다 생각합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Null 처리의 중요성&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;
&lt;p data-end=&quot;115&quot; data-start=&quot;81&quot; data-ke-size=&quot;size18&quot;&gt;댕글링 포인터(Dangling Pointer)란?&lt;/p&gt;
&lt;p data-end=&quot;124&quot; data-start=&quot;117&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;br /&gt;정의:&lt;br /&gt;&lt;/b&gt;이미 해제되거나 유효하지 않은 메모리를 가리키고 있는 포인터&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이 현상은 유니티에서 실제로 쉽게 볼 수 있는 현상입니다.&lt;br /&gt;&lt;br /&gt;예시를 들자면, GameObject 입니다.&lt;br /&gt;&lt;br /&gt;아까 위에서 언급했듯이, 유니티 엔진의 코어 기능들은 C++로 구현되어 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751216533142&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GameObject obj = new GameObject();&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; 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;1444&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6nemV/btsOXjitnmN/ZYkCaEEDlSeJqbgYCSrNKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6nemV/btsOXjitnmN/ZYkCaEEDlSeJqbgYCSrNKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6nemV/btsOXjitnmN/ZYkCaEEDlSeJqbgYCSrNKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6nemV%2FbtsOXjitnmN%2FZYkCaEEDlSeJqbgYCSrNKk%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;271&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1084&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;즉, 실제로 GameObject를 생성하게 되면 코어의 C++ 코드가 실행됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;&amp;nbsp;여기서 핵심은 엔진의 C++ 코드가 생성되면서 C++객체가 생성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;동시에 이를 접근하고 관리하기 위해서 C#의 객체를 생성하고 C++의 객체를 참조합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751217042174&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;						Destroy(obj);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Destroy 메소드 또한 코어 함수 중 하나입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Destroy가 호출되면, C++의 객체가 파괴됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 순간 댕글링 포인터 현상이 발생합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;C++의 객체는 파괴되지만, 이를 참조하기 위해 생성된 C# 객체는&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아직도 C++ 객체의 주소를 참조하고 있는 문제가 발생합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 되면 해당 C# 객체는 GC에 빠르게 수거 대상이 되지 않습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 불필요한 데이터가 계속해서 메모리에 쌓이게 되는 것입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 이를 유니티에서 어떻게 하면 확인할 수 있을까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751217885485&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        private void Update()
        {
            if(Input.GetKeyDown(KeyCode.F1))
            {
                Destroy(obj);
            }
            if (Input.GetKeyDown(KeyCode.F2))
            {
                Debug.Log(obj);
                Debug.Log(obj.GetType());
                Debug.Log(obj == null);
            }
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 방식으로 테스트하면 어떤 결과가 나올까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;306&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P2Yld/btsOWEgmb6S/tKZVXUkf3dNE8h8b7pkENK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P2Yld/btsOWEgmb6S/tKZVXUkf3dNE8h8b7pkENK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P2Yld/btsOWEgmb6S/tKZVXUkf3dNE8h8b7pkENK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP2Yld%2FbtsOWEgmb6S%2FtKZVXUkf3dNE8h8b7pkENK%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;306&quot; height=&quot;143&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;143&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;obj가 null처리 되었음에도 불구하고 obj의 타입은 아직 UnityEngine.GameObject임을 알려줍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이는 아직 C# 객체가 제대로 파괴되지 않았기 때문입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 이를 방지하기 위해서는 어떻게 해야할까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;간단합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;파괴한 객체를 Null 처리해주는 것입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751218166406&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        private void Update()
        {
            if(Input.GetKeyDown(KeyCode.F1))
            {
                Destroy(obj);
                obj = null;
            }
            if (Input.GetKeyDown(KeyCode.F2))
            {
                Debug.Log(obj);
                Debug.Log(obj.GetType());
                Debug.Log(obj == null);
            }
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 어떤 결과가 나올까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;890&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdDhRP/btsOVvRFzxI/8kz0TJqpYKdcXPKGvYJwv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdDhRP/btsOVvRFzxI/8kz0TJqpYKdcXPKGvYJwv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdDhRP/btsOVvRFzxI/8kz0TJqpYKdcXPKGvYJwv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdDhRP%2FbtsOVvRFzxI%2F8kz0TJqpYKdcXPKGvYJwv1%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;890&quot; height=&quot;98&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;98&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;객체가 null처리가 확실히 되면서 해당 객체와의 레퍼 연결이 끊깁니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 이는 GC의 대상이 되면서 빠르게 메모리 관리가 될 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;C++에서는 소멸자 등을 사용해서 데이터를 관리해주지만, C#은 GC가 메모리를 관리해준다는 점.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;자동으로 메모리가 관리되지만, 그럼에도 불구하고 레퍼런스 타입의 객체는 항상 null처리를 해주는 것이 중요합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;최근 저는 IDisposable을 구현하는 클래스에 상속해서 Dispose 패턴을 꾸준히 구현합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;작은 프로젝트의 경우에는 굳이 할 필요는 없을 수 있지만, 프로젝트가 커질 수록 메모리 관리는 중요해집니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이상으로 포스팅을 마치도록 하겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;008&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/008.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/008.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 노트</category>
      <category>c#</category>
      <category>til</category>
      <category>공부</category>
      <category>유니티</category>
      <category>코딩</category>
      <category>프로그래밍</category>
      <author>덴바</author>
      <guid isPermaLink="true">https://denbacodingnote.tistory.com/44</guid>
      <comments>https://denbacodingnote.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 30 Jun 2025 02:35:20 +0900</pubDate>
    </item>
  </channel>
</rss>