<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>슬로우도파민</title>
    <link>https://techtoart.tistory.com/</link>
    <description>모바일 게임 개발자가 만드는 사람의 관점으로 개발, 콘텐츠, 커리어를 기록합니다.</description>
    <language>ko</language>
    <pubDate>Sat, 30 May 2026 17:40:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>슬로우도파민</managingEditor>
    <image>
      <title>슬로우도파민</title>
      <url>https://tistory1.daumcdn.net/tistory/3842702/attach/38e845f8917e42ab85612c755bc771b5</url>
      <link>https://techtoart.tistory.com</link>
    </image>
    <item>
      <title>[겜만들기] 0. 겜만들기 시작</title>
      <link>https://techtoart.tistory.com/228</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;N 번째 시도이지만, 다시 한 번 시도합니다.&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WEhhj/dJMcacJRa21/K3jbOrDbWtrfIgiyu9MJV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WEhhj/dJMcacJRa21/K3jbOrDbWtrfIgiyu9MJV0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WEhhj/dJMcacJRa21/K3jbOrDbWtrfIgiyu9MJV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWEhhj%2FdJMcacJRa21%2FK3jbOrDbWtrfIgiyu9MJV0%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;300&quot; height=&quot;168&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;168&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시작 - 목적 - 끝&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;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 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;뭐 디자인이나 연출 같은거에 빠지면 다음 단계로 잘 못넘어가더라구요..&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;작업 하면서 계속 스스로에게 묻는거죠.&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;br /&gt;폰트 사이즈가 조금 어색한 것,&lt;br /&gt;버튼 위치가 완벽하지 않은 것,&lt;br /&gt;연출이 아직 덜 예쁜 것은 일단 넘기고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 기능부터 다 완성하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 그래서 이 방법론으로 게임을 하나 만들어볼 것입니다.&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;br /&gt;탑다운 액션으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뱀서라이크 종류 게임으로 생각 중입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz3yGX/dJMcahqQY33/8I9NZLYBP39TQHfA7qRIV0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz3yGX/dJMcahqQY33/8I9NZLYBP39TQHfA7qRIV0/img.webp&quot; data-alt=&quot;뱀파이어 서바이버즈&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz3yGX/dJMcahqQY33/8I9NZLYBP39TQHfA7qRIV0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz3yGX%2FdJMcahqQY33%2F8I9NZLYBP39TQHfA7qRIV0%2Fimg.webp&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;800&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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;&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;br /&gt;적이 등장하고,&lt;br /&gt;목적지까지 도달하는 아주 작은 구조부터 만들어볼 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 화이팅.  &lt;/p&gt;</description>
      <category>개발기록/겜만들기</category>
      <category>겜만들기</category>
      <category>모바일게임</category>
      <category>뱀서라이크</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/228</guid>
      <comments>https://techtoart.tistory.com/228#entry228comment</comments>
      <pubDate>Mon, 11 May 2026 00:02:32 +0900</pubDate>
    </item>
    <item>
      <title>개발자는 코드나 쓰자.</title>
      <link>https://techtoart.tistory.com/227</link>
      <description>&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;400&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9iNpo/dJMcaad6CrK/ZegUjB4PQqUuXsskwLib10/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9iNpo/dJMcaad6CrK/ZegUjB4PQqUuXsskwLib10/img.webp&quot; data-alt=&quot;빅뱅이론 쉘든&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9iNpo/dJMcaad6CrK/ZegUjB4PQqUuXsskwLib10/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9iNpo%2FdJMcaad6CrK%2FZegUjB4PQqUuXsskwLib10%2Fimg.webp&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;400&quot; height=&quot;482&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;482&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 과거(무려 1-2년 전) 개발의 많은 부분들을 감사하게도(ㅠㅠ?) 담당해주고 있어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이제 조금씩 코드가 아닌 글도 써보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절대 코드를 잘 못써서는 아닙니다.ㅎㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/prwTi/dJMcadBNy92/Hi6fZkhq7D7hKEFW33t57K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/prwTi/dJMcadBNy92/Hi6fZkhq7D7hKEFW33t57K/img.png&quot; data-alt=&quot;커서, 클로드 그리고 나 (by GPT)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/prwTi/dJMcadBNy92/Hi6fZkhq7D7hKEFW33t57K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FprwTi%2FdJMcadBNy92%2FHi6fZkhq7D7hKEFW33t57K%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;1536&quot; height=&quot;1024&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;커서, 클로드 그리고 나 (by GPT)&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;p data-ke-size=&quot;size16&quot;&gt;아마도 앞으로 쓰게 될 글에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI와 함께 급변하는 시대에서&lt;br /&gt;저와 같은 모든 청년들의 고민과 돌파구를 담은 내용들이 많을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 조금 더 제 소개를 하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 Unity 개발자로 3년 정도의 경력이 있고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년 넘게 원하지만 원하지 않는 백수 생활을 하다가&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;22년 말에 OpenAI의 ChatGPT가 공개되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇년 있다가 희망퇴직을 통해 회사에서 정리(?)를 당했구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그간 겪었던 혼자만의 시간, 행복, 고통 모두 다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글에서 함께 공유해볼 수 있을 것 같습니다.&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;</description>
      <category>코드말고잼글</category>
      <category>AI</category>
      <category>GPT</category>
      <category>개발자</category>
      <category>커서</category>
      <category>클로드</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/227</guid>
      <comments>https://techtoart.tistory.com/227#entry227comment</comments>
      <pubDate>Sun, 3 May 2026 16:30:53 +0900</pubDate>
    </item>
    <item>
      <title>벡터 내적 활용 : 몬스터가 캐릭터 시야에 있는지 확인하기(Field of View)</title>
      <link>https://techtoart.tistory.com/225</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;게임에서 캐릭터(또는 카메라)가 어떤 방향을 보고 있을 때, 특정 대상이 &lt;span&gt;&lt;b&gt;내가 보는 방향의 앞쪽 시야(FOV, Field of View)&lt;/b&gt;&lt;/span&gt; 안에 들어오는지 판단해야 하는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q8gfp/dJMb99Zl7fB/JTkw9HsfByrdL7PLl4ECsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q8gfp/dJMb99Zl7fB/JTkw9HsfByrdL7PLl4ECsk/img.png&quot; data-alt=&quot;시야 안에 들어오는지 여부 판단&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q8gfp/dJMb99Zl7fB/JTkw9HsfByrdL7PLl4ECsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ8gfp%2FdJMb99Zl7fB%2FJTkw9HsfByrdL7PLl4ECsk%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;1220&quot; height=&quot;956&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;956&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적이 내 시야 안에 들어오면 경고 UI 띄우기&lt;/li&gt;
