랜덤맵 제너레이터

양규빈·2024년 7월 21일

팀프로젝트

목록 보기
2/7

로그라이트

진행중인 팀프로젝트는 로그라이트로 결정 되었었습니다.
로그라이트란?
로그라이크 게임의 특징을 차용하면서도, 차별적인 게임성을 가진 게임들을 일컫습니다.

보통의 로그라이크 게임이 사망 시에 지니고 있더 모든 재화와 스탯 등이 사라지는 반면에,
로그라이트는 패널티를 완화시키는 등의 차별점이 있습니다.

결론적으로 로그라이크, 로그라이트 모두 랜덤맵 생성이 게임을 구현하는 데 있어서, 굉장히 중요한 핵심 시스템이라고 할 수 습니다.

설계

랜덤맵을 구현하는 방식은 여러 가지가 있겠으나, 통상적으로는 BSP 알고리즘.
즉, 이진공간분할법을 이용하는 경우가 많습니다.

하지만, 저희 팀은 랜덤하게 방을 배치하고, 문을 통해서 각 방을 이동하는 방식으로 게임을 기획했습니다.

로그라이크 게임으로 유명한 아이작과 비슷한 구조인 것입니다.

이러한 구조의 문제는 BSP 알고리즘으로 구현하기에 적절하지 않다는 것에 있습니다.

이진 공간 분할법은 공간을 계속해서 슬라이스 하면서, 랜덤맵을 만드는 알고리즘인데,
이러한 경우, 고정된 몇 가지의 사이즈로 방을 만들고 연결하는 데에 어려움이 있었습니다.

따라서
제가 설계한 랜덤맵 제너레이터의 구조는 이러했습니다.

  1. 방을 생성할 랜덤한 범위를 설정한다
  2. 범위에 해당하는 방을 담을 이중배열을 만든다.
  3. 이중배열의 중앙 값에 시작 방을 만들고, 시작방을 기준으로 상하좌우에 방이 존재하는지 체크한 후에, 없다면 Room을 타일맵으로 생성하고, 이중배열에 저장한다.
  4. 이중배열을 순회하면서 방과 방이 연결되어 있는 경우. 즉, 서로 인접한 경우에는 Door를 유지하고, Door와 Room을 딕셔너리로 연결. 반대로 방이 없는 경우에는 막다른 길로 가정하고, 문을 파괴한다.
  5. 만들어진 이중배열을 매개변수로 넘기며 미니맵 매니저를 통해서, 랜덤하게 만들어진 맵을 미니맵으로 출력한다.

즉, 랜덤맵 제너레이터를 구현하는데 필요한 클래스는

  • 랜덤하게 Room을 생성할 제너레이터 클래스.
  • 생성된 Room의 크기만큼 타일맵을 그릴 타일맵 렌더러 클래스.
  • 방에 대한 데이터를 저장하는 Room 클래스
  • Room에 부착되는 문에 관한 Door 클래스.

가 있었습니다.

구현

랜덤맵 제너레이터 클래스

랜덤맵을 실질적으로 생성하는 클래스입니다.
설계한 바와 같이, 사이즈를 결정하고
사이즈의 2배만큼 이중배열을 초기화한 후에,
중앙에 시작방을 설정 및 타일맵으로 방을 생성.

그리고, 반복문을 통해서, 마지막 방을 기점으로 랜덤한 position을 get하여서 새로운 방을 생성합니다.

이때, 1~4 범위 만큼 추가 반복하는 이유는 고정값으로 1회만 반복하는 경우에는, 깊이만 깊어지고 뻗어나가는 가지수가 적어지며 랜덤맵으로서의 재미와 완성도가 떨어지기 때문입니다.

랜덤한 direction에 방이 존재하는지. 즉, 유효한 좌표인지 체크하여 유효한 값이라면 해당 좌표를, 그렇지 않다면 매개변수로 받은 마지막 방의 좌표를 반환하는 함수입니다.

새로 생성할 방이, 기존의 방과 겹치는지 체크하는 함수입니다.

각 모서리의, 포인트가 일치하는지, 체크하고

모서리에서 뻗어나오는 변이 겹치는지도 체크합니다.
선분의 교차는 벡터의 외적을 사용했습니다.

방을 생성하는 함수입니다.

타일맵 렌더링을 담당하는 클래스인, mapCreator의 맴버 함수인 CreateRoom 을 호출하여, Room을 만들고, 만들어진 Room을 이중배열에 저장합니다.

이러한 이중 배열은 만들어진 맵을 바둑판 형식으로 저장하는 역할을 하며, 추후 문 연결과 미니맵 생성에 사용됩니다.

연결되지 않은 방, 즉. 인접하지 않은 방을 가리키는 Door를 제거하고, 인접한 방은 각 Room을 딕셔너리를 통해 연결하는 함수입니다.

실제로 Door에 디렉션값에 따라, 방을 매핑하는 함수입니다.

타일맵 생성기

랜덤맵 제너레이터에서 받은 좌표와 방 크기를 이용해서, tileMap을 그리는 함수입니다.

타일맵은 rectangle 타일을 기반으로 합니다.

각 변의 중앙 값에 Door 프리팹을 두고, Room이 보유한 딕셔너리에 방위에 맞게 초기화해줍니다.

결과

정상적으로 방이 생성된 것을 확인할 수 있습니다.
미니맵은 다른 문서에서 작성하도록 하겠습니다.

profile
훌륭한 개발자를 꿈꾸는 중입니다

0개의 댓글