EXQT EXQT
cover

Mineclone 소개

데모 비디오

사용 기술

  • MSYS2 - Windows 환경에서 Linux와 유사한 환경을 제공하는 개발 플랫폼입니다.
  • SDL (Simple DirectMedia Layer) - 크로스 플랫폼 멀티미디어 라이브러리로 여러 서브시스템으로 나뉘는데 그래픽 출력, 키보드/마우스 입력 받기, 소리 출력 등 게임 개발에 필요한 핵심 기능들을 제공합니다.
  • OpenGL - Khronos Group에 개발한 그래픽 API 입니다
  • RenderDoc - 실행되는 프로그램의 OpenGL과 같은 그래픽 API의 호출을 Hooking하여 특정 프레임을 캡쳐하면 해당 프레임에 어떠한 함수들이 호출 되었는지 그리고 OpenGL의 내부 상태를 확인할 수 있는 툴입니다.
  • CMake - C/C++ 프로젝트 빌드를 도와주는 툴입니다. CMakeLists.txt 에 빌드에 필요한 정보를 작성하면 makefile이 생성되고 이를 make로 컴파일 할 수 있습니다.
  • Ninja - make에 비해 속도가 빠르고 CMake에서 makefile 대신 ninja로 출력할 수 있습니다.
  • FastNoise - 마인크래프트의 가장 큰 특징이라면 무한히 생성되는 지형일 것입니다. 사람이 직접 맵을 만드는 것이 아닌 알고리즘에 의해 생성되는 것을 절차적 생성 (Procedural generation) 이라고 합니다. FastNoise에서 제공하는 노이즈들을 잘 조합하여 지형을 만들 수 있습니다. 추가로 라이브러리에 포함된 NoiseTool 을 사용하여 Node 형식으로 노이즈를 조합하여 2D 이미지나 3D Texture로 렌더링 해볼 수 있습니다.
  • enet - UDP 기반의 멀티플레이 게임을 위해 만들어진 라이브러리 입니다. optional reliable, in-order delivery of packets, and fragmentation 를 제공합니다.

주요 기능

절차적 생성 (Generative Terrain) 월드

현실적인 지형은 어떠한 규칙들 있는게 아니라 예측하기 어려운 랜덤한 형태를 띕니다. 하지만 완전한 랜덤은 아니고 특정한 규칙을 따르는 랜덤입니다. 특정 규칙에 따라 랜덤하게 생성 되는 것을 절차적 생성 (Procedural generation) 이라고 합니다.

Noise는 랜덤한 값을 생성하는 함수입니다. Noise 로는 Perlin Noise, Simplex Noise, Value Noise 등이 있습니다. 이 프로젝트에서는 Perlin Noise를 사용했습니다.

단순 Noise 로만은 현실적인 지형을 만들기에는 부족한데 이런 노이즈들을 다른 스케일로 겹겹이 잘 쌓으면 꽤나 흥미로운 패턴이 생깁니다. 이를 Fractal Noise 또는 FBM (Fractional Brownian Motion) 이라고 합니다.

이제 2D Fractal Noise를 구하고 이를 높이로 해서 지형을 생성합니다. 서버 측에서 유저의 좌표 주변의 지형을 생성하고 클라이언트 측에서는 서버로부터 받아 렌더링 합니다.

Voxel Ambient Occlusion

[좌: AO 미적용, 우: AO 적용]
[좌: AO 미적용, 우: AO 적용]

빛은 모서리 부분에서 반사가 많아서 흡수율이 높아 상대적으로 모서리 부분이 다른 부분 보다 어둡습니다. 이를 Ambient Occlusion (AO) 이라고 합니다. 현실적인 AO를 구현하기에는 비용이 많이 드는데 Minecraft처럼 Voxel 형식에서는 현실적이지는 않지만 꽤나 괜찮은 비주얼을 보여주는 Voxel Ambient Occlusion을 사용합니다.

참고한 글

각 블록의 Vertex 대해 얼마나 어두운지를 주변 블록을 여부에 따라 0-3 단계로 표현하고 Fragment Shader에서 해당 값을 사용하여 렌더링 합니다.

[좌: Trilinear Interpolation, 우: Bilinear Interpolation]
[좌: Trilinear Interpolation, 우: Bilinear Interpolation]

다만 Quad를 삼각형 2개로 구현하면 Barycentric Interpolation 때문에 대각선을 가로지르는 선이 보이는 현상이 생깁니다. 참고한 글에서는 특정 조건에 따라 Quad의 삼각형 방향을 뒤집는 형식으로 구현했는데 이 프로젝트에선 Bilinear Interpolation을 사용하여 삼각형 방향을 뒤집지 않고 구현했습니다.

AABB (Axis-Aligned Bounding Box) Collision Detection & Response

복잡한 물리 엔진 없이 모든 충돌체 (Collider) 를 축에 평행한 박스 형태 (AABB) 로 표현하면 충돌 감지(Collision Response)와 충돌 반응(Collision Response)을 간단하게 구현할 수 있습니다. bump.lua 라이브러리를 많이 참고했습니다.

플레이어가 벽에 충돌할 경우 벽에서 멈추면 안되고 미끌어지듯이 움직이도록 구현해야 합니다. 그렇지 않으면 벽으로 계속 돌진할 시 벽에 박혀있게 됩니다. 이는 간단하게 충돌한 축으로 움직이는 값을 0 으로 만들고 다시 나머지 축 방향으로 움직여서 구현할 수 있습니다.

제일 복잡한 부분은 한 충돌체가 이동하면서 다른 충돌체에 충돌하는지 판단하는 건데 이는 두 충돌체에 Minkowski difference 를 구하면 하나의 점이 움직이면서 다른 충돌체에 충돌하는지 판단하는 문제로 바뀝니다. 이는 GJK 알고리즘의 핵심 아이디어 입니다.

Client-Server 구조 멀티 플레이

enet에서 패킷을 안전하게 보낼 수 있음이 보장되기에 네트워크 적인 부분은 크게 신경 쓸 필요가 없었습니다.

플레이어나 지형 덩어리 (Chunk) 를 하나의 네트워크 오브젝트로 보고 해당 오브젝트가 생성되거나 업데이트 되면 서버에서 클라이언트로 해당 오브젝트 바이너리 형태로 Serialize 한 뒤 보내주는 방식으로 구현했습니다.

멀티 플레이어 게임 프로그래밍 책을 참고 하였습니다.