&lt;li&gt;NPC가 플레이어를 &amp;ldquo;봤는지&amp;rdquo; 판정하기&lt;/li&gt;
&lt;li&gt;자동 조준에서 &amp;ldquo;가장 내 정면에 가까운 대상&amp;rdquo; 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 가장 간단하고 빠르게 쓰는 방법이 &lt;span&gt;&lt;b&gt;벡터 내적(Dot product)&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 아이디어: &amp;ldquo;각도&amp;rdquo; 대신 &amp;ldquo;코사인&amp;rdquo;을 비교한다&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 두 방향 벡터를 준비한다&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;f&lt;/b&gt;&lt;/span&gt;: 내가 바라보는 방향(Forward)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;d&lt;/b&gt;&lt;/span&gt;: 나에서 대상까지의 방향(Direction to target)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로는 보통 이렇게 만듭니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;f = (내 forward 방향)&lt;/li&gt;
&lt;li&gt;d = (대상 위치 - 내 위치)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) 둘 다 정규화(normalize) 한다&lt;/b&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;정규화란 벡터의 길이를 1로 만드는 것입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정규화된 벡터는 &amp;ldquo;방향&amp;rdquo;만 남습니다.&lt;/li&gt;
&lt;li&gt;이 작업을 해야 &lt;span&gt;&lt;b&gt;내적 값이 각도의 코사인(cos)&lt;/b&gt;&lt;/span&gt; 이라는 깔끔한 형태가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화한 뒤에는 다음이 성립합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;Dot(f, d) = cos(&amp;theta;)&lt;br /&gt;&lt;/b&gt;(&amp;theta;는 f와 d 사이의 각도)&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Dot 값은 무엇을 의미할까?&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;정규화된 상태에서 내적은 &amp;ldquo;얼마나 같은 방향인가&amp;rdquo;를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Dot = 1&lt;/span&gt; &amp;rarr; 각도 0&amp;deg; (완전히 정면)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Dot = 0&lt;/span&gt; &amp;rarr; 각도 90&amp;deg; (옆)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Dot = -1&lt;/span&gt; &amp;rarr; 각도 180&amp;deg; (정반대)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;/span&gt;&lt;b&gt;Dot 값이 클수록 정면에 가깝다&lt;/b&gt;&lt;span&gt;는 뜻입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;FOV(시야각) 판정은 왜&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;cos(FOV/2) &lt;/b&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;시야각 FOV는 보통 &amp;ldquo;좌우로 벌어진 전체 각도&amp;rdquo;입니다.&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;예를 들어 FOV가 60&amp;deg;라면, 정면을 기준으로:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 30&amp;deg;&lt;/li&gt;
&lt;li&gt;오른쪽 30&amp;deg;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;/span&gt;&lt;b&gt;경계선은 정면 기준 &amp;plusmn;(FOV/2)&lt;/b&gt;&lt;span&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 대상이 시야 안에 있으려면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;대상과 정면 사이의 각도 &amp;theta;가 &lt;span&gt;&lt;b&gt;FOV/2 보다 작거나 같아야&lt;/b&gt;&lt;/span&gt; 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학으로 쓰면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;theta; &amp;le; FOV/2&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 게임에서는 보통 &lt;span&gt;&lt;b&gt;각도 계산(acos)&lt;/b&gt;&lt;/span&gt; 을 피합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(acos는 상대적으로 비용이 크고, 불필요한 경우가 많습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 코사인을 이용해 이렇게 바꿉니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cos(&amp;theta;) &amp;ge; cos(FOV/2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화된 벡터에서 &lt;span&gt;cos(&amp;theta;)&lt;/span&gt;가 바로 &lt;span&gt;Dot(f, d)&lt;/span&gt; 이므로 최종적으로:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;Dot(f, d) &amp;ge; cos(FOV/2)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 조건이면 대상은 시야각 안에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;직관적으로 이해하기&lt;/b&gt;&lt;/h2&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;span&gt;Dot(f, d)&lt;/span&gt;는 &amp;ldquo;대상이 내 정면에 얼마나 붙어있나&amp;rdquo; 점수입니다.&lt;/li&gt;
&lt;li&gt;FOV가 좁을수록 경계( &lt;span&gt;cos(FOV/2)&lt;/span&gt; )가 &lt;span&gt;&lt;b&gt;1에 가까워져서&lt;/b&gt;&lt;/span&gt; 조건이 빡빡해집니다.&lt;/li&gt;
&lt;li&gt;FOV가 넓을수록 경계가 작아져서(예: 0.5, 0.0에 가까워짐) 더 넓게 허용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FOV = 60&amp;deg; &amp;rarr; FOV/2 = 30&amp;deg; &amp;rarr; cos(30&amp;deg;) &amp;asymp; 0.866
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dot이 0.866 이상이면 &amp;ldquo;시야 안&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;FOV = 120&amp;deg; &amp;rarr; FOV/2 = 60&amp;deg; &amp;rarr; cos(60&amp;deg;) = 0.5
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dot이 0.5 이상이면 &amp;ldquo;시야 안&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발기록/Unity 유니티</category>
      <category>dot</category>
      <category>FOV</category>
      <category>Unity</category>
      <category>게임수학</category>
      <category>내적</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/225</guid>
      <comments>https://techtoart.tistory.com/225#entry225comment</comments>
      <pubDate>Sat, 3 Jan 2026 14:33:26 +0900</pubDate>
    </item>
    <item>
      <title>[C# 이해하기] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)</title>
      <link>https://techtoart.tistory.com/224</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;복사&amp;rdquo;라고 하면 보통 &amp;ldquo;완전히 똑같은 걸 하나 더 만든다&amp;rdquo;를 떠올립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 C#에서 복사는 생각보다 단순하지 않습니다. 왜냐하면 &lt;span&gt;&lt;b&gt;객체 안에 또 다른 객체(참조형)가 들어있을 수 있기 때문&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 복사에는 크게 두 가지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;얕은 복사(Shallow Copy)&lt;/b&gt;&lt;span&gt;: 겉은 새로 만들지만, 안쪽 참조는 &lt;/span&gt;&lt;b&gt;그대로 공유&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊은 복사(Deep Copy)&lt;/b&gt;&lt;span&gt;: 안쪽 참조까지 새로 만들어 &lt;/span&gt;&lt;b&gt;완전히 독립&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xWuFV/dJMcabCQ3Sv/kVnXj1HFlWZRjwvfO4KM8K/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xWuFV/dJMcabCQ3Sv/kVnXj1HFlWZRjwvfO4KM8K/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xWuFV/dJMcabCQ3Sv/kVnXj1HFlWZRjwvfO4KM8K/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxWuFV%2FdJMcabCQ3Sv%2FkVnXj1HFlWZRjwvfO4KM8K%2Fimg.webp&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;326&quot; height=&quot;280&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;280&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) 먼저, &amp;ldquo;복사 문제&amp;rdquo;가 왜 생기나?&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;값 형식(&lt;span&gt;int&lt;/span&gt;, &lt;span&gt;float&lt;/span&gt; 등)은 복사하면 그냥 값이 복사되니 직관적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 참조 형식(&lt;span&gt;class&lt;/span&gt;, 배열, List 등)입니다.&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;ldquo;겉(객체)&amp;rdquo; 안에 필드들이 있고, 그 필드 중 일부가 또 다른 객체를 가리킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이런 구조가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Player 객체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Level (int)&lt;/li&gt;
&lt;li&gt;Inventory (int[] 배열) &amp;larr; 또 다른 참조형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &amp;ldquo;Player를 복사했다&amp;rdquo;는 말이 &lt;span&gt;&lt;b&gt;Inventory도 새로 복사했다는 뜻인지&lt;/b&gt;&lt;/span&gt;가 애매해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 애매함을 정리한 개념이 얕은 복사/깊은 복사입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) 정의&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;얕은 복사&lt;/b&gt;&lt;/span&gt;: &amp;ldquo;겉 껍데기만 새로 만들고, 내부의 참조형은 같이 쓴다&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;깊은 복사&lt;/b&gt;&lt;/span&gt;: &amp;ldquo;내부의 참조형까지 새로 만들어서, 완전히 따로 쓴다&amp;rdquo;&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 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3) 얕은 복사 예시: 겉은 둘, 속은 공유&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1767404336134&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Player
{
    public int Level;
    public int[] Inventory; // 참조형(배열)
}

var p1 = new Player { Level = 1, Inventory = new[] { 10, 20 } };

// 얕은 복사(의미): Player는 새로 만들었지만 Inventory는 공유
var p2 = new Player { Level = p1.Level, Inventory = p1.Inventory };

p2.Level = 99;         // p2의 값 필드만 변경
p2.Inventory[0] = 777; // 공유된 배열을 변경

Console.WriteLine(p1.Level);        // 1   (영향 없음)
Console.WriteLine(p1.Inventory[0]); // 777 (영향 있음)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 이런 일이 생길까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inventory&lt;span&gt;는 배열이고(참조형), &lt;/span&gt;p1.Inventory&lt;span&gt;를 그대로 넣으면 &lt;/span&gt;p2.Inventory&lt;span&gt;도 &lt;/span&gt;&lt;span&gt;&lt;b&gt;같은 배열을 가리키게&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4) 깊은 복사 예시: 내부까지 새로 만들어 독립&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1767404367685&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var p3 = new Player
{
    Level = p1.Level,
    Inventory = (int[])p1.Inventory.Clone() // 배열 자체를 새로 복사
};

p3.Inventory[0] = 123;

Console.WriteLine(p1.Inventory[0]); // 777 (p3와 무관)
Console.WriteLine(p3.Inventory[0]); // 123&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 &lt;span&gt;Inventory&lt;/span&gt; 배열도 새로 만들었기 때문에, &lt;span&gt;p3&lt;/span&gt;는 &lt;span&gt;p1&lt;/span&gt;과 독립적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5) 심화 : &amp;ldquo;Clone() 했는데도 공유가 남는 경우&amp;rdquo;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열이 &lt;span&gt;int[]&lt;/span&gt;처럼 값형을 담으면 &lt;span&gt;Clone()&lt;/span&gt;이 꽤 안전합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 배열이 &lt;span&gt;Item[]&lt;/span&gt;처럼 &lt;span&gt;&lt;b&gt;참조형 객체를 담는 배열&lt;/b&gt;&lt;/span&gt;이면 얘기가 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767404427217&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Item { public string Name; }
class Bag  { public Item[] Items; }

var b1 = new Bag { Items = new[] { new Item { Name = &quot;Potion&quot; } } };
var b2 = new Bag { Items = (Item[])b1.Items.Clone() }; // 배열만 새로, Item은 공유

b2.Items[0].Name = &quot;Elixir&quot;;

Console.WriteLine(b1.Items[0].Name); // Elixir (같이 바뀜)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span&gt;Clone()&lt;/span&gt;은 &amp;ldquo;배열&amp;rdquo;은 새로 만들지만, 배열 안의 &lt;span&gt;Item&lt;/span&gt; 객체까지 새로 만들지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 &lt;/span&gt;b1.Items[0]&lt;span&gt;과 &lt;/span&gt;b2.Items[0]&lt;span&gt;이 &lt;/span&gt;&lt;span&gt;&lt;b&gt;같은 Item 객체를 가리키는 공유 상태&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&amp;ldquo;진짜 깊은 복사&amp;rdquo;로 고치면 이렇게 됩니다&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;&lt;span&gt;배열만 복사하지 말고, &lt;/span&gt;&lt;b&gt;각 Item도 새로 만들어 담아야&lt;/b&gt;&lt;span&gt; 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767404465551&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var b3 = new Bag
{
    Items = b1.Items.Select(item =&amp;gt; new Item { Name = item.Name }).ToArray()
};

b3.Items[0].Name = &quot;Elixir&quot;;

Console.WriteLine(b1.Items[0].Name); // Potion  &amp;larr; 안 바뀜
Console.WriteLine(b3.Items[0].Name); // Elixir&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 이 한 줄입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;얕은 복사: &lt;/span&gt;Items = (Item[])b1.Items.Clone()&lt;span&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;(Item 공유)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;깊은 복사: &lt;/span&gt;Items = b1.Items.Select(item =&amp;gt; new Item{...}).ToArray()&lt;span&gt; (Item도 복제)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&amp;ldquo;배열 요소가 값형이면?&amp;rdquo;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;span&gt;Items&lt;/span&gt;가 &lt;span&gt;int[]&lt;/span&gt; 같은 값형 배열이라면, &lt;span&gt;Clone()&lt;/span&gt;만으로도 사실상 깊은 복사처럼 동작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 요소 자체가 값이라 &amp;ldquo;참조 공유&amp;rdquo;라는 문제가 없기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;int[]&lt;/span&gt; &amp;rarr; &lt;span&gt;Clone()&lt;/span&gt;이면 요소 값이 그대로 복사(안전)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Item[]&lt;/span&gt; &amp;rarr; &lt;span&gt;Clone()&lt;/span&gt;이면 요소 &amp;ldquo;참조&amp;rdquo;가 그대로 복사(공유 위험)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6) 언제 얕은 복사가 문제이고, 언제 괜찮나?&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;얕은 복사가 &amp;ldquo;나쁘다&amp;rdquo;가 아니라, &lt;span&gt;&lt;b&gt;공유가 의도와 맞는지&lt;/b&gt;&lt;/span&gt;가 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;얕은 복사가 위험해지는 경우&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복사본을 수정했는데 원본도 같이 바뀌면 버그가 되는 상황&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;얕은 복사가 오히려 좋은 경우&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큰 데이터를 매번 복사하면 비용이 커서, 읽기 전용으로 공유하는 게 합리적인 상황&lt;/li&gt;
&lt;li&gt;내부 객체가 불변(immutable)이거나 수정되지 않는다고 보장되는 상황&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발기록/Computer Science</category>
      <category>c#</category>
      <category>CS</category>
      <category>csharp</category>
      <category>deepCopy</category>
      <category>shallowCopy</category>
      <category>깊은복사</category>
      <category>얕은복사</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/224</guid>
      <comments>https://techtoart.tistory.com/224#entry224comment</comments>
      <pubDate>Sat, 3 Jan 2026 10:45:35 +0900</pubDate>
    </item>
    <item>
      <title>[C# 이해하기] 값형식(Value Type)과 참조 형식(Reference Type)</title>
      <link>https://techtoart.tistory.com/223</link>
      <description>&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;C#에서 변수를 만들 때, 우리는 보통 &amp;ldquo;변수에 값이 들어간다&amp;rdquo;고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 자료형에 따라 변수 안에 들어가는 것이 두 가지로 갈립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;값 형식(Value Type)&lt;/b&gt;&lt;span&gt;: 변수에 &lt;/span&gt;&lt;b&gt;데이터 그 자체&lt;/b&gt;&lt;span&gt;가 들어간다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;참조 형식(Reference Type)&lt;/b&gt;&lt;/span&gt;: 변수에 **데이터가 있는 곳을 가리키는 정보(참조)**가 들어간다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 차이는 단순 개념이 아니라, 실제 코드에서 &lt;span&gt;&lt;b&gt;대입했을 때&lt;/b&gt;&lt;/span&gt;, &lt;span&gt;&lt;b&gt;수정했을 때&lt;/b&gt;&lt;/span&gt;, &lt;span&gt;&lt;b&gt;함수에 전달했을 때&lt;/b&gt;&lt;/span&gt; 동작을 완전히 바꿉니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QPqbk/dJMcabbNdzk/ZHrfyyXvbkfV4N84YrAekK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QPqbk/dJMcabbNdzk/ZHrfyyXvbkfV4N84YrAekK/img.png&quot; data-alt=&quot;ValueType vs ReferenceType&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QPqbk/dJMcabbNdzk/ZHrfyyXvbkfV4N84YrAekK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQPqbk%2FdJMcabbNdzk%2FZHrfyyXvbkfV4N84YrAekK%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;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ValueType vs ReferenceType&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) &amp;ldquo;복사되는 게 다르다&amp;rdquo;&lt;/b&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;값 형식: 대입하면 &amp;ldquo;내용&amp;rdquo;이 복사된다&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767403178056&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int a = 10;
int b = a;  // a의 값(10)이 b로 복사됨
b = 20;

Console.WriteLine(a); // 10
Console.WriteLine(b); // 20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;b&lt;/span&gt;를 바꿔도 &lt;span&gt;a&lt;/span&gt;는 그대로입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 &lt;span&gt;&lt;b&gt;처음 대입할 때부터 서로 다른 값&lt;/b&gt;&lt;/span&gt;을 가지고 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;참조 형식: 대입하면 &amp;ldquo;주소표(참조)&amp;rdquo;가 복사된다&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767403203904&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr1 = { 1, 2, 3 };
int[] arr2 = arr1; // arr1이 가리키는 &quot;같은 배열&quot;을 arr2도 가리킴

arr2[0] = 999;

Console.WriteLine(arr1[0]); // 999
Console.WriteLine(arr2[0]); // 999&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;arr2&lt;/span&gt;를 수정했는데 &lt;span&gt;arr1&lt;/span&gt;도 바뀐 것처럼 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히는 &lt;span&gt;arr1&lt;/span&gt;과 &lt;span&gt;arr2&lt;/span&gt;가 &lt;b&gt;같은 배열(같은 객체)&lt;/b&gt;을 공유하고 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) &amp;ldquo;변수 = 상자&amp;rdquo; 비유로 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&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;span&gt;&lt;b&gt;값 형식 변수&lt;/b&gt;&lt;/span&gt;: 상자 안에 &lt;span&gt;&lt;b&gt;물건 자체&lt;/b&gt;&lt;/span&gt;가 들어있음&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;참조 형식 변수&lt;/b&gt;&lt;/span&gt;: 상자 안에 &lt;span&gt;&lt;b&gt;물건이 있는 창고 주소&lt;/b&gt;&lt;/span&gt;가 적힌 쪽지가 들어있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 참조 형식은 상자를 복사해도 &amp;ldquo;쪽지&amp;rdquo;만 복사되고, 창고(객체)는 그대로 하나라서 함께 영향을 받습니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3) 대표적인 값 형식 / 참조 형식&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;값 형식(Value Type)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int&lt;span&gt;, &lt;/span&gt;float&lt;span&gt;, &lt;/span&gt;double&lt;span&gt;, &lt;/span&gt;bool&lt;span&gt;, &lt;/span&gt;char&lt;/li&gt;
&lt;li&gt;&lt;span&gt;struct&lt;/span&gt; (구조체)&lt;/li&gt;
&lt;li&gt;enum&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조 형식(Reference Type)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;class&lt;/span&gt;로 만든 타입&lt;/li&gt;
&lt;li&gt;string&lt;/li&gt;
&lt;li&gt;&lt;span&gt;배열(&lt;/span&gt;int[]&lt;span&gt;, &lt;/span&gt;char[]&lt;span&gt; 등)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;List&amp;lt;T&amp;gt;&lt;span&gt;, &lt;/span&gt;Dictionary&amp;lt;TKey, TValue&amp;gt;&lt;span&gt; 같은 컬렉션&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 가장 많이 헷갈리는 게 &lt;span&gt;string&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;string&lt;/span&gt;은 생김새는 값처럼 보이지만, &lt;span&gt;&lt;b&gt;분류는 참조 형식&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4) &amp;ldquo;참조 형식인데 왜 string은 안전해 보일까?&amp;rdquo;&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;배열이나 List는 수정이 가능합니다(&amp;ldquo;mutable&amp;rdquo;).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;b&gt;불변(immutable)&lt;/b&gt;&lt;span&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767403384553&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;string s1 = &quot;hi&quot;;
string s2 = s1;
s2 = &quot;bye&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;span&gt;s2&lt;/span&gt;를 바꾼 게 아니라, &lt;span&gt;s2&lt;/span&gt;가 &lt;span&gt;&lt;b&gt;새 문자열을 가리키게 된 것&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &amp;ldquo;참조 형식인데도 값 형식처럼&amp;rdquo; 느껴질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심만 정리하면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;string&lt;span&gt;은 &lt;/span&gt;&lt;span&gt;&lt;b&gt;참조 형식&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;다만 문자열 내용 자체를 바꾸는 방식이 아니라 &lt;span&gt;&lt;b&gt;새 문자열을 만든다(불변)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;그래서 공유로 인한 사고가 상대적으로 덜 보인다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5) 함수에 전달될 때(매개변수)도 핵심은 &amp;ldquo;무엇이 복사되나&amp;rdquo;&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#의 기본 전달 방식은 &lt;span&gt;&lt;b&gt;값 전달(call by value)&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 포인트는 &amp;ldquo;값 전달&amp;rdquo;이 &lt;span&gt;&lt;b&gt;항상 값 형식만 의미하는 게 아니라&lt;/b&gt;&lt;/span&gt;는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값 형식을 전달하면: &lt;span&gt;&lt;b&gt;데이터 자체가 복사&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;참조 형식을 전달하면: &lt;span&gt;&lt;b&gt;참조(주소표)가 복사&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 참조 형식도 기본은 &amp;ldquo;값 전달&amp;rdquo;인데, &lt;b&gt;그 값이 &amp;lsquo;참조&amp;rsquo;&lt;/b&gt;인 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767403443386&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ChangeFirst(int[] a)
{
    a[0] = 777; // 배열 내용 수정 (공유된 객체에 반영)
}

