7/13 - 랜덤 층 생성 알고리즘
오늘은 층 생성 알고리즘을 짰다. 이 과정에서 기획면에서 미스터리 방의 이벤트&골드/에메랄드/링 입수처&유물 입수처를 약간 수정했다.
1) 층 생성 알고리즘은 이전에 말한대로 아이작의 번제 방식에서 맵을 생성하는 방식을 적용했다. 우선 아이작의 번제에서 맵을 만드는 방법은 아래 글에서 자세히 설명하고 있다.
Dungeon Generation in Binding of Isaac
The Binding of Isaac, and its remake, Binding Of Isaac: Rebirth are one of my favourite games of all time. It’s a roguelite twin stick shooter, much like Enter the Gungeon. The dungeons it ge…
www.boristhebrave.com
내가 생성한 방식은 완전히 동일하지는 않지만 BFS 방식으로 큐에 시작점을 넣고 점차 바깥으로 확장하며 맵을 생성한다는 점에서 큰 틀은 위 방식을 따른다. 아무래도 나는 C++이 제일 익숙한 언어여서 일단 위 움짤은 C++로 구현한 상태이다.
(++아래 내용은 7/14일에 C#으로 구현한 후 수정되었다. 추가로, 위 움짤은 아래 규칙 중 b)번과 c)의 개수정보를 지키지 않는다.)
방 생성 전에 현재 개발중인 게임에서 짚고넘어가야 할 점은 다음과 같다.
a) 방은 11*11 크기의 격자에 생성된다. 단, 테두리(인덱스에 0 or 10이 포함되는 경우)는 방으로 선택될 수 없다. 각 격자는 -1~10 중 하나의 int 값을 가지며 이는 격자의 속성을 의미한다.
- -1: 방이 아님
- 0: 빈 방
- 1: 전투방
- 2~7: 미스터리방
- 8: 상점방
- 9: 보스방
- 10: 격자의 테두리임
b) 미스터리 방들 중 속성이 2, 3인 방은 각각 1개 이상, 4인 방은 단 1번만 생성되어야 한다. 5~7인 방은 몇 개가 생성되든 상관 없다(생성이 안되어도 됨).
c) n층이라고 할 때 방들의 개수/위치 관련 정보는 다음과 같다.
- 총 방의 개수는 8 + n*3 + random(0~2)개이다.
- 시작방의 좌표는 x, y 둘 다 4~6의 랜덤한 수 이다.
- 특수한 방(속성이 2~9인 방)들은 상하좌우에 인접한 방의 개수가 1개이다.
- 미스터리 방의 개수는 3 + 개 이다.
- 상점방은 n이 짝수이면 1개, 홀수이면 0개이다. 상점방은 특수한 방들 중 가장 시작방과 가까운 곳에 생성된다.
- 보스방의 개수는 1개이다. 보스방은 특수한 방들 중 가장 시작방과 먼 곳에 생성된다.
이를 고려하였을때 알고리즘은 다음과 같다.
1. 방 격자를 모두 -1로 채운다. 테두리는 10으로 채운다.
2. 시작점을 (4~6, 4~6) 중 하나로 랜덤하게 고른다.
3. 방 격자에서 시작점을 0으로 채운다.
4. 큐에 시작점을 넣는다.
5. 큐에 원소가 있는 동안 아래를 반복한다.
a. 큐의 맨 앞을 연결고리 방으로 정한다.
b. 연결고리 방의 상하좌우 방에 대하여 아래를 반복한다.
i. 이미 필요한 방 개수만큼 다 생성했으면 포기한다. (이 조건을 반복문 밖에서 체크하면 층 생성 완료 후 특별방 여부를 bfs로 다시 확인해야 하기 때문에 반복문 안에서 체크하는 것임)
ii. 이 방이 이미 채워졌으면 포기한다. (== -1이 아닌 값으로 채워졌음)
iii. 이 방의 인접 방 개수가 1개 초과이면 포기한다. (==상하좌우가 -1이 아닌 값으로 채워진 방 개수가 1 초과임)
iv. 50%확률로 포기한다.
v. 선택한다. 즉, 방 격자에서 이 방을 1로 채우고 큐에 넣는다.
c. b에서 한번도 방을 생성하지 못했다면 이 방을 특수방 리스트에 넣는다.
6. 만일 큐가 모두 비었음에도 충분한 방 개수를 채우지 못했거나, 생성된 특수방 개수가 목표 개수와 다르다면 1번으로 돌아간다.
7. 특수방 리스트의 맨 마지막에 해당하는 격자를 9로 채운다. (특수방들 중 BFS로 가장 마지막으로 확인한 방이므로 시작점과 제일 먼 곳임)
8. 상점을 만들어야 하면 특수방 리스트의 맨 앞에 해당하는 격자를 8으로 채운다. (위와 마찬가지 원리로 시작점과 제일 가까운 곳임)
9. 특수방 리스트에서 랜덤하게 3개 원소를 뽑아 해당하는 격자를 각각 2, 3, 4로 채운다.
10. 남은 특수방들에 해당하는 격자를 2, 3, 5, 6, 7 중 하나로 채운다.
코드 전문을 보고 싶으면 내 깃헙에서 Asset/Scripts/Floor.cs를 보면 된다.
2) 간단하게 포탈과 미니맵에 쓰일 스프라이트를 만들었다. 임시로 만든거라 못생겼지만 쨌든.
이제 내일 할 일은 오늘 구현한 내용을 C#으로 바꿔서 실제로 게임에서 층을 생성하고, 방끼리 이동하며, 하단에 미니맵까지 보여주는 것이다.
- 층 생성 구현
- 방 이동 구현(전투방은 입장시 바로 전투를 시작하도록)
- 미니맵 구현