본문 바로가기

프로젝트

[C++] 3D 콘솔 미로게임 배경 및 구상 + 최종 구현

배경

컴퓨터 프로그래밍 시간, C++ 프로젝트를 작성해야 하는 과제를 받았다. 프로젝트의 크기는 상관이 없었고, 프로젝트의 완성도와 노력, 그리고 주석 등을 위주로 평가받는 프로그램을 작성해야 했다. 그래서 사실 내게 간단한 프로그램을 만들어서 꼼꼼히 주석을 달고 제출해도 충분히 성적을 받을 수 있는 과제였다. 그래도 나름 대학교에서 만들 첫 프로젝트인 만큼 어려운 것, 아니면 경험해보지 않았던 분야의 프로젝트를 만들고자 했다. 그래서 건드리게 된 것이 그래픽이었다.

그래픽으로 만들 수 있는 프로젝트는 많다. openGL을 이용해서 그래픽 툴을 이용해도 되고, 아니면 내가 한 것처럼 콘솔을 이용해서 직접 랜더링 해봐도 된다. 나는 직접 랜더링하는 것을 택했다. 이미 openGL로는 그래픽을 구현하는 방법이 거의 정형화되어 있기에 인터넷상의 코드를 따라 치고 싶기는 않았기 때문이다. 이러한 고민 끝에 나는 3D미로 게임을 구현하기로 마음먹었다.

 

결과물

 

아직은 완성본은 아니지만, 대략적으로 이러한 느낌의 프로그램이다. 사용자는 방향키와 "," "."을 이용해서 화면 회전이 가능하고, 미로를 탐험하는 경험을 하게 된다.

 

구상

이론

내가 랜더링에 사용한 방법은 화면의 각 픽셀에서 레이캐스팅을 하여 밝기를 구한 방식이다. 이것은 해상도가 2560x1440, 즉 3686400개의 픽셀을 가지는 화면에는 적합하지 않지만, 지금 내가 진행하는 프로젝트처럼 1) 픽셀수가 적고 2) fps가 중요하지 않은 경우에는 충분히 구현 가능하다. 그러나 이론적 배경은 다소 찾기가 어려워, 3D → 2D 로딩/언로딩 과정을 참고하여서 직접 구현하였다.

그림과 같이 카메라, 카메라 평면(화면), 그리고 미로 상의 한 점이 존재한다고 하자.

* 래이캐스팅은 원래는 이 글에서 설명된 방식으로 진행되지만, 현재 벽의 크기>1이므로 그냥 벡터를 더해나가는 방식이 더 편할 듯하여 아래와 같이 구현했다.

 

여기에는 2개의 좌표계가 공존하고 있다. 하나는 카메라좌표계, 나머지 하나는 미로의 좌표계(world coordinate)이다. 따라서 나는 카메라 좌표계를 먼저 미로 좌표계로 변환한 후 나머지 계산을 진행했다.

 

 

계산 과정은 그림을 참고하면되는데, 1) 카메라 좌표를 맵 좌표로 변환 2) 레이를 생성 3) DDA이용 4) 충돌시 색상과 내적을 통한 빛 세기 도출. 이런 과정을 거쳤다.

카메라상 좌표를 미지수로 두고 worldpos로 천천히 좌표를 변환하고 회전변환만 적용시키면 된다.

 

레이캐스팅을 하기 위해서 나는 아래 그림에서 붉은색으로 표시한 벡터를 구하고자 했다. 벡터를 구한 뒤에는 벡터를 정규화한 후(=길이를 1로 만든 후) 계속 더해나가 벽에 부딧치는 시점을 구하는 과정을 통해 레이캐스팅을 할 것이기 때문이다.

 

실제 구현

클래스 설명

객체지향을 활용하기 위해서 렌더링 뿐만 아니라 게임 엔진까지 구성했다.

결과

https://github.com/ZirAjs/CP-Maze3D

 

GitHub - ZirAjs/CP-Maze3D: 컴퓨터프로그래밍 프로젝트

컴퓨터프로그래밍 프로젝트. Contribute to ZirAjs/CP-Maze3D development by creating an account on GitHub.

github.com