RTS

https://github.com/raylee9919/rts


GitHub YouTube

개요#

인원 기간 사용 기술
1인 2024년 3월 ~ C++17, OpenGL

RTS 장르에 초점을 둔 게임 엔진

문제 해결#

메모리 관리#

C++ 표준 라이브러리 사용 시 다음과 같은 문제 존재:

  • 수천~수만 개의 malloc·free 호출로 인한 높은 오버헤드
  • 스마트 포인터 레퍼런스 카운터 갱신 시 캐시 라인 독점 비용 발생
  • 다수의 실패 가능 지점 및 OS의 개입으로 인한 성능 편차

따라서, 직접 메모리 자료구조 작성.

Windows VirtualAlloc()으로 페이지 단위 메모리를 예약하고, 스택 포인터 이동만으로 주소를 반환하는 Arena 할당자 구현.

memory_1

수명이 한 프레임으로 정해지는 객체들을 한데 묶어, 매 프레임 시작 시 할당자를 통째로 초기화. 할당·해제 호출을 N번 → 1번으로 상수화.

memory_2

할당했던 블록을 재사용할 수 있는 Free List·Pool을 구현해 할당·해제 오버헤드 감소.

memory_3

malloc·free 대비 렌더링 데이터 처리와 개체 관리 모두 개선:

µs/frame malloc·free Arena·Pool
렌더링 106.12 14.88
개체 관리 31.29 23.99

대규모 렌더링#

100 vs 100을 시작으로 전투 규모를 확장하며 프레임 드랍 발생.

mass_1

CPU와 GPU 프로파일러로 원인 분석 후, 그래픽스 디버거로 Shadow Pass의 지오메트리 셰이더 단계의 낮은 병렬성 확인. 단순한 반복 렌더링으로 전환해 15ms → 9ms로 개선.

mass_3

행렬 업데이트용 GPU 메모리를 게임 종료 시까지 CPU에 매핑해 매 프레임 Map/Unmap·Fence 동기화 비용 제거. 4x4 → 3x4 행렬 압축으로 업로드 대역폭도 개선.

mass_2

CPU 애니메이션 업데이트는 단위 간 의존성이 없어 parallel for로 병렬 처리, 동기화 비용도 최소화.

template <typename F>
void ParallelFor(Thread_Group& group, int64_t count, F&& func);

mass_2

1000 vs 1000에서 60 FPS 달성.

전 후
드로우 콜 수 10,000 30
Shadow Pass 15ms 9ms
600 vs 600 30 FPS 100 FPS
1000 vs 1000 --- 60 FPS

경로탐색#

RTS의 필수 요소인 경로 탐색 구현을 위해 삼각분할 알고리즘 관련 코드 필요. 오픈 소스 라이브러리 사용을 고민하여 다음과 같은 문제 발생:

  • 장애물 파괴를 위한 삭제 연산 미지원
  • 지진 시뮬레이션 등이 주 목적인 무거운 코드

이에 따라 기하 라이브러리를 직접 작성.

다음과 같은 과정으로 알고리즘 구현.

  1. 들루네 삼각분할(CDT)로 NavMesh 생성.
  2. A*을 통해 경로 산출.
  3. Simple Stupid Funnel 알고리즘으로 경로 단순화.

navmesh_2

타 유명 라이브러리들 대비 빠른 빌드 시간과 수행 시간, 삭제 연산 확보.

자체개발 CGAL Triangle
빌드 시간 (ms) 748 17,805 3,894
삭제 연산 O O X
수행 시간 (ms) 1.94 1.82 3.84

코드를 GitHub에 배포하여 100여 개의 스타 획득.

navmesh_1