평생 배우는 개발자

1차 프로젝트 회고 본문

원티드 포텐업 게임개발 4기

1차 프로젝트 회고

개발지식 블로그 2026. 2. 13. 19:04

📌 프로젝트 명

        콘솔 뱀서라이크

1. 프로젝트 개요

  • 게임 소개:
    콘솔 환경에서 뱀서류(서바이버) 핵심 루프를 구현한 프로토타입입니다. 자체 엔진 구조를 기반으로 Player/Enemy/Bullet, EXP·레벨업·스탯, 카메라 스크롤 월드, 대량 객체 처리(Object Pooling), 충돌 최적화(AABB → Quadtree), 디버그 모드를 통합하여 구현-통합-디버깅-최적화의 전 과정을 경험하는 것을 목표로 했습니다.
  • 개발 기간:
     총 7일(2026-02-04 ~ 2026-02-10 + 발표 준비 2026-02-11 )
  • 참여 인원:
    개인 프로젝트
  • 현황(결과):

기술 스택

항목 Skill Set
Core Tech Custom Game Loop(GameLevel Tick), Actor Update Pipeline
Gameplay Systems Stat/Interface(IStatHolder), LevelUp + Pause, Hit Invincibility
AI / Behavior Vector-based Chasing(normalize 사용), (A* algorithm 검토 후 미적용)
Collision AABB → Quadtree 전환, Query 파이프라인
Optimization Object Pooling, swap-pop(vector에서 erase할 때), Debug Mode tools(FPS, Actor position, Quadtree 정보)
Trouble Shoot dllexport와 dllimport 자동화 매크로 사용시 판단 미스 버그 해결, 오브젝트 풀링 BeginPlay()에서 prewarm() 시 프로세스 메모리 무한 증가 해결
Environment Windows Console, Visual Studio, Git, Obsidian

 

 

주요 기능

기능 설명
Player 이동 및 조작 키보드 이동, 좌표 출력(디버그 모드 포함)
Enemy 스폰 및 추격 랜덤 방향 스폰, Player 추격(방향 벡터 계산, 정규화로 속도 일정)
자동 공격 시스템 가장 가까운 적 탐색 후 일정 시간 마다 자동 발사
Bullet(투사체) 방향 벡터 기반 이동, 속도/형변환 이슈 해결
스탯 시스템 Stat struct + IStatHolder 인터페이스 적용
HP/피격/무적 데미지/게임오버/피격 플래시/무적 시간 알아 볼 수 있는 UI 인터페이스 제작
EXP/레벨업 EXP 드랍, FullExp 20% 증가, 레벨 표시 UI 인터페이스 제작
레벨업 UI + Pause 게임 일시정지 후 중앙 UI에서 선택(방향키)
충돌 처리 AABB 구현 후 Quadtree 공간 분할로 확장
오브젝트 풀링 Exp Gem/Enemy/Bullet 메모리 공간 미리 할당
카메라/월드 확장 스크롤링 카메라( worldPos - cameraPos에 Draw), 마진 설정, 잔디 타일링
디버그 모드 화면에 Quadtree 디버그 라인 표시

 

2. 기획 목표 및 협업 방식

🔸기획의도 및 목표

  • 게임 분석:
    뱀서류 장르는 시간이 지날수록 적/탄/아이템 오브젝트가 폭증하기 때문에, “대량 객체 처리”와 “충돌 최적화”가 구조적으로 중요합니다. 콘솔 환경에서도 동일한 부담이 발생하므로, 풀링과 공간 분할을 중심으로 성능과 안정성을 설계 과제로 삼았습니다.
  • 구현 목표:
    • Player/Enemy/Bullet 등 핵심 class 구조 완성
    • HP/EXP/레벨업/스탯 적용 및 UI 통합
    • 대량 객체 대응(Object Pooling)
    • 충돌 최적화(AABB → Quadtree 전환)
    • 카메라 스크롤 월드 구현
  • 성장 목표:
    • 엔진 루프(GameLevel Tick) 구조 이해와 제어(dt/pause)
    • 자료구조 기반 최적화(Quadtree, swap-pop)
    • 메모리/라이프사이클 문제(누수, 반복 호출, 이미 제거된 객체 접근) 디버깅 역량 강화
    • 문서화 습관(일지, 이슈 분류, 재발 방지 기록) - Obsidian 사용