int[] x = { 1, 2, 3 };
ChangeFirst(x);
Console.WriteLine(x[0]); // 777&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6) 가장 중요한 실전 결론 3가지&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;값 형식은 복사해도 독립적이라 예측이 쉽다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조 형식은 &amp;ldquo;공유&amp;rdquo;가 기본이어서, 한쪽 수정이 다른 쪽에 영향을 줄 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;내가 지금 바꾸는 게 변수 자체인지, 변수 너머의 객체인지&amp;rdquo;를 구분하면 실수가 줄어든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발기록/Computer Science</category>
      <category>c#</category>
      <category>CS</category>
      <category>csharp</category>
      <category>referencetype</category>
      <category>ValueType</category>
      <category>값형식</category>
      <category>참조형식</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/223</guid>
      <comments>https://techtoart.tistory.com/223#entry223comment</comments>
      <pubDate>Sat, 3 Jan 2026 10:36:08 +0900</pubDate>
    </item>
    <item>
      <title>[2D-Platformer] 3. 점프 구현하기 (Jump)</title>
      <link>https://techtoart.tistory.com/222</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 점프 기능을 추가하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;251226-2dplatformer.gif&quot; data-origin-width=&quot;1908&quot; data-origin-height=&quot;1064&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cB8Fic/dJMcabQlQYG/KZmqTWjTAHo1ZB1sUqLKg1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cB8Fic/dJMcabQlQYG/KZmqTWjTAHo1ZB1sUqLKg1/img.gif&quot; data-alt=&quot;점프 기능 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cB8Fic/dJMcabQlQYG/KZmqTWjTAHo1ZB1sUqLKg1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cB8Fic/dJMcabQlQYG/KZmqTWjTAHo1ZB1sUqLKg1/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;1908&quot; height=&quot;1064&quot; data-filename=&quot;251226-2dplatformer.gif&quot; data-origin-width=&quot;1908&quot; data-origin-height=&quot;1064&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;&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;점프는 Update에서 점프가 가능한 상태인지를 구분해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FixedUpdate에서 실행해 주었다.&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;pre id=&quot;code_1766800520332&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void Update()
    {
        if (isGrounded &amp;amp;&amp;amp; !isClimbing &amp;amp;&amp;amp; Input.GetKeyDown(KeyCode.Space))
        {
            jumpRequest = true;
        }
    }



    private void FixedUpdate()
    {   
        // jump
        if (jumpRequest)
        {
            Jump();
            jumpRequest = false;
        } 
    }


    private void Jump()
    {
        rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0f);
        rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpPower);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jump 함수에서 0을 한번 줬다가 jumpPower를 주는 이유는 모든 점프를 일정하게 하기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점프 파워, 높이 등을 일정하게 맞춰준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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-filename=&quot;jumpbug.gif&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1064&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh2Lbc/dJMcaiaSuP9/SLI8RFlss2jUFyD5cChHC0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh2Lbc/dJMcaiaSuP9/SLI8RFlss2jUFyD5cChHC0/img.gif&quot; data-alt=&quot;Jump Bug&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh2Lbc/dJMcaiaSuP9/SLI8RFlss2jUFyD5cChHC0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bh2Lbc/dJMcaiaSuP9/SLI8RFlss2jUFyD5cChHC0/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;1904&quot; height=&quot;1064&quot; data-filename=&quot;jumpbug.gif&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1064&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Jump Bug&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;p data-ke-size=&quot;size16&quot;&gt;점프를 하면서 벽을 밀쳤을 때 마찰력 때문에 서로 계속 밀어서 움직이지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중력이 엄청 세지 않아서 그런 것도 같았다. (gravity scale 10)&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;결국 마찰력을 0으로 한 Physics Material 2D를 만들어 Player Collider에 연결해줌으로써 문제를 해결했다!&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;730&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crsdjb/dJMcabv3APT/keN9TdDKjQXXyjKFm1SMy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crsdjb/dJMcabv3APT/keN9TdDKjQXXyjKFm1SMy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crsdjb/dJMcabv3APT/keN9TdDKjQXXyjKFm1SMy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcrsdjb%2FdJMcabv3APT%2FkeN9TdDKjQXXyjKFm1SMy1%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;730&quot; height=&quot;342&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발기록/Unity 유니티</category>
      <category>2dgame</category>
      <category>2dplatformer</category>
      <category>jump</category>
      <category>physicsmaterial2D</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/222</guid>
      <comments>https://techtoart.tistory.com/222#entry222comment</comments>
      <pubDate>Sat, 27 Dec 2025 11:28:37 +0900</pubDate>
    </item>
    <item>
      <title>[2D Platformer] 2. 사다리 로직 구현 (Climbing Ladder)</title>
      <link>https://techtoart.tistory.com/221</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 사다리 타기 로직을 구현해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크해야할 것도 많고, 올라가는 것 뿐 아니라 다시 내려오는것까지 구현해야해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 은근 까다로웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 결과물이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메이플 스토리 사다리 타는것 기준으로 구현했는데 뭔가 느낌이 괜찮은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/460205014&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cmdj73/hyZPYhHcXV/jRWRJi3the1AHEe9YkYQB1/img.jpg?width=1768&amp;amp;height=982&amp;amp;face=0_0_1768_982,https://scrap.kakaocdn.net/dn/cqIY4a/hyZQtNVJC2/WalutVkFckOAxzjkeba5n0/img.jpg?width=1768&amp;amp;height=982&amp;amp;face=0_0_1768_982&quot; data-video-width=&quot;860&quot; data-video-height=&quot;478&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;478&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/460205014?service=daum_tistory&quot; width=&quot;860&quot; height=&quot;478&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;사다리 로직 구현 결과물&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 사다리가 옆에 있는지 체크&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;일단 사다리 로직을 구현할 때 내가 가장 먼저 생각해야하는 조건이&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;i&gt;&lt;b&gt;사다리가 옆에 있는가??&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이런식으로 Near 사다리 조건을 체크해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사다리에 Ladder 스크립트를 넣어서 어떤 사다리를 타고 있는지도 가져와줬다. (나중에 필요할 것 같아서)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766724796802&quot; class=&quot;nginx&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 OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.name == &quot;ladder&quot;)
        {
            isNearLadder = true;
            ladder = other.GetComponent&amp;lt;Ladder&amp;gt;();
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.gameObject.name == &quot;ladder&quot;)
        {
            isNearLadder = false;
            ladder = null;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;그래서 update 문에서 Near사다리 이면 중력을 없애버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766724954025&quot; class=&quot;angelscript&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;    void Update()
    {
        // gravity setting
        if (isNearLadder)
            rb.gravityScale = 0;
        else
            rb.gravityScale = gravityScale;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Climbing 상태 체크&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;Climbing 중일 때, 좌우 이동을 막기 위해 Climbing 조건을 정의해봤다.&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;b&gt;Climbing 이 시작될때&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Near Ladder true&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- horizontal 입력 true&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;Climbing 상태가 끝나는 조건&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- IsClimbing true&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- isGrounded true (항상 위든 아래든 땅에 닿아야 클라이밍이 끝난다.)&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;pre id=&quot;code_1766725350556&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void Update()
    {      
        // judge climbing
        if (isNearLadder &amp;amp;&amp;amp; vertical != 0)
            isClimbing = true;
        else if (isClimbing &amp;amp;&amp;amp; isGrounded)
            isClimbing = false;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. IsGrounded 체크&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ground 체크는 상용화 된 방법을 사용했다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Player 바닥 밑에 EmptyObject를 깔아주고 Physics2D.OverlapCircle을 통해 체크해준다.&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-filename=&quot;스크린샷 2025-12-26 오후 2.04.14.png&quot; data-origin-width=&quot;2040&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YRWzj/dJMcagc3YoZ/XF3erYIPpWIDmAnKmvzbWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YRWzj/dJMcagc3YoZ/XF3erYIPpWIDmAnKmvzbWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YRWzj/dJMcagc3YoZ/XF3erYIPpWIDmAnKmvzbWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYRWzj%2FdJMcagc3YoZ%2FXF3erYIPpWIDmAnKmvzbWK%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;2040&quot; height=&quot;846&quot; data-filename=&quot;스크린샷 2025-12-26 오후 2.04.14.png&quot; data-origin-width=&quot;2040&quot; data-origin-height=&quot;846&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;pre id=&quot;code_1766725545416&quot; class=&quot;csharp&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 FixedUpdate()
    {
        // judge isGrounded
        isGrounded = Physics2D.OverlapCircle
			(groundCheck.position, groundRadius, groundLayer);
    }&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;GroundCheck는 물리 상태이기 때문에, FixedUpdate에서 하는게 가장 안전하다.&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 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 맵 조정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초록 부분 - Ground&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갈색 부분 - Ladder&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;맵 특징 1&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사다리 부분은 ground가 끊겨있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사다리 부분의 Ground는 isTrigger 조건만 넣어서 Player가 막힘없이 통과할 수 있도록 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 사다리 부분의 ground가 없었는데, 있어야 다 올라갔다는 체크를 해줄 수 있어서 추가하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;맵 특징2 - 사다리 2d collider&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윗부분을 길게 뽑아서 윗층에서 돌아다닐때도 Player가 사다리랑 Trigger를 감지할 수 있도록 하였다.&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-filename=&quot;스크린샷 2025-12-26 오후 2.13.15.png&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;978&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d6TDH6/dJMcaa4YlNo/UvCiRy9ehNVMFM1fUiakuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d6TDH6/dJMcaa4YlNo/UvCiRy9ehNVMFM1fUiakuk/img.png&quot; data-alt=&quot;맵 2d Collider&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d6TDH6/dJMcaa4YlNo/UvCiRy9ehNVMFM1fUiakuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd6TDH6%2FdJMcaa4YlNo%2FUvCiRy9ehNVMFM1fUiakuk%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;1756&quot; height=&quot;978&quot; data-filename=&quot;스크린샷 2025-12-26 오후 2.13.15.png&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;맵 2d Collider&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;맵 특징3&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사다리 양 옆 초록 ground의 collider는 조금 줄여준다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 이동 로직&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;이제 Climb 상태에 따라,&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;Climbing 일때는 좌우 이동을 막고, x position을 사다리 중앙으로 고정시켜 줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Climbing 중이 아닐 때는 좌우 입력을 반영시켜주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766725650319&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private void FixedUpdate()
    {
        // Player Move (Climb / not Climb)
        if (isClimbing)
        {
            float newX = ladder.transform.position.x;
            float newY
            = Mathf.Clamp
            (rb.position.y + vertical * climbSpeed * Time.fixedDeltaTime, 
                ladder.bottom.position.y, ladder.top.position.y);
            
            rb.MovePosition(new Vector2(newX, newY));
        }
        else
        {
            rb.linearVelocity 
            = new Vector2(horizontal * moveSpeed, rb.linearVelocity.y);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Climb 상한/하한 위치 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 중간에 Mathf.Clamp를 넣어, 위 아래 포지션의 상한, 하한선을 제한시켜준 이유는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 코드를 넣지 않았더니 플레이어가 사다리에 도착했을 때 심하게 진동을하고 상태가 꼬여버려서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안전하게 사다리 top, bottom 위치까지만 움직이도록 제한해주었다.&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;p data-ke-size=&quot;size16&quot;&gt;다음은 점프를 추가해볼 것이다!&lt;/p&gt;</description>
      <category>개발기록/Unity 유니티</category>
      <category>2dplatformer</category>
      <category>Climb</category>
      <category>Climbing</category>
      <category>isGrounded</category>
      <category>Unity2D</category>
      <category>unityphysics</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/221</guid>
      <comments>https://techtoart.tistory.com/221#entry221comment</comments>
      <pubDate>Fri, 26 Dec 2025 14:11:27 +0900</pubDate>
    </item>
    <item>
      <title>[2D Platformer]  1. START &amp;amp; 좌우 이동 구현</title>
      <link>https://techtoart.tistory.com/220</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;다시 게임 만들기 프로젝트를 시작했다-!-!-!  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2D 플랫포머 게임&lt;/b&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;요즘 메이플랜드를 많이 하기도 했고 2D 게임을 만들어보고 싶어서 이 장르를 택했다.&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 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;게임 개발은 이전에도 해본 적이 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 조금 더 &lt;span&gt;&lt;b&gt;체계적이고 효율적인 방식&lt;/b&gt;&lt;/span&gt;으로 해보고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 GPT의 도움을 받아&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 단순한 규칙 두 가지를 정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;항상 &lt;/span&gt;&lt;b&gt;시작 &amp;ndash; 목표 &amp;ndash; 플레이 &amp;ndash; 끝&lt;/b&gt;&lt;span&gt;이 있는 상태를 유지한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;아트는 타인에게 보여줘도 될 정도로 플레이가 안정된 이후에 넣는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완성도가 낮아도 상관없고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일단 &lt;/span&gt;&lt;b&gt;게임처럼 켜서 플레이하고 끝낼 수 있는 상태&lt;/b&gt;&lt;span&gt;를 유지하는 게 목표다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;꼭 구현해보고 싶은 기능&lt;/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;진짜 간단한데, 메이플 사다리 타는 기능을 꼭 구현해보고 싶다. (심플하죠?)&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;NPC 다이얼로그도 한 번 붙여보고 싶다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;1026&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPbwRz/dJMcadtA2Sd/iws8i64s1yPVTvjQZCTg9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPbwRz/dJMcadtA2Sd/iws8i64s1yPVTvjQZCTg9K/img.png&quot; data-alt=&quot;메이플월드 - 메이플랜드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPbwRz/dJMcadtA2Sd/iws8i64s1yPVTvjQZCTg9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPbwRz%2FdJMcadtA2Sd%2Fiws8i64s1yPVTvjQZCTg9K%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;1402&quot; height=&quot;1026&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;1026&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;First Day&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;Day 1에서는 목표를 아주 작게 잡았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;왼쪽에서 시작해서&lt;br /&gt;&lt;/b&gt;&lt;b&gt;좌우로 움직여서&lt;br /&gt;&lt;/b&gt;&lt;b&gt;흰색 네모에 도달하면 끝&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이어 좌우 이동을 만들고&lt;/li&gt;
&lt;li&gt;목표를 흰색 네모로 정하고&lt;/li&gt;
&lt;li&gt;도달하면 Success 가 뜨도록 했다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아트는 전부 square로 처리했다.&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;ldquo;게임을 켜면 &amp;rarr; 움직일 수 있고 &amp;rarr; 끝낼 수 있는 상태&quot;가 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 현재 상태의 플레이 영상이다.&lt;/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;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/460097260&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/068vh/hyZP48U9nv/ojMFV1j5P7PrZuQtqOq1N0/img.jpg?width=1532&amp;amp;height=854&amp;amp;face=0_0_1532_854,https://scrap.kakaocdn.net/dn/qnzoB/hyZPZ0ONtV/KIcdum4WeSQ5Q6O2xelsQ1/img.jpg?width=1532&amp;amp;height=854&amp;amp;face=0_0_1532_854&quot; data-video-width=&quot;860&quot; data-video-height=&quot;479&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;479&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/460097260?service=daum_tistory&quot; width=&quot;860&quot; height=&quot;479&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 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;ndash; 목표 &amp;ndash; 플레이 &amp;ndash; 끝이 명확하니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발하는 입장에서도 &lt;span&gt;&lt;b&gt;뿌듯함이 두 배&lt;/b&gt;&lt;/span&gt;인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 도트만 찍다가 끝난 경우도 많았는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 꽤 마음에 든다.&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&gt;&lt;b&gt;사다리 타기 구현&lt;/b&gt;&lt;/span&gt;이다~!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발기록/Unity 유니티</category>
      <category>2d-platformer</category>
      <category>2dgame</category>
      <category>game</category>
      <category>mapleland</category>
      <category>Unity</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/220</guid>
      <comments>https://techtoart.tistory.com/220#entry220comment</comments>
      <pubDate>Mon, 22 Dec 2025 10:12:35 +0900</pubDate>
    </item>
    <item>
      <title>비트 연산으로 이해하는 2의 거듭제곱 - Math.Pow 대신 1 &amp;lt;&amp;lt; n을 사용하는 이유</title>
      <link>https://techtoart.tistory.com/219</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Math.Pow(2, n) &lt;/b&gt;&lt;b&gt;대신&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;1 &amp;lt;&amp;lt; n &lt;/b&gt;&lt;b&gt;을 쓰는 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLs6ky/dJMcabCJfzw/gajiJtrgIk6zkpOPrWh6n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLs6ky/dJMcabCJfzw/gajiJtrgIk6zkpOPrWh6n0/img.png&quot; data-alt=&quot;2048 게임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLs6ky/dJMcabCJfzw/gajiJtrgIk6zkpOPrWh6n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLs6ky%2FdJMcabCJfzw%2FgajiJtrgIk6zkpOPrWh6n0%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;350&quot; height=&quot;512&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2048 게임&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 문제를 풀다 보면 &lt;span&gt;2ⁿ&lt;/span&gt; 형태의 값이 자주 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C#에서는 흔히 다음과 같이 작성하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765516860638&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = (int)Math.Pow(2, n);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 경우, 더 적절한 표현은 다음이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765516960036&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x = 1 &amp;lt;&amp;lt; n;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;비트 관점에서의 의미&lt;/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;정수 &lt;span&gt;1&lt;/span&gt;을 이진수로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765516985661&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 = 0001&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 시프트 연산(&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;)은 비트를 왼쪽으로 이동시키는 연산이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765517002225&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 &amp;lt;&amp;lt; 1 = 0010 (2)
1 &amp;lt;&amp;lt; 2 = 0100 (4)
1 &amp;lt;&amp;lt; 3 = 1000 (8)&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;즉, 비트를 한 칸 이동할 때마다 값은 2배가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765517022266&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 &amp;lt;&amp;lt; n == 2ⁿ&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Math.Pow&lt;/b&gt;&lt;b&gt;가 적절하지 않은 이유 - &lt;/b&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;Math.Pow&lt;span&gt;와 &lt;/span&gt;MathF.Pow&lt;span&gt;는 각각 &lt;/span&gt;double&lt;span&gt;, &lt;/span&gt;float&lt;span&gt; 기반의 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765517043296&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Math.Pow(2, n)   // double
MathF.Pow(2, n)  // float&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수 연산이 필요한 상황에서 불필요한 부동소수점 계산과 캐스팅이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2의 거듭제곱을 표현할 때 &lt;span&gt;1 &amp;lt;&amp;lt; n&lt;/span&gt;이 더 적절하다.&lt;/li&gt;
&lt;li&gt;정수 연산이며, 비트마스크 문제와 의미적으로 잘 맞는다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Math.Pow&lt;/span&gt;는 부동소수점 연산이므로 이런 상황에서는 피하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발기록/자료구조 &amp;amp; 알고리즘</category>
      <category>Algorithm</category>
      <category>BIT</category>
      <category>bitmask</category>
      <category>CS</category>
      <category>Math.pow</category>
      <category>거듭제곱</category>
      <category>비트연산</category>
      <category>알고리즘</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/219</guid>
      <comments>https://techtoart.tistory.com/219#entry219comment</comments>
      <pubDate>Fri, 12 Dec 2025 14:33:01 +0900</pubDate>
    </item>
    <item>
      <title>LeetCode 136. SingleNumber &amp;mdash; XOR 연산 응용</title>
      <link>https://techtoart.tistory.com/218</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  LeetCode 136번&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;Single Number&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; Dictionary 풀이 vs XOR 풀이 완전 비교&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LeetCode 136번 &lt;span&gt;&lt;b&gt;Single Number&lt;/b&gt;&lt;/span&gt; 문제는 매우 유명한 비트 연산 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;배열에서 &lt;span&gt;&lt;b&gt;단 한 번만 등장하는 숫자를 찾아라&lt;/b&gt;&lt;/span&gt;&amp;rdquo;라는 단순한 요구지만, 효율성과 공간 복잡도에 따라 풀이의 난이도가 크게 달라진다.&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&gt;이 글에서는 &lt;/span&gt;&lt;b&gt;직관적인 Dictionary 풀이&lt;/b&gt;&lt;span&gt;와 &lt;/span&gt;&lt;b&gt;가장 빠르고 메모리 효율이 좋은 XOR 정석 풀이&lt;/b&gt;&lt;span&gt;를 비교하여, 어떤 방식이 더 좋은 선택인지 자세히 분석해보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://leetcode.com/problems/single-number/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/single-number/description/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;  문제 요약&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;정수 배열 &lt;span&gt;nums&lt;/span&gt;에서&lt;br /&gt;&lt;b&gt;오직 한 번만 등장하는 숫자&lt;/b&gt;&lt;span&gt;를 찾기.&lt;br /&gt;&lt;/span&gt;나머지 숫자는 모두 &lt;i&gt;두 번씩&lt;/i&gt; 등장한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre id=&quot;code_1765443290457&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;입력:  [2,2,1]
출력:  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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;  1. Dictionary(해시맵) 풀이 &amp;mdash; 직관적이지만 비효율적인 이유&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 내가 처음에 풀었던 방식인 Dictionary를 이용한 풀이:&lt;/p&gt;
&lt;pre id=&quot;code_1765443333566&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int SingleNumber(int[] nums)
{
    Dictionary&amp;lt;int, bool&amp;gt; dict = new Dictionary&amp;lt;int, bool&amp;gt;();

    foreach (var i in nums)
    {
        if (dict.ContainsKey(i))
        {
            dict.Remove(i);
        }
        else
        {
            dict[i] = true;
        }
    }

    return dict.Keys.First();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✔️ 장점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;①&amp;nbsp; 직관적으로 이해가 쉽다&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;결국 마지막에 딱 하나 남는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;②&amp;nbsp; 논리적으로 오류가 없다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 조건(단 한 숫자만 1회 등장)과 정확히 일치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;❌ 단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;①&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;공간 복잡도 O(n)&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;중간 과정에서 &lt;span&gt;dict&lt;/span&gt;에는 여러 숫자가 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 큰 입력에서는 불필요한 메모리 사용이 커진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;②&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;성능이 XOR보다 느리다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ContainsKey&lt;span&gt;, &lt;/span&gt;Remove&lt;span&gt;는 평균 O(1)이지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 연산과 리사이징이 일어나기 때문에 실제 실행 비용은 XOR보다 훨씬 크다.&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;③ LeetCode가 의도한 풀이와 다르다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 문제는 원래 &lt;/span&gt;&lt;b&gt;O(1) 공간으로 해결하는 비트 연산 문제&lt;/b&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;  2. XOR 정석 풀이 &amp;mdash; 가장 빠르고 메모리 효율 최고의 방식&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LeetCode 토론에서도 공식 인터뷰에서도 가장 많이 언급되는 풀이가 바로 XOR 풀이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 이 풀이 보고 미쳤다고 생각했다..(positive)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765443431679&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int SingleNumber(int[] nums)
{
    int result = 0;
    foreach (var n in nums)
    {
        result ^= n;
    }
    return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;✔️ XOR이 가능한 이유 (핵심 성질 3개)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;a ^ a = 0&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 숫자는 서로 지워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;0 ^ b = b&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0은 XOR에 영향을 주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;교환/결합 법칙이 성립한다&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서 상관 없이 모든 숫자를 XOR 해도 된다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e;&quot; data-ke-size=&quot;size16&quot;&gt;결국 &amp;ldquo;짝수 번 등장하는 숫자는 모두 사라지고 한 번 등장한 숫자만 남는다.&amp;rdquo;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chj2yD/dJMcaf6b9l3/EFcdn4xoz6lAxGE281RLBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chj2yD/dJMcaf6b9l3/EFcdn4xoz6lAxGE281RLBk/img.png&quot; data-alt=&quot;XOR 연산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chj2yD/dJMcaf6b9l3/EFcdn4xoz6lAxGE281RLBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchj2yD%2FdJMcaf6b9l3%2FEFcdn4xoz6lAxGE281RLBk%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;341&quot; height=&quot;208&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;XOR 연산&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✔️ 장점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;① 공간 복잡도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;O(1)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 메모리가 필요 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;② 시간 복잡도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;O(n)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번만 순회하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;③ 가장 빠르고 가장 짧다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 가장 좋아하는 연산: 비트 연산.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✔️ 단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;① 초보자에게는 직관적이지 않다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이 &amp;ldquo;왜 XOR이 되지?&amp;rdquo; 하고 이해하는 데 시간이 걸린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 일단 이해하면 비트 문제에서 자주 응용된다.&lt;/p&gt;</description>
      <category>개발기록/자료구조 &amp;amp; 알고리즘</category>
      <category>csharp</category>
      <category>leetcode</category>
      <category>singlenumber</category>
      <category>xor</category>
      <category>비트연산</category>
      <category>알고리즘</category>
      <category>코딩테스트</category>
      <author>슬로우도파민</author>
      <guid isPermaLink="true">https://techtoart.tistory.com/218</guid>
      <comments>https://techtoart.tistory.com/218#entry218comment</comments>
      <pubDate>Thu, 11 Dec 2025 18:03:05 +0900</pubDate>
    </item>
  </channel>
</rss>