<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>평생 배우는 개발자</title>
    <link>https://learn-forever.tistory.com/</link>
    <description>코딩 테스트, 개발자 면접을 위해 평생 배우는 개발자의 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 12 Apr 2026 10:43:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>개발지식 블로그</managingEditor>
    <image>
      <title>평생 배우는 개발자</title>
      <url>https://tistory1.daumcdn.net/tistory/7514965/attach/dc4196527f184fa8ab8e140325d7e2a6</url>
      <link>https://learn-forever.tistory.com</link>
    </image>
    <item>
      <title>2차 프로젝트 회고</title>
      <link>https://learn-forever.tistory.com/31</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;소감&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원티드 포텐업 게임개발 4기 2차 프로젝트를 클리어했다! 1차 프로젝트에서 완성했던 QuadTree 시각화에 더해 A star Algorithm까지 완성시켜서 의미가 있었던 프로젝트였다. 이번 프로젝트는 QuadTree와 A* Algorithm을 시각화하는 게 목표였고 잘 이루어 냈다고 생각한다. 다만, 아쉬운 점은 맵을 크게 정해서 여러 actor들을 이동시킬 때 FPS가 하락하는 현상이 남아있고, actor가 이동 시에 다른 actor를 선택하면 이전 actor의 Path가 화면에 계속 남아있는 버그 등이 발견되었다는 것이다. 다음 프로젝트는 마지막 점검을 깐깐하게 해서 최적화 및 버그를 잘 잡아내야겠다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번에도 1차 프로젝트와 같이 정말 창의적인 아이디어로 만든 게임이 즐비했고, 배워야 할 점이 많다는 것을 여실히 깨달았다. 다음 프로젝트 부터는 언리얼로 진행을 하는데 어떤 프로젝트가 나올지 긴장도 되고 기대도 된다. 지금까지 배운 점을 바탕으로 재미있는 프로젝트를 진행하고 싶은 마음이 생겨났다.&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  프로젝트 이름&lt;/h2&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 콘솔 뱀서라이크 V2&lt;/b&gt;&lt;/h3&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 프로젝트 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;게임 소개:&lt;br /&gt;콘솔 환경에서 Quadtree와 A* Algorithm 기술을 시각화하는 데모입니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;개발 기간:&lt;br /&gt;&amp;nbsp;총 7일(2026-03-04 ~ 2026-03-10 + 발표 준비 2026-03-11 )&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;참여 인원:&lt;br /&gt;개인&amp;nbsp;프로젝트&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;현황(결과):
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;GitHub:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/jaw-choi/Wanted4_ShootingGame#&quot;&gt;https://github.com/jaw-choi/Wanted4_ShootingGame#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기술 스택&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #ffffff; color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;항목&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;Skill Set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Core Tech&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;Custom Game Loop(GameLevel Tick), Actor Update Pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Gameplay Systems&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;Stat/Interface(IStatHolder), LevelUp + Pause, Hit Invincibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Collision&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;Quadtree&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Optimization&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;점유 유닛 그리드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Trouble Shoot&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;double delete,mouse input 강제 초기화, 파싱 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333; width: 17.907%;&quot;&gt;Environment&lt;/td&gt;
&lt;td style=&quot;color: #333333; width: 81.9767%;&quot;&gt;Windows Console, Visual Studio, Git, Obsidian, Trello&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 기능&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #ffffff; color: #333333; text-align: start; border-collapse: collapse; width: 100%; height: 104px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;기능&lt;/td&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;Player 이동 및 조작&lt;/td&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;마우스 드래그 기능, 마우스 우클릭으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;충돌 처리&lt;/td&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;Quadtree 공간 분할로 확장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;color: #333333; height: 16px;&quot;&gt;A* Algorithm&lt;/td&gt;
&lt;td style=&quot;color: #333333; height: 16px;&quot;&gt;Actor의 이동에 최적의 이동 계산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;디버그 모드&lt;/td&gt;
&lt;td style=&quot;color: #333333; height: 22px;&quot;&gt;화면에 Quadtree 디버그 라인 표시, A* algorithm, closed path, best path 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 기획 목표&amp;nbsp;&lt;/h2&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; 기획의도 및 목표&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;게임 분석:&lt;br /&gt;QuadTree 기술과 A* Algorithm 계산을 안정적으로 실행하고 시각화하는 것.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;구현 목표:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;안정적인 QuadTree계산과 시각화&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;안정적인 A* Algorithm 계산과 시각화&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;마우스 인풋을 활용한 드래그 기능 및 클릭 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;성장 목표:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;엔진 루프(GameLevel Tick) 구조 이해와 제어(dt/pause)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;자료구조 기반 최적화(Quadtree, A* Algorithm, 유닛 점유 그리드)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;문서화 습관(일지, 이슈 분류, 재발 방지 기록) - Obsidian, Trello, Git&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; 기록 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;문서화:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;솔로 프로젝트였기 때문에 기록에 집중&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Obsidian, Trello 기반 개발일지/체크리스트/이슈 로그로 문서화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Git 전략:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;개발 과정에서 예기치 못한 버그에 대비해 빠른 롤백이 가능하도록 자주 커밋&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;솔로 프로젝트였기 때문에 branch는 만들지 않았고, 원활한 작은 기능(Git 사용 여부 및 브랜치 전략)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;이슈 트래킹 방식:&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Obsidian 체크리스트 + 날짜별 로그 + 이슈 분류(억까 버그/내 실력 버그/배우기 좋은 버그)로 관리&lt;br /&gt;Trello : 칸반, 카드 활용 즉시 Todo 생성 및 Doing, Testing, Done카드로 옮겨가며 프로젝트 팔로우 빠르게 가능&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;&amp;nbsp;3. 핵심기능 구현&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;3-1. A* 길 찾기 알고리즘 구현&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능 소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드래그로 선택된 유닛에게 마우스 우클릭으로 이동 명령을 내리면, 해당 유닛은 현재 위치에서 목표 지점까지의 최적 경로를 A* 알고리즘으로 계산하고 그 경로를 따라 이동한다. 경로 위에 벽이 있거나 다른 유닛이 길을 막고 있으면 이를 회피하고, 이동 중에 막히면 즉시 새 경로를 다시 계산한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A* 알고리즘의 기본 구조는 Open List와 Closed List를 관리하면서 f(n) = g(n) + h(n) 공식으로 다음에 탐색할 노드를 결정하는 방식이다. 여기서 g(n)은 출발지부터 현재 노드까지의 실제 비용이고, h(n)은 현재 노드에서 목적지까지의 추정 비용인 휴리스틱이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휴리스틱으로는 맨해튼 거리(abs(dx) + abs(dy))를 선택했다. 상하좌우 4방향 이동만 지원하기 때문에 맨해튼 거리가 실제 이동 비용을 가장 정확하게 추정한다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기술적 도전 &amp;mdash; 유닛 크기 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 좌표 한 칸만 보는 게 아니라 유닛의 전체 크기 영역을 고려해야 했다. 예를 들어 유닛이 3 &amp;times;3 크기라면, 경로의 특정 노드에 도달했을 때 유닛의 몸체가 차지하는 3&amp;times;3 영역 전체에 대해 벽이나 다른 유닛과의 충돌 여부를 확인해야 한다. 단순히 현재 좌표 한 점만 검사하면 이동 중에 벽이나 다른 유닛과 겹치는 현상이 발생한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이중 장애물 회피 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애물 확인은 두 가지 경로로 분리했다. 벽은 IsBlockedByMap() 함수로 타일 배열을 직접 조회하고, 다른 유닛의 위치는 &lt;b&gt;유닛 점유 그리드&lt;/b&gt;를 통해 O(1)로 조회한다. 이 두 가지 확인을 동시에 통과해야 해당 칸으로 이동 가능하다고 판단한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;재탐색 로직&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로를 계산한 이후에도 다른 유닛이 이동해 길을 막는 상황이 발생할 수 있다. 이를 대비해 이동 중에 막히면 즉시 A*를 재실행하는 재탐색 로직을 구현했다. 단, 재탐색을 무제한으로 허용하면 여러 유닛이 동시에 재탐색을 반복할 때 FPS가 급격히 떨어진다. 실험을 통해 재탐색 횟수를 최대 3회로 제한하는 것이 경로 안정성과 성능 사이의 균형점임을 확인했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘을 이론으로 이해하는 것과 실제로 게임에 통합해 돌아가게 만드는 것은 완전히 다른 문제였다. 특히 유닛 크기, 동적으로 변하는 장애물, 성능 제한 같은 현실적인 제약 조건들이 알고리즘 구현을 훨씬 복잡하게 만든다. 이론 공부와 구현 연습을 병행하는 것의 중요성을 실감했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-2. 유닛 점유 그리드&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능 소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵의 각 타일 칸에 현재 그 칸을 점유하고 있는 유닛이 무엇인지를 기록하는 2차원 배열 구조다. A* 탐색 과정에서 특정 좌표를 이동 가능 여부를 판단할 때 이 배열을 조회한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정과 도입 배경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 A* 탐색 중에 유닛과의 충돌 확인을 QuadTree로 처리하려 했다. QuadTree가 공간 탐색을 빠르게 해 준다고 생각했기 때문이다. 그런데 실제로 구현해 보니 A*는 경로 하나를 계산하는 동안 수십에서 수백 번의 충돌 확인을 반복한다. 게다가 유닛 수가 많아질수록 이 반복 횟수는 더 늘어난다. QuadTree 쿼리는 그 자체로도 동적 갱신 비용이 있어서, 이렇게 고빈도로 호출하기에는 너무 무거웠다. FPS가 눈에 띄게 떨어지는 것을 확인하고 다른 방법을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 단순했다. 맵 전체를 2차원 배열로 만들고, 유닛이 이동할 때마다 이전 위치를 null로, 새 위치를 해당 유닛 참조로 업데이트하는 방식이다. A* 탐색 중에는 이 배열을 &lt;u&gt;좌표로 직접 인덱싱&lt;/u&gt;하는 O(1) 조회 한 번으로 유닛 존재 여부를 확인할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;효과&lt;/h3&gt;
&lt;div&gt;방식유닛 확인 비용특이사항
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;QuadTree (이전)&lt;/td&gt;
&lt;td&gt;O(log n) ~ O(n)&lt;/td&gt;
&lt;td&gt;동적 갱신 비용 추가 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;점유 그리드 (현재)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;배열 인덱스 조회 1회&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닛 수가 늘어날수록 성능 차이는 더욱 극명해진다. QuadTree는 데이터가 많을수록 탐색 비용이 늘어나지만, 점유 그리드는 유닛 수와 무관하게 항상 O(1)을 유지한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;공간 탐색이 필요하면 무조건 공간 분할 자료구조&quot;라는 선입견이 얼마나 위험한지 배웠다. 해결하려는 문제의 접근 패턴을 먼저 분석하는 것이 중요하다. 고빈도 반복 조회가 필요한 상황에서는 복잡한 자료구조보다 단순한 배열이 훨씬 나은 선택일 수 있다. 자료구조는 용도에 맞게 선택해야 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-3. QuadTree 공간 분할 충돌 최적화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능 소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵 공간을 재귀적으로 4등분(좌상, 우상, 좌하, 우하)해서 그 구역 안의 Actor를 저장하는 트리 자료구조다. 팀 간 충돌 판정 시 전체 유닛을 순회하는 대신, 대상 유닛 주변 영역과 겹치는 후보만 빠르게 추출하는 데 사용한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 프레임 모든 활성 Actor를 위치 기반으로 QuadTree에 삽입한다. Team A 유닛의 충돌 판정이 필요할 때 Query()를 호출하면 해당 유닛의 영역과 겹치는 후보 목록만 반환된다. 반환된 목록에서 Team B 유닛만 필터링한 뒤, TestIntersect()로 AABB 충돌과 layer/mask 조건을 동시에 확인해 최종 충돌 여부를 결정한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;점유 그리드와의 역할 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QuadTree와 점유 그리드를 함께 쓰는 것이 중복처럼 보일 수 있다. 하지만 두 구조는 해결하는 문제가 완전히 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점유 그리드는 A* &lt;b&gt;탐색 중&lt;/b&gt; 특정 타일 칸에 유닛이 있는지를 확인하는 O(1) 룩업 테이블이다. 그리드 단위의 이산적 공간에서 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QuadTree는 A*와 독립적으로, 팀 간 &lt;b&gt;실시간 충돌 판정&lt;/b&gt; 시 근거리 후보를 추려내는 연속 공간 인덱스다. 유닛의 실제 픽셀/좌표 영역 기반으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 구조가 각자의 역할을 맡아야 시스템 전체가 성능과 정확성을 함께 갖출 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;효과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QuadTree 없이 단순 순회로 충돌을 판정하면 O(n&amp;sup2;) 비용이 발생한다. 유닛 수가 10개면 100번, 30개면 900번의 비교가 필요하다. QuadTree를 도입하면 공간적으로 멀리 있는 유닛은 후보에서 처음부터 제외되므로 실제 비교 횟수가 대폭 줄어든다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 문제를 하나의 완벽한 자료구조로 해결하려는 생각보다, 각 구조의 강점을 파악하고 문제의 특성에 맞게 조합하는 것이 더 현실적이고 효과적인 설계라는 것을 배웠다. QuadTree, 점유 그리드, A*는 서로 다른 레이어에서 서로 다른 문제를 해결하며 시스템을 완성한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3-4. 마우스 입력 &amp;amp; 드래그 UI&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능 소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스 좌클릭 드래그로 범위 안의 유닛을 다중 선택하고, 우클릭으로 선택된 유닛 전체에 이동 명령을 일괄 전달하는 UI 시스템이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔 환경에서 마우스 입력을 처리하기 위해 Windows API 기반의 MOUSE_EVENT_RECORD를 활용했다. 드래그 선택은 마우스 버튼을 누른 시작 좌표와 현재 좌표로 사각형 영역을 계산하고, 해당 영역 안에 포함된 Actor를 선택 상태로 전환하는 방식으로 구현했다. 선택된 유닛은 시각적으로 구분되도록 표시 처리도 함께 했다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;트러블 슈팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레벨이 바뀔 때 system(&quot;cls&quot;)를 사용했는데 이 함수가 mouse inputsystem mode가 초기화되던 문제를 발견하고, 최초에만 설정하던 mode를 매 level이 변경될 때마다 변경해 주어서 해결하였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 프로젝트 기록 &amp;amp; 추적 시스템&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Obsidian, Git, Trello 세 가지 도구를 각각의 역할에 맞게 운영했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Obsidian&lt;/b&gt;은 개발 과정에서 만든 모든 기술 지식의 허브였다. A*와 QuadTree를 설계하는 과정에서 떠오른 아이디어, 구조 결정의 근거, 트러블슈팅 원인과 해결 과정을 모두 마크다운 문서로 정리했다. 특히 알고리즘 설계 노트는 막힐 때마다 다시 읽으면서 현재 상태를 점검하는 기준점이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Git&lt;/b&gt;은 기능 단위로 커밋해 변경 이력을 관리했다. 버그가 발생했을 때 어느 커밋 이후부터 문제가 생겼는지 이력을 추적하고, 필요하면 롤백해 문제 지점을 복원할 수 있었다. 이는 디버깅 시간을 크게 단축시켜 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Trello&lt;/b&gt;는 할 일 관리 보드로 운영했다. TODO/DOING/DONE의 칸반 방식으로 기능 구현 상태를 시각화했고, 버그가 발생하면 즉시 카드를 만들어 이슈를 추적했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도구를 쓰는 것 자체가 목적이 되어선 안 된다. 각 도구가 해결하는 문제를 명확히 이해하고, 그 도구가 가장 잘 맞는 용도에만 쓰는 것이 중요하다. Obsidian은 지식 축적, Git은 이력 관리, Trello는 작업 흐름 관리로 역할을 분리했기 때문에 세 도구가 서로 충돌하지 않고 보완하는 구조가 되었다.&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;h1&gt;5. 트러블 슈팅&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ISSUE 1. 마우스 입력 모드 초기화 문제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 생성 후 마우스 우클릭으로 이동 명령을 내리면 정상적으로 동작해야 하는데, 특정 시점 이후부터 마우스 클릭이 전혀 반응하지 않거나 엉뚱한 동작을 했다. 처음에는 이동 명령 로직 자체의 문제라고 생각하고 해당 부분을 집중적으로 들여다봤지만 코드에는 문제가 없었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범위를 넓혀 추적하던 중 system(&quot;cls&quot;)를 호출하는 시점과 문제가 발생하는 시점이 일치한다는 것을 발견했다. 레벨이 바뀌는 시점에 콘솔 화면을 지우기 위해 system(&quot;cls&quot;)를 실행하면 콘솔의 입력 모드 설정이 초기화되는 부작용이 있었다. 마우스 입력을 받으려면 SetConsoleMode()로 ENABLE_MOUSE_INPUT 플래그를 활성화해야 하는데, system(&quot;cls&quot;) 호출 이후 이 설정이 기본값으로 되돌아가면서 마우스 입력이 무시되었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 핵심이 system(&quot;cls&quot;)의 부작용임을 파악한 뒤, 레벨이 바뀌거나 화면을 지울 때마다 ProcessInput()에서 명시적으로 마우스 입력 모드를 다시 설정하는 것으로 해결하였다. 레벨 전환 시마다 SetConsoleMode()를 호출해 마우스 모드를 명시적으로 복원하는 코드를 추가했다. 이후 마우스 입력이 안정적으로 동작했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;system()류 함수는 운영체제 수준에서 프로세스를 실행하기 때문에 현재 프로그램의 상태에 예상치 못한 부작용을 줄 수 있다. 특히 콘솔 모드 설정처럼 프로세스별로 관리되는 상태는 외부 명령 실행 후 변경될 수 있다는 점을 알아두어야 한다. 중요한 시스템 설정은 외부 호출 전후로 명시적으로 복원하는 방어적 코딩이 필요하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ISSUE 2. Actor 삭제 시 메모리 충돌&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레벨을 종료하거나 전환할 때 게임이 갑자기 크래시 되는 현상이 반복적으로 발생했다. 항상 같은 시점, 즉 레벨 삭제 과정에서 터졌기 때문에 해당 흐름을 집중적으로 살펴봤다. 디버거로 확인하니 이미 해제된 메모리 주소에 다시 delete를 시도하는 이중 해제(double free) 오류였다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor 객체의 포인터가 여러 곳에서 관리되고 있었다. Actor는 씬의 Actor 목록에도 등록되어 있고, 팀의 유닛 목록에도 같은 포인터가 들어 있었다. 레벨을 삭제하는 과정에서 씬이 먼저 Actor를 delete 하고, 이후 팀도 동일한 Actor를 delete 하려 시도하면서 이미 해제된 메모리를 다시 해제하는 문제가 발생했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SafeDelete() 매크로 혹은 함수를 도입했다. 이 함수는 포인터가 nullptr인지 먼저 확인하고, nullptr가 아닌 경우에만 delete를 수행한 뒤 포인터를 nullptr로 설정하는 구조다. 삭제 후 포인터를 nullptr로 만들기 때문에 같은 포인터로 두 번 delete를 시도해도 두 번째 호출에서는 아무런 동작도 하지 않는다. 크래시가 완전히 사라졌다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;cpp&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;// SafeDelete 예시
template &amp;lt;typename T&amp;gt;
void SafeDelete(T*&amp;amp; ptr) {
    if (ptr != nullptr) {
        delete ptr;
        ptr = nullptr;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 객체를 여러 컨테이너에서 동시에 소유권을 갖는 구조는 생명 주기 관리가 복잡해진다. 이 문제를 근본적으로 해결하려면 소유권을 명확히 한 곳에만 두고 다른 곳은 약한 참조만 유지하거나, 현대 C++의 shared_ptr/weak_ptr 같은 스마트 포인터를 활용하는 것이 좋다. 이번에는 SafeDelete로 방어적으로 처리했지만, 소유권 설계 자체를 처음부터 명확히 하는 것이 더 본질적인 해결책이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ISSUE 3. 다수 유닛 이동 명령 시 FPS 급락 (핵심 이슈)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닛 수가 적을 때는 괜찮았지만 10개 이상의 유닛에 동시에 이동 명령을 내리면 게임이 버벅거리기 시작했다. 유닛 수가 늘어날수록 FPS 하락이 두드러졌고, 30개 이상이 되면 거의 슬라이드쇼 수준이 되었다. 처음에는 A* 알고리즘 자체의 탐색 복잡도 문제라고 생각했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인 분석 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로파일링과 코드 검토를 통해 병목이 A* 알고리즘의 탐색 자체가 아니라, &lt;b&gt;탐색 중 매 노드마다 호출하는 충돌 확인 로직&lt;/b&gt;에 있다는 것을 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 구조는 A* 탐색 중에 특정 좌표가 다른 유닛에 의해 막혀 있는지 확인하기 위해 매번 QuadTree에 쿼리를 날리고 있었다. 경로 하나를 계산하는 동안 수십~수백 번의 QuadTree 쿼리가 발생하고, 여러 유닛이 동시에 A*를 실행하면 이 쿼리 횟수가 곱해진다. 여기에 QuadTree는 매 프레임 전체를 재구성해야 하는 갱신 비용도 있었다. 결과적으로 O(n&amp;sup2;)에 가까운 연산이 매 프레임 발생하고 있었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 아이디어는 &lt;b&gt;A* 탐색 중 사용하는 유닛 확인 자료구조를 QuadTree에서 점유 그리드로 교체&lt;/b&gt;하는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점유 그리드는 맵과 동일한 크기의 2차원 배열로, 각 칸에 그 칸을 점유한 유닛의 포인터(또는 null)를 저장한다. 유닛이 이동할 때마다 이전 위치를 null로, 새 위치를 해당 유닛으로 갱신한다. A* 탐색 중에는 grid [y][x]!= null이면 이동 불가 칸으로 판단한다. 배열 인덱스 조회 한 번이므로 O(1)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 재탐색 횟수를 최대 3회로 제한했다. 여러 유닛이 동시에 재탐색을 무한히 반복하면 프레임당 처리량이 폭증하기 때문이다. 3회 안에 경로를 찾지 못하면 현 위치에서 대기하도록 했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수치 비교&lt;/h3&gt;
&lt;div&gt;유닛 수QuadTree 방식 (이전)점유 그리드 방식 (이후)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10개&lt;/td&gt;
&lt;td&gt;버벅거림 시작&lt;/td&gt;
&lt;td&gt;원활&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30개&lt;/td&gt;
&lt;td&gt;슬라이드쇼 수준&lt;/td&gt;
&lt;td&gt;정상 범위 FPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;확인 비용&lt;/td&gt;
&lt;td&gt;O(log n) + 갱신 비용&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 문제를 만났을 때 &quot;이 알고리즘이 느린 것&quot;이라고 바로 단정하지 말고, &lt;b&gt;어느 구체적인 연산이 얼마나 자주 실행되는가&lt;/b&gt;를 먼저 파악해야 한다. 이번 경우 A* 자체는 문제가 아니었다. 문제는 A* 내부에서 고빈도로 반복 호출되는 확인 로직이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;시각자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;주요 기능 화면&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;A* Algorithm으로 구현 한 Title&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;랜덤맵 생성(미로맵)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;TeamA (파란 Actor)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;TeamB (빨간 Actor)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;보라색 pixel(Closed Path)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;노란색 pixel(Best Path)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;화면상 Quad로 나눠지는 Debug Line&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;TitleVideo.gif&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmmc9c/dJMcagEMXaW/Hpw2GTkWVKvWugSBJKFJrK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmmc9c/dJMcagEMXaW/Hpw2GTkWVKvWugSBJKFJrK/img.gif&quot; data-alt=&quot;A* Algorithm으로 구현 한 Title&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmmc9c/dJMcagEMXaW/Hpw2GTkWVKvWugSBJKFJrK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cmmc9c/dJMcagEMXaW/Hpw2GTkWVKvWugSBJKFJrK/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;426&quot; height=&quot;240&quot; data-filename=&quot;TitleVideo.gif&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;A* Algorithm으로 구현 한 Title&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2739&quot; data-origin-height=&quot;1368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RBNsc/dJMcac3pdNu/fD8lh3Q7TBo9RV3gDMy8q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RBNsc/dJMcac3pdNu/fD8lh3Q7TBo9RV3gDMy8q0/img.png&quot; data-alt=&quot;랜덤맵 생성(미로맵)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RBNsc/dJMcac3pdNu/fD8lh3Q7TBo9RV3gDMy8q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRBNsc%2FdJMcac3pdNu%2FfD8lh3Q7TBo9RV3gDMy8q0%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;606&quot; height=&quot;303&quot; data-origin-width=&quot;2739&quot; data-origin-height=&quot;1368&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;랜덤맵 생성(미로맵)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pSj0Y/dJMcahDEpV4/PKh7iQwF2xkVwxArayf2M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pSj0Y/dJMcahDEpV4/PKh7iQwF2xkVwxArayf2M1/img.png&quot; data-alt=&quot;TeamA&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pSj0Y/dJMcahDEpV4/PKh7iQwF2xkVwxArayf2M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpSj0Y%2FdJMcahDEpV4%2FPKh7iQwF2xkVwxArayf2M1%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;557&quot; height=&quot;454&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TeamA&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGrgE/dJMcagrdRhP/wzccZFNokEw9gvqogG0NbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGrgE/dJMcagrdRhP/wzccZFNokEw9gvqogG0NbK/img.png&quot; data-alt=&quot;보라색 pixel(Closed Path)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGrgE/dJMcagrdRhP/wzccZFNokEw9gvqogG0NbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGrgE%2FdJMcagrdRhP%2FwzccZFNokEw9gvqogG0NbK%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;535&quot; height=&quot;280&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;보라색 pixel(Closed Path)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs9tIa/dJMcacbijnY/iIGZDnUykFPKxEdQFiwSh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs9tIa/dJMcacbijnY/iIGZDnUykFPKxEdQFiwSh0/img.png&quot; data-alt=&quot;TeamA와 TeamB&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs9tIa/dJMcacbijnY/iIGZDnUykFPKxEdQFiwSh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs9tIa%2FdJMcacbijnY%2FiIGZDnUykFPKxEdQFiwSh0%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;362&quot; height=&quot;393&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TeamA와 TeamB&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Quadtree.gif&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ovedE/dJMcab4v97W/9aPkHWGnXPkmCvINeZ7C90/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ovedE/dJMcab4v97W/9aPkHWGnXPkmCvINeZ7C90/img.gif&quot; data-alt=&quot;Quadtree 시각화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ovedE/dJMcab4v97W/9aPkHWGnXPkmCvINeZ7C90/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ovedE/dJMcab4v97W/9aPkHWGnXPkmCvINeZ7C90/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;731&quot; height=&quot;412&quot; data-filename=&quot;Quadtree.gif&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Quadtree 시각화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>원티드 포텐업 게임개발 4기</category>
      <category>2차 프로젝트</category>
      <category>게임개발</category>
      <category>게임개발4기</category>
      <category>원티드</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/31</guid>
      <comments>https://learn-forever.tistory.com/31#entry31comment</comments>
      <pubDate>Sun, 15 Mar 2026 21:30:01 +0900</pubDate>
    </item>
    <item>
      <title>베오메오 게임개발일지 - 2화</title>
      <link>https://learn-forever.tistory.com/30</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UWa9K/dJMcacPTzus/VN1wJ8g906tMQxx0AKDvMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UWa9K/dJMcacPTzus/VN1wJ8g906tMQxx0AKDvMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UWa9K/dJMcacPTzus/VN1wJ8g906tMQxx0AKDvMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUWa9K%2FdJMcacPTzus%2FVN1wJ8g906tMQxx0AKDvMk%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8AwoY/dJMcabXKQ1S/PaVxfYMBKYToKdjBBEPcYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8AwoY/dJMcabXKQ1S/PaVxfYMBKYToKdjBBEPcYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8AwoY/dJMcabXKQ1S/PaVxfYMBKYToKdjBBEPcYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8AwoY%2FdJMcabXKQ1S%2FPaVxfYMBKYToKdjBBEPcYK%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1QYrb/dJMcaaEy0zz/8K53KKnPzIUYB4hI7k3lCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1QYrb/dJMcaaEy0zz/8K53KKnPzIUYB4hI7k3lCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1QYrb/dJMcaaEy0zz/8K53KKnPzIUYB4hI7k3lCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1QYrb%2FdJMcaaEy0zz%2F8K53KKnPzIUYB4hI7k3lCK%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eytlk2/dJMcajam2S0/OnGAZf0gYNwyrCR50C1ax1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eytlk2/dJMcajam2S0/OnGAZf0gYNwyrCR50C1ax1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eytlk2/dJMcajam2S0/OnGAZf0gYNwyrCR50C1ax1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feytlk2%2FdJMcajam2S0%2FOnGAZf0gYNwyrCR50C1ax1%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KGtO8/dJMcajam2SZ/voZPaWmFaRNg3iKUOhwBA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KGtO8/dJMcajam2SZ/voZPaWmFaRNg3iKUOhwBA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KGtO8/dJMcajam2SZ/voZPaWmFaRNg3iKUOhwBA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKGtO8%2FdJMcajam2SZ%2FvoZPaWmFaRNg3iKUOhwBA1%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260314_193128728_05.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cil3gn/dJMcabXKQ2b/ZkmmzJ3pV5gsUW1DAtRkTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cil3gn/dJMcabXKQ2b/ZkmmzJ3pV5gsUW1DAtRkTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cil3gn/dJMcabXKQ2b/ZkmmzJ3pV5gsUW1DAtRkTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcil3gn%2FdJMcabXKQ2b%2FZkmmzJ3pV5gsUW1DAtRkTK%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260314_193128728_05.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구독하고 다음 화에서 만나요! 더 많은 이야기가 기다리고 있어요!&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팔로우하고 새로운 작품을 만나보세요!&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;https://www.instagram.com/beomeo_studio/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773484513216&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;로그인 &amp;bull; Instagram&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.instagram.com&quot; data-og-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot; data-og-url=&quot;https://www.instagram.com/beomeo_studio/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로그인 &amp;bull; Instagram&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.instagram.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>베오메오 개발일지 만화</category>
      <category>게임개발</category>
      <category>베오메오</category>
      <category>인스타툰</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/30</guid>
      <comments>https://learn-forever.tistory.com/30#entry30comment</comments>
      <pubDate>Sat, 14 Mar 2026 20:40:08 +0900</pubDate>
    </item>
    <item>
      <title>베오메오 게임개발일지 - 1화</title>
      <link>https://learn-forever.tistory.com/29</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232701594.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I0ElV/dJMcahKpF0N/bKleRslxzVWwxVguGwD0H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I0ElV/dJMcahKpF0N/bKleRslxzVWwxVguGwD0H1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I0ElV/dJMcahKpF0N/bKleRslxzVWwxVguGwD0H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI0ElV%2FdJMcahKpF0N%2FbKleRslxzVWwxVguGwD0H1%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232701594.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232701594_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wcsMN/dJMcaduoGtp/GKctmgUISo8x741HVpzX3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wcsMN/dJMcaduoGtp/GKctmgUISo8x741HVpzX3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wcsMN/dJMcaduoGtp/GKctmgUISo8x741HVpzX3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwcsMN%2FdJMcaduoGtp%2FGKctmgUISo8x741HVpzX3k%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232701594_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232701594_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CjTby/dJMcafy3NEk/r8JDGCZcvdEwbYbReq1bk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CjTby/dJMcafy3NEk/r8JDGCZcvdEwbYbReq1bk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CjTby/dJMcafy3NEk/r8JDGCZcvdEwbYbReq1bk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCjTby%2FdJMcafy3NEk%2Fr8JDGCZcvdEwbYbReq1bk1%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232701594_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232701594_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt5WI3/dJMcafy3NEl/AghIpF6MMqQMDFeMNk1ar0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt5WI3/dJMcafy3NEl/AghIpF6MMqQMDFeMNk1ar0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt5WI3/dJMcafy3NEl/AghIpF6MMqQMDFeMNk1ar0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt5WI3%2FdJMcafy3NEl%2FAghIpF6MMqQMDFeMNk1ar0%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232701594_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232701594_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xdvBB/dJMcaakcKb1/9hU8RA4tS5RwJOzEJIvQok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xdvBB/dJMcaakcKb1/9hU8RA4tS5RwJOzEJIvQok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xdvBB/dJMcaakcKb1/9hU8RA4tS5RwJOzEJIvQok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxdvBB%2FdJMcaakcKb1%2F9hU8RA4tS5RwJOzEJIvQok%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232701594_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구독하고 다음 화에서 만나요! 더 많은 이야기가 기다리고 있어요!&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팔로우하고 새로운 작품을 만나보세요!&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;https://www.instagram.com/beomeo_studio/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773239685353&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;로그인 &amp;bull; Instagram&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.instagram.com&quot; data-og-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot; data-og-url=&quot;https://www.instagram.com/accounts/login/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로그인 &amp;bull; Instagram&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.instagram.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>베오메오 개발일지 만화</category>
      <category>게임개발</category>
      <category>베오메오</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/29</guid>
      <comments>https://learn-forever.tistory.com/29#entry29comment</comments>
      <pubDate>Thu, 12 Mar 2026 06:00:53 +0900</pubDate>
    </item>
    <item>
      <title>베오메오 게임개발일지 - 프롤로그</title>
      <link>https://learn-forever.tistory.com/28</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bulibi/dJMcadA9sGO/DJPGlklyL9Ehyo3UCnphbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bulibi/dJMcadA9sGO/DJPGlklyL9Ehyo3UCnphbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bulibi/dJMcadA9sGO/DJPGlklyL9Ehyo3UCnphbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbulibi%2FdJMcadA9sGO%2FDJPGlklyL9Ehyo3UCnphbk%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pdAK4/dJMcafy3Nvs/1Uq2PL7jttmIKedSxTzX31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pdAK4/dJMcafy3Nvs/1Uq2PL7jttmIKedSxTzX31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pdAK4/dJMcafy3Nvs/1Uq2PL7jttmIKedSxTzX31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpdAK4%2FdJMcafy3Nvs%2F1Uq2PL7jttmIKedSxTzX31%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116_01.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u49QH/dJMcadA9sGP/fCx2xWSxg7IQWRtijPBHe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u49QH/dJMcadA9sGP/fCx2xWSxg7IQWRtijPBHe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u49QH/dJMcadA9sGP/fCx2xWSxg7IQWRtijPBHe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu49QH%2FdJMcadA9sGP%2FfCx2xWSxg7IQWRtijPBHe0%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116_02.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZJgla/dJMcadA9sGQ/kLoCCglovkYwxFFUWm7oik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZJgla/dJMcadA9sGQ/kLoCCglovkYwxFFUWm7oik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZJgla/dJMcadA9sGQ/kLoCCglovkYwxFFUWm7oik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZJgla%2FdJMcadA9sGQ%2FkLoCCglovkYwxFFUWm7oik%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116_03.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjy3zf/dJMcafy3Nvr/lnbCmAlljjIMxAA8tgp2e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjy3zf/dJMcafy3Nvr/lnbCmAlljjIMxAA8tgp2e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjy3zf/dJMcafy3Nvr/lnbCmAlljjIMxAA8tgp2e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjy3zf%2FdJMcafy3Nvr%2FlnbCmAlljjIMxAA8tgp2e0%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116_04.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20260311_232334116_05.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJcei/dJMcafy3Nvq/F9Ijpia4oHMZIb0QbraK00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJcei/dJMcafy3Nvq/F9Ijpia4oHMZIb0QbraK00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJcei/dJMcafy3Nvq/F9Ijpia4oHMZIb0QbraK00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJcei%2FdJMcafy3Nvq%2FF9Ijpia4oHMZIb0QbraK00%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;2160&quot; height=&quot;2700&quot; data-filename=&quot;KakaoTalk_20260311_232334116_05.png&quot; data-origin-width=&quot;2160&quot; data-origin-height=&quot;2700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구독하고 다음 화에서 만나요! 더 많은 이야기가 기다리고 있어요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팔로우하고 새로운 작품을 만나보세요! &lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;https://www.instagram.com/beomeo_studio/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773239287716&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;로그인 &amp;bull; Instagram&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.instagram.com&quot; data-og-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot; data-og-url=&quot;https://www.instagram.com/accounts/login/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.instagram.com/beomeo_studio/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.instagram.com/beomeo_studio/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로그인 &amp;bull; Instagram&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.instagram.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>베오메오 개발일지 만화</category>
      <category>베오메오#개발일지</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/28</guid>
      <comments>https://learn-forever.tistory.com/28#entry28comment</comments>
      <pubDate>Wed, 11 Mar 2026 23:30:37 +0900</pubDate>
    </item>
    <item>
      <title>1차 프로젝트 회고</title>
      <link>https://learn-forever.tistory.com/27</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;소감&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원티드 포텐업 게임개발 4기 1차 프로젝트를 클리어했다! 주말이 포함된 일정이었지만 안 그래도 짧은 기간 중, 딱 주말에 열이 나고 어지러워서 정말 아무것도 못했다는 점에 아쉬움이 남는다. 물론 처음 계획 했던 QuadTree 시각화는 완성했지만, 비주얼로 보았을 때는 거의 기본 버전 그대로라서 게임성이 떨어진다는 것에 아쉬움이 남는다. 이를 양분 삼아서, 다음 2차 프로젝트에는 어느 정도 게임성을 갖추면서도 내가 원하는 기능을 보여줄 수 있게 기획하고 디버그 기능도 확실하게 만들고 싶다. 1차 프로젝트를 진행하면서 게임 엔진의 큰 그림을 이해하고 활용할 수 있는 기회였어서 좋았고 구현해보고 싶었던 기능과 만들고 싶었던 게임을 제작하면서 정말 재미있었다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특히, 프로젝트 발표 다음날 만들었던 게임을 서로서로 해보는 시간을 가졌는데, 발표로만 보던 게임을 직접 해보니 정말 재미있었고, 다음 프로젝트에는 더 재미있는 게임을 만들고 싶은 마음이 생겨났다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  프로젝트 이름&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 콘솔 뱀서라이크&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 프로젝트 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 소개:&lt;br /&gt;콘솔 환경에서 뱀서류(서바이버) 핵심 루프를 구현한 프로토타입입니다. 자체 엔진 구조를 기반으로 Player/Enemy/Bullet, EXP&amp;middot;레벨업&amp;middot;스탯, 카메라 스크롤 월드, 대량 객체 처리(Object Pooling), 충돌 최적화(AABB &amp;rarr; Quadtree), 디버그 모드를 통합하여 구현-통합-디버깅-최적화의 전 과정을 경험하는 것을 목표로 했습니다.&lt;/li&gt;
&lt;li&gt;개발 기간:&lt;br /&gt;&amp;nbsp;총&amp;nbsp;7일(2026-02-04&amp;nbsp;~&amp;nbsp;2026-02-10&amp;nbsp;+&amp;nbsp;발표&amp;nbsp;준비&amp;nbsp;2026-02-11&amp;nbsp;)&lt;/li&gt;
&lt;li&gt;참여 인원:&lt;br /&gt;개인&amp;nbsp;프로젝트&lt;/li&gt;
&lt;li&gt;현황(결과):
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/jaw-choi/Wanted4_ShootingGame#&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/jaw-choi/Wanted4_ShootingGame#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기술 스택&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;Skill Set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core Tech&lt;/td&gt;
&lt;td&gt;Custom Game Loop(GameLevel Tick), Actor Update Pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gameplay Systems&lt;/td&gt;
&lt;td&gt;Stat/Interface(IStatHolder), LevelUp + Pause, Hit Invincibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI / Behavior&lt;/td&gt;
&lt;td&gt;Vector-based Chasing(normalize 사용), (A* algorithm 검토 후 미적용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collision&lt;/td&gt;
&lt;td&gt;AABB &amp;rarr; Quadtree 전환, Query 파이프라인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimization&lt;/td&gt;
&lt;td&gt;Object Pooling, swap-pop(vector에서 erase할 때), Debug Mode tools(FPS, Actor position, Quadtree 정보)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trouble Shoot&lt;/td&gt;
&lt;td&gt;dllexport와 dllimport 자동화 매크로 사용시 판단 미스 버그 해결, 오브젝트 풀링 BeginPlay()에서 prewarm() 시 프로세스 메모리 무한 증가 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment&lt;/td&gt;
&lt;td&gt;Windows Console, Visual Studio, Git, Obsidian&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 기능&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 286px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;기능&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Player 이동 및 조작&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;키보드 이동, 좌표 출력(디버그 모드 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Enemy 스폰 및 추격&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;랜덤 방향 스폰, Player 추격(방향 벡터 계산, 정규화로 속도 일정)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;자동 공격 시스템&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;가장 가까운 적 탐색 후 일정 시간 마다 자동 발사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Bullet(투사체)&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;방향 벡터 기반 이동, 속도/형변환 이슈 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;스탯 시스템&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Stat struct + IStatHolder 인터페이스 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;HP/피격/무적&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;데미지/게임오버/피격 플래시/무적 시간 알아 볼 수 있는 UI 인터페이스 제작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;EXP/레벨업&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;EXP 드랍, FullExp 20% 증가, 레벨 표시 UI 인터페이스 제작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;레벨업 UI + Pause&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;게임 일시정지 후 중앙 UI에서 선택(방향키)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;충돌 처리&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;AABB 구현 후 Quadtree 공간 분할로 확장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;오브젝트 풀링&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Exp Gem/Enemy/Bullet 메모리 공간 미리 할당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;카메라/월드 확장&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;스크롤링 카메라( worldPos - cameraPos에 Draw), 마진 설정, 잔디 타일링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;디버그 모드&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;화면에 Quadtree 디버그 라인 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 기획 목표 및 협업 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 기획의도 및 목표&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 분석:&lt;br /&gt;뱀서류 장르는 시간이 지날수록 적/탄/아이템 오브젝트가 폭증하기 때문에, &amp;ldquo;대량 객체 처리&amp;rdquo;와 &amp;ldquo;충돌 최적화&amp;rdquo;가 구조적으로 중요합니다. 콘솔 환경에서도 동일한 부담이 발생하므로, 풀링과 공간 분할을 중심으로 성능과 안정성을 설계 과제로 삼았습니다.&lt;/li&gt;
&lt;li&gt;구현 목표:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Player/Enemy/Bullet 등 핵심 class 구조 완성&lt;/li&gt;
&lt;li&gt;HP/EXP/레벨업/스탯 적용 및 UI 통합&lt;/li&gt;
&lt;li&gt;대량 객체 대응(Object Pooling)&lt;/li&gt;
&lt;li&gt;충돌 최적화(AABB &amp;rarr; Quadtree 전환)&lt;/li&gt;
&lt;li&gt;카메라 스크롤 월드 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;성장 목표:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진 루프(GameLevel Tick) 구조 이해와 제어(dt/pause)&lt;/li&gt;
&lt;li&gt;자료구조 기반 최적화(Quadtree, swap-pop)&lt;/li&gt;
&lt;li&gt;메모리/라이프사이클 문제(누수, 반복 호출, 이미 제거된 객체 접근) 디버깅 역량 강화&lt;/li&gt;
&lt;li&gt;문서화 습관(일지, 이슈 분류, 재발 방지 기록) - Obsidian 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 협업 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문서화:
&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;Obsidian 기반 개발일지/체크리스트/이슈 로그로 문서화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Git 전략:
&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;솔로 프로젝트였기 때문에 branch는 만들지 않았고, 원활한 작은 기능(Git 사용 여부 및 브랜치 전략)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이슈 트래킹 방식:&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Obsidian 체크리스트 + 날짜별 로그 + 이슈 분류(억까 버그/내 실력 버그/배우기 좋은 버그)로 관리&lt;br /&gt;다음 계획: 만약 팀 프로젝트를 진행한다면 Trello로 전환 예정&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;3. 아키텍처 및 워크플로우&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 아키텍처 특징 및 설계 의도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조적 특징:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GameLevel 중심 게임 루프에서 Actor 리스트를 순회하며 Tick/Render 수행&lt;/li&gt;
&lt;li&gt;레벨업 UI 노출 시 dt 제어로 게임 진행을 일시정지하는 방식 적용&lt;/li&gt;
&lt;li&gt;IStatHolder 인터페이스 + Stat struct로 Player/Enemy 스탯 접근을 공통화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;게임 흐름:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enemy는 Player 포인터(또는 Actor 참조)를 전달받아 target 기반 추격&lt;/li&gt;
&lt;li&gt;Enemy 사망 시 EXP 드롭 &amp;rarr; Player가 수집 &amp;rarr; FullExp 도달 시 레벨업&lt;/li&gt;
&lt;li&gt;레벨업 UI에서 선택된 업그레이드가 Player Stat에 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;확장성/안정성 관점 포인트:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object Pooling으로 런타임 생성/삭제 비용과 단편화 위험을 줄이려는 의도&lt;/li&gt;
&lt;li&gt;충돌은 AABB(베이스) 유지 + Quadtree(확장)로 단계적 최적화&lt;/li&gt;
&lt;li&gt;디버그 모드(좌표/쿼드트리 테스트 기능)로 통합 과정 검증 가능하도록 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 사용자 워크플로우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 흐름:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;게임 시작&lt;/li&gt;
&lt;li&gt;Player 이동&lt;/li&gt;
&lt;li&gt;Enemy 사방 스폰 및 추격&lt;/li&gt;
&lt;li&gt;Player 자동 공격으로 전투&lt;/li&gt;
&lt;li&gt;Enemy 처치 &amp;rarr; EXP 드랍 &amp;rarr; Player 수집&lt;/li&gt;
&lt;li&gt;레벨업 발생 &amp;rarr; 게임 일시정지 + 중앙 UI 표시&lt;/li&gt;
&lt;li&gt;업그레이드 선택 &amp;rarr; 스탯 적용 &amp;rarr; 게임 재개&lt;/li&gt;
&lt;li&gt;피격 시 HP 감소 + 무적 시간/피격 이펙트&lt;/li&gt;
&lt;li&gt;HP 0이면 게임오버/메뉴 전환&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;기능 간 데이터 흐름(Flow chart):&lt;br /&gt;예시: Input &amp;rarr; Player Move &amp;rarr; Enemy MoveTo(Player) &amp;rarr; Collision(AABB/Quadtree) &amp;rarr; Damage/Drop &amp;rarr; EXP Accumulate &amp;rarr; LevelUp UI &amp;rarr; Stat Apply&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 주요 작업&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 오브젝트 풀링(Object Pooling) 적용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 소개:&lt;br /&gt;Enemy/Gem/Bullet 등 반복 생성되는 객체를 미리 풀링 하여 재사용하도록 구현했습니다.&lt;/li&gt;
&lt;li&gt;작업 과정:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀링 대상으로 Gem/Enemy/Bullet 선정&lt;/li&gt;
&lt;li&gt;prewarm 방식으로 초기 풀 확보&lt;/li&gt;
&lt;li&gt;활성/비활성(IsActive) 기준으로 재사용 흐름 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수정/고도화 사항:&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적용 후 프로세스 메모리 무한 증가 이슈 발생 &amp;rarr; 호출 구조 분석 후 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 충돌 처리 최적화: AABB &amp;rarr; Quadtree&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 소개:&lt;br /&gt;기본 AABB 충돌을 구현한 뒤, 대량 객체 상황에서 후보군을 줄이기 위해 Quadtree 공간 분할을 도입했습니다.&lt;/li&gt;
&lt;li&gt;작업 과정:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AABB 충돌 구현(기본 충돌 처리)&lt;/li&gt;
&lt;li&gt;Quadtree 자료구조 구현(Rect 포함)&lt;/li&gt;
&lt;li&gt;AABB/Quadtree 모두 디버그 가능하도록 함수화 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수정/고도화 사항:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;죽은 객체까지 충돌 체크에 포함되던 문제 해결(Actor-&amp;gt;IsActive 필터)&lt;/li&gt;
&lt;li&gt;Query 역할 이해 부족으로 Player-Enemy 충돌 누락 &amp;rarr; 사용 방식 정리 후 수정&lt;/li&gt;
&lt;li&gt;컨테이너 const 문제 해결(const Actor* vs Actor*) - const 객체를 const가 아닌 컨테이너에 넣을 수 없음!&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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 문제 해결 및 기술적 도전&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 이슈 1: 오브젝트 풀링 이후 프로세스 메모리 무한 증가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제 상황:&lt;br /&gt;오브젝트 풀링 적용 이후 프로세스 메모리가 지속적으로 증가(무한 증가)하는 현상이 발생했습니다.&lt;/li&gt;
&lt;li&gt;원인 분석:&lt;br /&gt;beginPlay()가 루프 내부에 있고 hasbeganplay로 거르는 구조였는데, GameLevel 단계의 beginPlay()에 불리는 prewarm은 Actor 산하의 hasbeganplay로 차단되지 않아 tick마다 beginPlay/prewarm이 반복 호출되며 리소스가 계속 누적되는 구조였습니다.&lt;/li&gt;
&lt;li&gt;해결 방법:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선택지 1: hasbeganplay 플래그가 prewarm까지 포함하도록 구조 변경&lt;/li&gt;
&lt;li&gt;선택지 2: beginPlay를 루프 외부로 이동하거나, prewarm을 명시적 1회 호출로 분리&lt;br /&gt;최종 해결책: GameLevel의 hasbeganplay를 생성하고 따로 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해결 과정:&lt;br /&gt;호출 위치/주기 확인 &amp;rarr; tick에서 반복 실행됨을 확인 &amp;rarr; 초기화 루틴을 1회성으로 분리/보장하도록 수정&lt;/li&gt;
&lt;li&gt;해결 결과:&lt;br /&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; 이슈 2: Quadtree 전환 후 메모리 에러 및 충돌 누락&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도전 과제:&lt;br /&gt;AABB에서 Quadtree로 전환하며 Enemy 사망 시 메모리 에러(delete array, 접근 오류)와 Player-Enemy 충돌 누락이 발생했습니다.&lt;/li&gt;
&lt;li&gt;원인 분석:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;죽은 Enemy까지 충돌 체크/Query에 포함되어 이미 제거/비활성 객체 접근 가능성이 생김&lt;/li&gt;
&lt;li&gt;Query 역할 이해 부족으로 충돌 판정 흐름이 깨짐&lt;/li&gt;
&lt;li&gt;디버그 시각화는 라인이 따라오는데 실제 정보가 첫 화면 기준으로 고정(카메라 좌표계 불일치)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해결 방법:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Actor-&amp;gt;IsActive 필터로 살아있는 객체만 Quadtree 처리&lt;/li&gt;
&lt;li&gt;Query 반환/사용 방식 재정리 후 충돌 흐름 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해결 결과:&lt;br /&gt;메모리 오류 제거 및 Player-Enemy 충돌 정상화&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 기술적 의사결정 기록&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적용 기술:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enemy 추격: A* 시도 후 방향벡터 기반 추격 방식으로 수정&lt;/li&gt;
&lt;li&gt;충돌: AABB &amp;rarr; Quadtree 확장&lt;/li&gt;
&lt;li&gt;대량 객체: Object Pooling&lt;/li&gt;
&lt;li&gt;벡터 메모리 삭제 최적화: swap-pop(O(1) 삭제)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;선택 이유:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A*: 지형/장애물이 없는 상태에서는 효용이 낮고 추격이 어색하게 동작&lt;/li&gt;
&lt;li&gt;방향벡터: 구현 단순 + 안정적 + 정규화로 속도 일관성 확보&lt;/li&gt;
&lt;li&gt;raw pointer: 구현 단순, 메모리 관리 공부(단, 소유권/삭제 책임을 명확히 해야 함)&lt;/li&gt;
&lt;li&gt;swap-pop: 순서 보장 불필요한 컨테이너에서 성능 이점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개선 아이디어:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;A* 의미 확보를 위한 타일 맵/장애물/절차적 맵 생성 추가&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Enemy끼리 충돌 시 버벅거림 &amp;rarr; 충돌 Layer 생성 후 충돌 검사 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;raw pointer 구간 소유권 규칙 문서화 및 해제 책임 일원화&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 결과 및 회고&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 결과&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목표 달성도:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Player/Enemy/Bullet + HP/EXP/레벨업 + Pause UI 통합 완료&lt;/li&gt;
&lt;li&gt;Object Pooling 및 Quadtree 통합 완료&lt;/li&gt;
&lt;li&gt;카메라 스크롤 월드(잔디 타일링 포함) 완료&lt;/li&gt;
&lt;li&gt;디버그 모드(좌표/Quadtree 라인 등) 일부 완료&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;성과 지표:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stress Test에서 FPS 저하 체감 없음&lt;/li&gt;
&lt;li&gt;vector 삭제(erase) O(N) &amp;rarr; swap-pop으로 O(1) 최적화 적용&lt;/li&gt;
&lt;li&gt;메모리 무한 증가 버그 해결&lt;/li&gt;
&lt;li&gt;Quadtree 통합 후 충돌 정상화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;임팩트 액션:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대량 객체 처리 + 충돌 최적화 + UI/pause + 스탯 시스템을 하나의 루프에 통합&lt;/li&gt;
&lt;li&gt;통합 과정에서 발생한 메모리/흐름/좌표계 문제를 분석-수정하며 프로젝트 수행 역량을 확보&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 회고&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기술 측면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진 루프 관점에서 문제를 추적(super Tick, return flow 등)&lt;/li&gt;
&lt;li&gt;정규화/형변환/const/링킹 등 기본기에서 터지는 버그를 케이스로 축적&lt;/li&gt;
&lt;li&gt;Quadtree 디버그와 카메라 좌표계까지 맞추며 통합 난이도를 경험&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;기록 측면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문서화를 좀 더 형식에 맞춰서 일정하게 매일 남기기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다시 한다면 어떻게 설계할까?:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FPS/메모리 측정 루틴을 프로젝트 초기에 내장&lt;/li&gt;
&lt;li&gt;Quadtree 소유권/해제 책임을 문서로 먼저 확정&lt;/li&gt;
&lt;li&gt;beginPlay/prewarm 같은 초기화 루틴을 1회 보장하는 구조로 고정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시각자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주요 기능 화면&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상단 파란색 바 - 현재 EXP&lt;/li&gt;
&lt;li&gt;상단 빨간색 바 - 현재 HP&lt;/li&gt;
&lt;li&gt;좌측 하단 플레이어 Stat&lt;/li&gt;
&lt;li&gt;카메라 스크롤 월드(잔디 타일 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSWfh/dJMcaiPJBZR/rI6liaSksMckkI5TG22BWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSWfh/dJMcaiPJBZR/rI6liaSksMckkI5TG22BWK/img.png&quot; data-alt=&quot;플레잉 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSWfh/dJMcaiPJBZR/rI6liaSksMckkI5TG22BWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSWfh%2FdJMcaiPJBZR%2FrI6liaSksMckkI5TG22BWK%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;596&quot; height=&quot;396&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1466&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;플레잉 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로파일링&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FPS 출력 화면&lt;/li&gt;
&lt;li&gt;Quadtree 적용 전/후 Stress Test 조건 화면&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;오히려 AABB가 더 빠르다(?) - 사실상 텍스트만 출력하는 게임에서는 큰 성능 차이는 없는 듯하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oB9D2/dJMcafrY64Y/2y0KLTjSOdfHZokRlcs3bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oB9D2/dJMcafrY64Y/2y0KLTjSOdfHZokRlcs3bk/img.png&quot; data-origin-width=&quot;2195&quot; data-origin-height=&quot;1324&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.5287%; margin-right: 10px;&quot; data-widthpercent=&quot;53.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oB9D2/dJMcafrY64Y/2y0KLTjSOdfHZokRlcs3bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoB9D2%2FdJMcafrY64Y%2F2y0KLTjSOdfHZokRlcs3bk%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;2195&quot; height=&quot;1324&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL6kNL/dJMcai3gug3/44ePafmC4dn6reZTatdmkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL6kNL/dJMcai3gug3/44ePafmC4dn6reZTatdmkK/img.png&quot; data-origin-width=&quot;2204&quot; data-origin-height=&quot;1508&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;46.85&quot; style=&quot;width: 46.3085%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL6kNL/dJMcai3gug3/44ePafmC4dn6reZTatdmkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL6kNL%2FdJMcai3gug3%2F44ePafmC4dn6reZTatdmkK%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;2204&quot; height=&quot;1508&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;QuadTree / AABB&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;color: #9d9d9d;&quot;&gt;이미지가 거의 같아 보이지만 구현 방법은 다르다.. 그러나 이 또한 큰 성능 차이는 없는 듯 하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w0qeU/dJMcafld2dB/ZpUsJGKfGAwKngSuqFWiL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w0qeU/dJMcafld2dB/ZpUsJGKfGAwKngSuqFWiL0/img.png&quot; data-origin-width=&quot;2189&quot; data-origin-height=&quot;1497&quot; data-is-animation=&quot;false&quot; width=&quot;442&quot; height=&quot;302&quot; style=&quot;width: 48.2713%; margin-right: 10px;&quot; data-widthpercent=&quot;48.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w0qeU/dJMcafld2dB/ZpUsJGKfGAwKngSuqFWiL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw0qeU%2FdJMcafld2dB%2FZpUsJGKfGAwKngSuqFWiL0%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;2189&quot; height=&quot;1497&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkFk9d/dJMcagEsvGY/BP6joakd8ZqA1na4SjyZdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkFk9d/dJMcagEsvGY/BP6joakd8ZqA1na4SjyZdK/img.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1448&quot; data-is-animation=&quot;false&quot; width=&quot;499&quot; height=&quot;326&quot; style=&quot;width: 50.5659%;&quot; data-widthpercent=&quot;51.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkFk9d/dJMcagEsvGY/BP6joakd8ZqA1na4SjyZdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkFk9d%2FdJMcagEsvGY%2FBP6joakd8ZqA1na4SjyZdK%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;2218&quot; height=&quot;1448&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Object Pooling 으로 미리 공간할당 / 매 프레임 할당과 삭제 반복&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;1차 프로젝트를 되돌아보며&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잘했다고 생각한 점:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문서화와 커밋 전략이 개발 방식으로 자리 잡은 점 - 프로젝트 규모가 커질수록 강점이 될 것&lt;/li&gt;
&lt;li&gt;어려웠던 Quadtree 시각화를 성공해 낸 점 - 어려운 기술도 계속 부딪혀 나감&lt;/li&gt;
&lt;li&gt;발표 피드백으로 프로파일링이 안 되는 것을 고친 점 - 피드백 수용 능력 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;부족
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임규모에 맞게 공통 스탯을 관리하는 클래스로 인터페이스 클래스를 쓴 점 - 현재 게임 규모에서는 좋았던 선택이었을 수 있으나 게임규모가 커진다는 가정 하에 component 설계를 하였으면 확장성이 좋았을 듯&lt;/li&gt;
&lt;li&gt;시간 부족의 핑계로 게임성을 높이지 않은 점 - 기술 구현을 빠르게 끝내고 게임성 높이는 데에도 시간을 두어야 할 듯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>원티드 포텐업 게임개발 4기</category>
      <category>개발</category>
      <category>게임</category>
      <category>원티드</category>
      <category>원티드 포텐업 게임개발 4기</category>
      <category>콘솔</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/27</guid>
      <comments>https://learn-forever.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 13 Feb 2026 19:04:25 +0900</pubDate>
    </item>
    <item>
      <title>2025 NC soft 신입공채 게임 프로그래머 채용 코딩테스트 후기</title>
      <link>https://learn-forever.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;20251025&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔씨소프트 코딩테스트가 있었다. 프로그래머스 사이트로 시험이 진행되었고 총 3문제 120분이 주어졌다. 문제의 난이도는 크게 어렵지 않았다. 1,2번은 간단한 구현 문제여서 문제만 잘 읽고 그대로 표현하면 되는 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 문제는 3번이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;255&quot; data-start=&quot;183&quot; data-ke-size=&quot;size16&quot;&gt;주어진 벡터의 원소들이 각각 무한히 뻗어가는 배수열을 가질 때,&lt;br /&gt;그 전체 수열에서 &lt;b&gt;k번째로 작은 수&lt;/b&gt;를 구하는 문제와 비슷하였다.&lt;/p&gt;
&lt;p data-end=&quot;476&quot; data-start=&quot;257&quot; data-ke-size=&quot;size16&quot;&gt;처음 문제를 읽었을 때는 &amp;ldquo;이건 간단하겠는데?&amp;rdquo; 싶었다.&lt;br /&gt;배수들을 전부 나열해서 정렬한 다음, k번째 원소를 찾으면 되겠다고 생각했다.&lt;br /&gt;하지만 곧바로 그 방식은 &lt;b&gt;TLE(Time Limit Exceeded)&lt;/b&gt; 이 날 수밖에 없다는 걸 깨달았다.&lt;br /&gt;왜냐하면 각 원소의 배수열이 무한히 이어지기 때문에&lt;br /&gt;모든 수를 직접 생성하고 정렬하는 건 &lt;b&gt;불가능한 접근&lt;/b&gt;이었기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;526&quot; data-start=&quot;478&quot; data-ke-size=&quot;size16&quot;&gt;그때부터 본격적으로 &amp;ldquo;이걸 어떻게 유한하게 줄일 수 있을까?&amp;rdquo;라는 고민이 시작됐다.&lt;/p&gt;
&lt;hr data-end=&quot;531&quot; data-start=&quot;528&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;553&quot; data-start=&quot;533&quot; data-ke-size=&quot;size23&quot;&gt;첫 시도: 이분 탐색&lt;/h3&gt;
&lt;p data-end=&quot;645&quot; data-start=&quot;554&quot; data-ke-size=&quot;size16&quot;&gt;평소처럼 &amp;ldquo;k번째 원소를 찾는 문제&amp;rdquo;를 보고 k의 범위가 아주 큰 값이면 자연스럽게 &lt;b&gt;이분 탐색&lt;/b&gt;이 떠오른다.&lt;br /&gt;범위를 잡고 mid 이하의 원소 개수를 세서 조정하면 되겠지 했다.&lt;/p&gt;
&lt;p data-end=&quot;725&quot; data-start=&quot;647&quot; data-ke-size=&quot;size16&quot;&gt;그런데 금방 벽에 부딪혔다.&lt;br /&gt;배수들이 서로 겹치기 때문에 단순히 &amp;ldquo;&amp;lt;= mid&amp;rdquo;인 값의 개수를 정확히 셀 수 없었다.&lt;br /&gt;예를 들어,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;813&quot; data-start=&quot;726&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;813&quot; data-start=&quot;726&quot;&gt;12는 3&amp;times;4로도, 4&amp;times;3으로도 만들어질 수 있다.&lt;br /&gt;이 중복이 정렬 순서를 교란시켜버리기 때문에,&lt;br /&gt;이분 탐색으로는 정확한 순서를 구할 수 없었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;818&quot; data-start=&quot;815&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;848&quot; data-start=&quot;820&quot; data-ke-size=&quot;size23&quot;&gt;사고 전환: 유한한 부분으로 줄이기&lt;/h3&gt;
&lt;p data-end=&quot;909&quot; data-start=&quot;849&quot; data-ke-size=&quot;size16&quot;&gt;&amp;lsquo;무한히 뻗어가니 답이 없다고 생각했지만,&lt;br /&gt;k번째 작은 수는 어차피 &lt;b&gt;유한한 구간 안에&lt;/b&gt; 존재한다.&amp;rsquo;&lt;/p&gt;
&lt;p data-end=&quot;1011&quot; data-start=&quot;911&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 {1,2,3,4}에서 k = 29라면,&lt;br /&gt;벡터 크기 n이 4이므로 k보다 큰 4의 배수 중 가장 작은 값은 32다.&lt;br /&gt;즉, &lt;b&gt;8배수까지만 보면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1031&quot; data-start=&quot;1013&quot; data-ke-size=&quot;size16&quot;&gt;그럼 가능한 값들은 다음과 같다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;1,2,3,4,5,6,7,8, 2,4,6,8,10,12,14,16, 3,6,9,12,15,18,21,24, 4,8,12,16,20,24,28,32 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1221&quot; data-start=&quot;1124&quot; data-ke-size=&quot;size16&quot;&gt;여기서 정렬하면 29번째 원소는 24가 된다.&lt;br /&gt;즉, 문제는 **무한한 수열이 아니라,&lt;br /&gt;&amp;lsquo;k보다 큰 벡터 크기의 배수까지 제한된 부분 문제&amp;rsquo;**로 축소할 수 있었다.&lt;/p&gt;
&lt;hr data-end=&quot;1226&quot; data-start=&quot;1223&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1264&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size23&quot;&gt;전환점: priority_queue(우선순위 큐)&lt;/h3&gt;
&lt;p data-end=&quot;1341&quot; data-start=&quot;1265&quot; data-ke-size=&quot;size16&quot;&gt;문제를 다시 바라보다가 문득 priority_queue가 떠올랐다.&lt;br /&gt;&amp;lsquo;가장 큰 값들만 관리하면서 하나씩 줄여나가면 되지 않을까?&amp;rsquo;&lt;/p&gt;
&lt;p data-end=&quot;1416&quot; data-start=&quot;1343&quot; data-ke-size=&quot;size16&quot;&gt;그 순간 퍼즐이 맞춰졌다.&lt;br /&gt;각 배수열의 마지막 값(가장 큰 배수)과 어떤 수의 배수인지 알 수 있는 수를 pair 형식으로 힙에 넣고,&lt;br /&gt;가장 큰 수를 하나씩 꺼내며 줄여가면 된다.&lt;/p&gt;
&lt;p data-end=&quot;1425&quot; data-start=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;pq&lt;/span&gt;&lt;/span&gt;&lt;span&gt; = { {&lt;/span&gt;&lt;span&gt;&lt;span&gt;32&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;span&gt;}, {&lt;/span&gt;&lt;span&gt;&lt;span&gt;24&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span&gt;}, {&lt;/span&gt;&lt;span&gt;&lt;span&gt;16&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span&gt;}, {&lt;/span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span&gt;} } &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1506&quot; data-start=&quot;1473&quot; data-ke-size=&quot;size16&quot;&gt;형태로 넣어두면, top은 항상 가장 큰 수(32)가 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1629&quot; data-start=&quot;1508&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1543&quot; data-start=&quot;1508&quot;&gt;top을 꺼내서 4를 빼고 다시 넣는다 &amp;rarr; {28,4}&lt;/li&gt;
&lt;li data-end=&quot;1575&quot; data-start=&quot;1544&quot;&gt;다시 top을 꺼내서 4를 빼고 &amp;rarr; {24,4}&lt;/li&gt;
&lt;li data-end=&quot;1629&quot; data-start=&quot;1576&quot;&gt;&amp;hellip;이 과정을 k번째까지 반복하면,&lt;br /&gt;마지막으로 꺼낸 값이 곧 k번째로 작은 값이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1642&quot; data-start=&quot;1631&quot; data-ke-size=&quot;size16&quot;&gt;이 방식의 핵심은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1745&quot; data-start=&quot;1643&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1669&quot; data-start=&quot;1643&quot;&gt;&lt;b&gt;배수 중복이 자연스럽게 처리되고&lt;/b&gt;,&lt;/li&gt;
&lt;li data-end=&quot;1745&quot; data-start=&quot;1670&quot;&gt;&lt;b&gt;항상 최대 n개의 값만 관리&lt;/b&gt;하기 때문에&lt;br /&gt;k가 아무리 커도 &lt;b&gt;O(n log n)&lt;/b&gt; 수준의 효율로 해결된다는 점이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1750&quot; data-start=&quot;1747&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1769&quot; data-start=&quot;1752&quot; data-ke-size=&quot;size23&quot;&gt;시간복잡도 직관&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1891&quot; data-start=&quot;1770&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1783&quot; data-start=&quot;1770&quot;&gt;n = 벡터 크기&lt;/li&gt;
&lt;li data-end=&quot;1813&quot; data-start=&quot;1784&quot;&gt;k = 매우 큰 수 (최대 10⁸ 이상 가능)&lt;/li&gt;
&lt;li data-end=&quot;1891&quot; data-start=&quot;1814&quot;&gt;하지만 힙에는 n개의 원소만 유지되므로,&lt;br /&gt;각 pop/push가 O(log n), 전체는 O(n log n) 내에 해결 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1897&quot; data-start=&quot;1893&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;blockquote data-end=&quot;1954&quot; data-start=&quot;1898&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1954&quot; data-start=&quot;1900&quot; data-ke-size=&quot;size16&quot;&gt;n이 10,000이고 k가 100,000,000이라도&lt;br /&gt;최대 10,000번만 순회하면 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;1985&quot; data-start=&quot;1961&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;예시: k = 29일 때의 과정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;초기 힙: {32,4}, {24,3}, {16,2}, {8,1} &lt;/span&gt;&lt;span&gt;&lt;span&gt;32번째: top {32,4} &amp;rarr; {28,4}&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;31번째: top {28,4} &amp;rarr; {24,4}&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;30번째: top {24,4} &amp;rarr; {20,4}&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;29번째: top {24,3} &amp;rarr; 답 = 24&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;2135&quot; data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;24&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2150&quot; data-start=&quot;2147&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2164&quot; data-start=&quot;2152&quot; data-ke-size=&quot;size23&quot;&gt;마무리하며&lt;/h3&gt;
&lt;p data-end=&quot;2225&quot; data-start=&quot;2165&quot; data-ke-size=&quot;size16&quot;&gt;이 문제는 단순한 구현 문제가 아니라,&lt;br /&gt;&amp;ldquo;&lt;b&gt;무한을 유한으로 바꾸는 사고의 전환&lt;/b&gt;&amp;rdquo;이 필요한 문제였다.&lt;/p&gt;
&lt;p data-end=&quot;2359&quot; data-start=&quot;2227&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 단순히 모든 배수를 나열하고 정렬하는 단순한 brute-force 접근이 떠올랐고,&lt;br /&gt;그다음엔 이분 탐색으로 풀 수 있지 않을까 시도했지만 실패했다.&lt;br /&gt;결국 핵심은 &lt;b&gt;정렬을 뒤집어 시뮬레이션하는 우선순위 큐의 관점&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-end=&quot;2383&quot; data-start=&quot;2361&quot; data-ke-size=&quot;size16&quot;&gt;이 경험을 통해 배운 점은 명확하다.&lt;/p&gt;
&lt;blockquote data-end=&quot;2451&quot; data-start=&quot;2384&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2451&quot; data-start=&quot;2386&quot; data-ke-size=&quot;size16&quot;&gt;문제를 풀 때는 &lt;b&gt;풀어야 할 데이터의 크기&lt;/b&gt;가 아니라,&lt;br /&gt;&lt;b&gt;&amp;ldquo;진짜 필요한 범위&amp;rdquo;를 먼저 찾아내야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>코딩테스트</category>
      <category>c++</category>
      <category>priority_queue</category>
      <category>문제풀이</category>
      <category>알고리즘</category>
      <category>코딩테스트</category>
      <category>회고</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/25</guid>
      <comments>https://learn-forever.tistory.com/25#entry25comment</comments>
      <pubDate>Fri, 19 Dec 2025 18:00:13 +0900</pubDate>
    </item>
    <item>
      <title>DrawCall을 줄여야 하는 이유, drawcall,batches,setpass call</title>
      <link>https://learn-forever.tistory.com/26</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;게임개발에서 드로우콜을 줄여야하는 것은 개발자의 의무이다. 그렇다면 드로우콜은 무엇이고 왜 줄여야 하며 줄이는 방법에는 무엇이 있을까? 더하여 드로우콜과 batches 그리고 setpass call은 무엇일까?&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;본론&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;251&quot; data-start=&quot;173&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Draw Call&lt;/b&gt;은 CPU가 GPU에게&lt;br /&gt;&amp;ldquo;이 오브젝트를 이 머티리얼과 셰이더로 렌더링하라&amp;rdquo;&lt;br /&gt;라고 명령하는 호출 단위입니다.&lt;/p&gt;
&lt;p data-end=&quot;465&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;GPU는 수천 개의 스레드로 병렬 처리가 가능하지만,CPU는 이러한 Draw Call들을 직렬적으로 하나씩 처리해야 합니다.&lt;br /&gt;따라서 &lt;b&gt;Draw Call의 수가 많아지면 CPU가 병목(Bottleneck)&lt;/b&gt; 이 되고,결국 프레임 처리 속도가 떨어집니다.&lt;br /&gt;즉, &lt;b&gt;Draw Call을 줄인다는 것은 CPU의 명령 전송 부담을 줄여 최적화를 한다는 의미&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-end=&quot;470&quot; data-start=&quot;467&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;551&quot; data-start=&quot;472&quot; data-ke-size=&quot;size16&quot;&gt;Unity에서는 &lt;b&gt;Batches&lt;/b&gt;라는 개념을 볼 수 있습니다.이는 Draw Call과 유사하지만, &lt;b&gt;약간 더 큰 개념&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;741&quot; data-start=&quot;553&quot; data-ke-size=&quot;size16&quot;&gt;OpenGL의 렌더링 과정을 예로 들면 다음과 같습니다.오브젝트를 그리기 위해서는&lt;/p&gt;
&lt;p data-end=&quot;741&quot; data-start=&quot;553&quot; data-ke-size=&quot;size16&quot;&gt;glBindBuffer(VBO/IBO), glUseProgram(Shader), glBindTexture(Texture)&lt;br /&gt;등의 &lt;b&gt;바인딩(상태 전환)&lt;/b&gt; 이 먼저 이루어지고,그 다음 glDraw__() 호출이 수행됩니다.이때 &lt;b&gt;같은 상태(State)&lt;/b&gt; 를 공유하는 오브젝트들이 많다면 한 번의 바인딩으로 여러 번의 glDraw__() 호출을 실행할 수 있습니다.&lt;br /&gt;이러한 &lt;b&gt;한 세트의 바인딩과 그 안의 여러 Draw Call 묶음이 Batch&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;1002&quot; data-start=&quot;884&quot; data-ke-size=&quot;size16&quot;&gt;즉, Draw Call은 glDraw__() 호출 하나하나를 의미하지만, Batch는 그보다 상위의 개념으로,&lt;br /&gt;&lt;b&gt;같은 상태에서 연속으로 처리되는 Draw Call들의 묶음&lt;/b&gt;이라고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1166&quot; data-start=&quot;1004&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로, &lt;b&gt;Draw Call의 절대 수보다 Batch의 수를 줄이는 것이 더 직접적인 최적화 효과&lt;/b&gt;를 줍니다.&lt;br /&gt;왜냐하면, Batch를 줄인다는 것은 &lt;b&gt;상태 전환(binding)&lt;/b&gt; 횟수를 줄인다는 뜻이고, 이 바인딩 과정이 CPU에서 수행되며 비용이 매우 비싸기 때문입니다.&lt;/p&gt;
&lt;hr data-end=&quot;1171&quot; data-start=&quot;1168&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1331&quot; data-start=&quot;1173&quot; data-ke-size=&quot;size16&quot;&gt;다음으로 &lt;b&gt;SetPass Call&lt;/b&gt;은 GPU의 실제 렌더링 파이프라인 상태(머티리얼, 셰이더, 텍스처 등)가 변경될 때마다 발생합니다.&lt;br /&gt;즉, glUseProgram, glBindTexture, glBlendFunc 등의 상태 전환이 일어날 때마다 증가합니다.&lt;/p&gt;
&lt;p data-end=&quot;1423&quot; data-start=&quot;1333&quot; data-ke-size=&quot;size16&quot;&gt;SetPass Call은 Batch와 거의 1:1로 대응되며, &lt;b&gt;최종적으로는 SetPass Call을 줄이는 것이 진정한 의미의 렌더링 최적화&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-end=&quot;1428&quot; data-start=&quot;1425&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1497&quot; data-start=&quot;1430&quot; data-ke-size=&quot;size16&quot;&gt;Draw Call을 줄이는 대표적인 방법으로는 &lt;b&gt;Batching&lt;/b&gt;과 &lt;b&gt;GPU Instancing&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1759&quot; data-start=&quot;1499&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1631&quot; data-start=&quot;1499&quot;&gt;&lt;b&gt;Batching&lt;/b&gt;은 여러 오브젝트의 버텍스 데이터를 묶어서 CPU가 한 번에 전달하도록 하여 Draw Call을 줄이는 방법입니다.&lt;br /&gt;(예: Static/Dynamic Batching, SRP Batcher 등)&lt;/li&gt;
&lt;li data-end=&quot;1759&quot; data-start=&quot;1633&quot;&gt;&lt;b&gt;GPU Instancing&lt;/b&gt;은 동일한 머티리얼을 사용하는 오브젝트를 GPU 내부에서 복제하여 렌더링하는 기술입니다.&lt;br /&gt;즉, CPU가 동일한 명령을 여러 번 보내지 않아도 GPU가 병렬적으로 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1764&quot; data-start=&quot;1761&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1776&quot; data-start=&quot;1766&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1885&quot; data-start=&quot;1778&quot; data-ke-size=&quot;size16&quot;&gt;드로우콜을 줄인다는 것은 단순히 호출 수를 줄인다는 의미가 아니라,&lt;br /&gt;&lt;b&gt;CPU에서 비싼 바인딩(State Change)을 최소화하여 GPU의 병렬 성능을 최대한 활용한다는 뜻&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;2014&quot; data-start=&quot;1887&quot; data-ke-size=&quot;size16&quot;&gt;정확히 말하면, &amp;ldquo;Draw Call을 줄인다&amp;rdquo;는 말은 &amp;ldquo;&lt;b&gt;SetPass Call(상태 변경 수)을 줄인다&lt;/b&gt;&amp;rdquo;와 같은 의미이며,&lt;br /&gt;이는 곧 &lt;b&gt;CPU의 부담을 줄이고 GPU가 쉬지 않고 일하게 만드는 최적화의 핵심&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 내용을 바탕으로 개발자 면접 간&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. Drawcall이 무엇인가요?&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. Drawcall을 왜 줄여야 하나요?&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 경험해본 게임 프로젝트에서 Drawcall을 줄이기 위해 했던 노력이 있나요?&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;등에 대한 질문을 생각해 볼 수 있겠다. 스스로에게 질문을 해보고 답해보자.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;헷갈리는 부분은 보완하기! 찡긋 O.&amp;lt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;틀린 부분이나 보완해줬으면 하는 내용이 있으면 댓글로 알려주세요! 추가 설명이 필요하신 부분도 댓글로 알려주세요.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어떠한 피드백도 환영입니다. 긴 글 읽어주셔서 감사합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;출처 : ChatGPT&lt;/p&gt;</description>
      <category>개발면접준비</category>
      <category>batches</category>
      <category>DrawCall</category>
      <category>SetPass Call</category>
      <category>최적화</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/26</guid>
      <comments>https://learn-forever.tistory.com/26#entry26comment</comments>
      <pubDate>Thu, 6 Nov 2025 22:31:25 +0900</pubDate>
    </item>
    <item>
      <title>2025 넥토리얼 - 게임 프로그래머 준비(0)</title>
      <link>https://learn-forever.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2024 넥토리얼, 2025 집중채용에 이어 또 한 번 대규모 공채가 넥슨 메이플에서 나왔다. 이번에도 역시나 준비해보려 한다. 작년 넥토리얼에서는 코딩테스트에서 부터 떨어졌던 기억이 있다. 그 때는 아마 해커랭크라는 사이트에서 진행되었고 시간이 되게 길게 주어졌었던 기억이 있는데 32시간에 5문제였나 여하튼 완전히 새로운 방식에 당황 했던것 같다. 이번 2025 집중채용에서는 코테를 통과하고 1차면접까지 갔었던 만큼 지난 기억들을 살려서 코테 및 1,2차 면접을 통과하길 기원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 집중채용 이후 부터 unity로 포트폴리오를 위한 게임을 개발해왔다. 현재 거의 마무리 단계이고 오늘 자소서를 모두 작성하여 넥토리얼 원서를 냈다. 매번 마찬가지로 서류는 붙게 해줄 것 같다. 문제는 코테 이므로 다가오는 9/20에 있는 코테를 잘 준비해서 다음 과정까지 나아가기를 빌어본다.&lt;/p&gt;</description>
      <category>개발면접준비</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/24</guid>
      <comments>https://learn-forever.tistory.com/24#entry24comment</comments>
      <pubDate>Fri, 12 Sep 2025 18:00:33 +0900</pubDate>
    </item>
    <item>
      <title>NHN 2025 게임공채 I 게임 클라이언트(1)</title>
      <link>https://learn-forever.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;8/23 코딩테스트를 쳤다. 총 3개의 문제가 나왔다. 구현,dp,backtracking 범위로 나왔던 듯하다. 이 중 마지막 backtracking문제에서 조건 설정이 복잡해지면서 시간이 길어졌고 앞선 두 문제는 풀었지만 마지막 문제를 풀지 못했다. 그 다음주 8/26에 바로 결과를 받아 볼 수 있었고. 결과는 불합. 1,2번 문제가 상대적으로 쉬워서 3번 문제로 당락이 결정되었던 듯하다. 여전히 많은 연습과 훈련이 필요한것 같다. 꾸준히 코테를 풀어보면서 준비해보도록 하자.&lt;/p&gt;</description>
      <category>개발면접준비</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/23</guid>
      <comments>https://learn-forever.tistory.com/23#entry23comment</comments>
      <pubDate>Fri, 12 Sep 2025 12:00:31 +0900</pubDate>
    </item>
    <item>
      <title>NHN 2025 게임공채 I 게임 클라이언트(0)</title>
      <link>https://learn-forever.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이제 2025 하반기 게임 공채 시즌이 슬슬 시작되는 것 같다. 물론 9~10월은 되어야 메이저 회사들의 공채가 시작된다고 알고 있지만 NHN도 내가 목표했던 회사중 하나이기 때문에 이번 공채에도 꾸준한 준비를 해왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;NHN 2025 게임공채 I 게임 클라이언트부문 서류 제출일은 8/17까지 였고 제출일까지 3일정도 여유를 두고 자기소개서를 작성하고 제출했다. 결과는 8/20일에 나왔고 서류합격이였다. 코테일정은 8/21에 안내 받았고, 8/23에 바로 시험을 친다고 안내받았다. 물론 개인적인 생각이지만 대부분의 게임회사들은 서류에서 많은 인원을 떨어트리지 않는 것 같다. 어쩌면 100퍼센트 합격일지도 모르고, 내가 지금까지 운이 좋았을 지도 모른다. 대부분 큰 회사의 공채에서는 일단 코딩테스트를 볼 자격은 쉽게 주고 이 후에 그 성적과 서류를 보는 느낌이다. 반면에 규모가 작은 회사들은 경력과 자소서를 많이 보고 서류통과조차 어려운 경우가 많았던것 같다. 어쨌든 많은 기회를 받는것은 좋은 거니까.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;내일 코테를 치고 2차 테스트는 약 일주일 후 본사에서 본다는데 일주일 간격으로 계속해서 시험이나 면접을 볼 것 같다. 만약 코테 및 테스트를 합격한다면 면접은 일주일 후에 바로 본다는 생각으로 지금부터 병행해야겠다. 다음 글에서 프리테스트와 면접에 모두 합격했다는 글을 꼭 올릴 수 있기를 바란다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발면접준비</category>
      <author>개발지식 블로그</author>
      <guid isPermaLink="true">https://learn-forever.tistory.com/22</guid>
      <comments>https://learn-forever.tistory.com/22#entry22comment</comments>
      <pubDate>Sat, 23 Aug 2025 18:00:11 +0900</pubDate>
    </item>
  </channel>
</rss>