🔸협업 방식

  • 문서화:
    • 솔로 프로젝트였기 때문에 기록에 집중
    • Obsidian 기반 개발일지/체크리스트/이슈 로그로 문서화
  • Git 전략:
    • 개발 과정에서 예기치 못한 버그에 대비해 빠른 롤백이 가능하도록 자주 커밋
    • 솔로 프로젝트였기 때문에 branch는 만들지 않았고, 원활한 작은 기능(Git 사용 여부 및 브랜치 전략)
  • 이슈 트래킹 방식:

Obsidian 체크리스트 + 날짜별 로그 + 이슈 분류(억까 버그/내 실력 버그/배우기 좋은 버그)로 관리
다음 계획: 만약 팀 프로젝트를 진행한다면 Trello로 전환 예정

 

 

3. 아키텍처 및 워크플로우

🔸아키텍처 특징 및 설계 의도

  • 구조적 특징:
    • GameLevel 중심 게임 루프에서 Actor 리스트를 순회하며 Tick/Render 수행
    • 레벨업 UI 노출 시 dt 제어로 게임 진행을 일시정지하는 방식 적용
    • IStatHolder 인터페이스 + Stat struct로 Player/Enemy 스탯 접근을 공통화
  • 게임 흐름:
    • Enemy는 Player 포인터(또는 Actor 참조)를 전달받아 target 기반 추격
    • Enemy 사망 시 EXP 드롭 → Player가 수집 → FullExp 도달 시 레벨업
    • 레벨업 UI에서 선택된 업그레이드가 Player Stat에 반영
  • 확장성/안정성 관점 포인트:
    • Object Pooling으로 런타임 생성/삭제 비용과 단편화 위험을 줄이려는 의도
    • 충돌은 AABB(베이스) 유지 + Quadtree(확장)로 단계적 최적화
    • 디버그 모드(좌표/쿼드트리 테스트 기능)로 통합 과정 검증 가능하도록 구성

🔸사용자 워크플로우

  • 사용자 흐름:
    1. 게임 시작
    2. Player 이동
    3. Enemy 사방 스폰 및 추격
    4. Player 자동 공격으로 전투
    5. Enemy 처치 → EXP 드랍 → Player 수집
    6. 레벨업 발생 → 게임 일시정지 + 중앙 UI 표시
    7. 업그레이드 선택 → 스탯 적용 → 게임 재개
    8. 피격 시 HP 감소 + 무적 시간/피격 이펙트
    9. HP 0이면 게임오버/메뉴 전환
  • 기능 간 데이터 흐름(Flow chart):
    예시: Input → Player Move → Enemy MoveTo(Player) → Collision(AABB/Quadtree) → Damage/Drop → EXP Accumulate → LevelUp UI → Stat Apply

 

4. 주요 작업

 

🔸오브젝트 풀링(Object Pooling) 적용

  • 기능 소개:
    Enemy/Gem/Bullet 등 반복 생성되는 객체를 미리 풀링 하여 재사용하도록 구현했습니다.
  • 작업 과정:
    • 풀링 대상으로 Gem/Enemy/Bullet 선정
    • prewarm 방식으로 초기 풀 확보
    • 활성/비활성(IsActive) 기준으로 재사용 흐름 구성
  • 수정/고도화 사항:
    • 적용 후 프로세스 메모리 무한 증가 이슈 발생 → 호출 구조 분석 후 수정

 

🔸충돌 처리 최적화: AABB → Quadtree

  • 기능 소개:
    기본 AABB 충돌을 구현한 뒤, 대량 객체 상황에서 후보군을 줄이기 위해 Quadtree 공간 분할을 도입했습니다.
  • 작업 과정:
    • AABB 충돌 구현(기본 충돌 처리)
    • Quadtree 자료구조 구현(Rect 포함)
    • AABB/Quadtree 모두 디버그 가능하도록 함수화 유지
  • 수정/고도화 사항:
    • 죽은 객체까지 충돌 체크에 포함되던 문제 해결(Actor->IsActive 필터)
    • Query 역할 이해 부족으로 Player-Enemy 충돌 누락 → 사용 방식 정리 후 수정
    • 컨테이너 const 문제 해결(const Actor* vs Actor*) - const 객체를 const가 아닌 컨테이너에 넣을 수 없음!

 

 

5. 문제 해결 및 기술적 도전

🔸이슈 1: 오브젝트 풀링 이후 프로세스 메모리 무한 증가

  • 문제 상황:
    오브젝트 풀링 적용 이후 프로세스 메모리가 지속적으로 증가(무한 증가)하는 현상이 발생했습니다.
  • 원인 분석:
    beginPlay()가 루프 내부에 있고 hasbeganplay로 거르는 구조였는데, GameLevel 단계의 beginPlay()에 불리는 prewarm은 Actor 산하의 hasbeganplay로 차단되지 않아 tick마다 beginPlay/prewarm이 반복 호출되며 리소스가 계속 누적되는 구조였습니다.
  • 해결 방법:
    • 선택지 1: hasbeganplay 플래그가 prewarm까지 포함하도록 구조 변경
    • 선택지 2: beginPlay를 루프 외부로 이동하거나, prewarm을 명시적 1회 호출로 분리
      최종 해결책: GameLevel의 hasbeganplay를 생성하고 따로 관리
  • 해결 과정:
    호출 위치/주기 확인 → tick에서 반복 실행됨을 확인 → 초기화 루틴을 1회성으로 분리/보장하도록 수정
  • 해결 결과:
    메모리 무한 증가 현상 제거

 

🔸이슈 2: Quadtree 전환 후 메모리 에러 및 충돌 누락

  • 도전 과제:
    AABB에서 Quadtree로 전환하며 Enemy 사망 시 메모리 에러(delete array, 접근 오류)와 Player-Enemy 충돌 누락이 발생했습니다.
  • 원인 분석:
    • 죽은 Enemy까지 충돌 체크/Query에 포함되어 이미 제거/비활성 객체 접근 가능성이 생김
    • Query 역할 이해 부족으로 충돌 판정 흐름이 깨짐
    • 디버그 시각화는 라인이 따라오는데 실제 정보가 첫 화면 기준으로 고정(카메라 좌표계 불일치)
  • 해결 방법:
    • Actor->IsActive 필터로 살아있는 객체만 Quadtree 처리
    • Query 반환/사용 방식 재정리 후 충돌 흐름 수정
  • 해결 결과:
    메모리 오류 제거 및 Player-Enemy 충돌 정상화

 

🔸기술적 의사결정 기록

  • 적용 기술:
    • Enemy 추격: A* 시도 후 방향벡터 기반 추격 방식으로 수정
    • 충돌: AABB → Quadtree 확장
    • 대량 객체: Object Pooling
    • 벡터 메모리 삭제 최적화: swap-pop(O(1) 삭제)
  • 선택 이유:
    • A*: 지형/장애물이 없는 상태에서는 효용이 낮고 추격이 어색하게 동작
    • 방향벡터: 구현 단순 + 안정적 + 정규화로 속도 일관성 확보
    • raw pointer: 구현 단순, 메모리 관리 공부(단, 소유권/삭제 책임을 명확히 해야 함)
    • swap-pop: 순서 보장 불필요한 컨테이너에서 성능 이점
  • 개선 아이디어:
    •  A* 의미 확보를 위한 타일 맵/장애물/절차적 맵 생성 추가
    •  Enemy끼리 충돌 시 버벅거림 → 충돌 Layer 생성 후 충돌 검사 적용

 raw pointer 구간 소유권 규칙 문서화 및 해제 책임 일원화

 

6. 결과 및 회고

🔸결과

  • 목표 달성도:
    • Player/Enemy/Bullet + HP/EXP/레벨업 + Pause UI 통합 완료
    • Object Pooling 및 Quadtree 통합 완료
    • 카메라 스크롤 월드(잔디 타일링 포함) 완료
    • 디버그 모드(좌표/Quadtree 라인 등) 일부 완료
  • 성과 지표:
    • Stress Test에서 FPS 저하 체감 없음
    • vector 삭제(erase) O(N) → swap-pop으로 O(1) 최적화 적용
    • 메모리 무한 증가 버그 해결
    • Quadtree 통합 후 충돌 정상화
  • 임팩트 액션:
    • 대량 객체 처리 + 충돌 최적화 + UI/pause + 스탯 시스템을 하나의 루프에 통합
    • 통합 과정에서 발생한 메모리/흐름/좌표계 문제를 분석-수정하며 프로젝트 수행 역량을 확보

🔸회고

  • 기술 측면:
    • 엔진 루프 관점에서 문제를 추적(super Tick, return flow 등)
    • 정규화/형변환/const/링킹 등 기본기에서 터지는 버그를 케이스로 축적
    • Quadtree 디버그와 카메라 좌표계까지 맞추며 통합 난이도를 경험
  • 기록 측면:
    • 문서화를 좀 더 형식에 맞춰서 일정하게 매일 남기기
  • 다시 한다면 어떻게 설계할까?:
    • FPS/메모리 측정 루틴을 프로젝트 초기에 내장
    • Quadtree 소유권/해제 책임을 문서로 먼저 확정
    • beginPlay/prewarm 같은 초기화 루틴을 1회 보장하는 구조로 고정

 

시각자료

  • 주요 기능 화면:
    • 상단 파란색 바 - 현재 EXP
    • 상단 빨간색 바 - 현재 HP
    • 좌측 하단 플레이어 Stat
    • 카메라 스크롤 월드(잔디 타일 포함)

플레잉 화면

  • 프로파일링:
    • FPS 출력 화면
    • Quadtree 적용 전/후 Stress Test 조건 화면
      • 오히려 AABB가 더 빠르다(?) - 사실상 텍스트만 출력하는 게임에서는 큰 성능 차이는 없는 듯하다.

QuadTree / AABB

 

  • 오브젝트 풀링 전/후 프로세스 메모리 변화
  • 이미지가 거의 같아 보이지만 구현 방법은 다르다.. 그러나 이 또한 큰 성능 차이는 없는 듯 하다.

Object Pooling 으로 미리 공간할당 / 매 프레임 할당과 삭제 반복

 

 

1차 프로젝트를 되돌아보며

  • 잘했다고 생각한 점:
    • 문서화와 커밋 전략이 개발 방식으로 자리 잡은 점 - 프로젝트 규모가 커질수록 강점이 될 것
    • 어려웠던 Quadtree 시각화를 성공해 낸 점 - 어려운 기술도 계속 부딪혀 나감
    • 발표 피드백으로 프로파일링이 안 되는 것을 고친 점 - 피드백 수용 능력 증가
  • 부족
    • 게임규모에 맞게 공통 스탯을 관리하는 클래스로 인터페이스 클래스를 쓴 점 - 현재 게임 규모에서는 좋았던 선택이었을 수 있으나 게임규모가 커진다는 가정 하에 component 설계를 하였으면 확장성이 좋았을 듯
    • 시간 부족의 핑계로 게임성을 높이지 않은 점 - 기술 구현을 빠르게 끝내고 게임성 높이는 데에도 시간을 배치하면 좋을

소감

원티드 포텐업 게임개발 1차 프로젝트를 클리어했다! 주말이 포함된 일정이었지만 안 그래도 짧은 기간 중, 딱 주말에 열이 나고 어지러워서 정말 아무것도 못했다는 점에 아쉬움이 남는다. 물론 처음 계획 했던 QuadTree 시각화는 완성했지만, 비주얼로 보았을 때는 거의 기본 버전 그대로라서 게임성이 떨어진다는 것에 아쉬움이 남는다. 이를 양분 삼아서, 다음 2차 프로젝트에는 어느 정도 게임성을 갖추면서도 내가 원하는 기능을 보여줄 수 있게 기획하고 디버그 기능도 확실하게 만들고 싶다. 1차 프로젝트를 진행하면서 게임 엔진의 큰 그림을 이해하고 활용할 수 있는 기회였어서 좋았고 구현해보고 싶었던 기능과 만들고 싶었던 게임을 제작하면서 정말 재미있었다. 

특히, 프로젝트 발표 다음날 만들었던 게임을 서로서로 해보는 시간을 가졌는데, 발표로만 보던 게임을 직접 해보니 정말 재미있었고, 다음 프로젝트에는 더 재미있는 게임을 만들고 싶은 마음이 생겨났다.