Procedural Dungeon Generation Algorithm(절차적 던전 생성)
이리저리 포럼을 찾다가 절차적 던전 생성 알고리즘이라는 소스코드와 자료를 보게 되어서 포스팅하게 되었다.
간단하게 절차적 던전 생성은 임의의 크기인 생성될 오브젝트를 생성하고 난 이후에 겹치지 않도록 공간을 비집고 해당 공간을 연결해주는 방식으로 재조립하는 알고리즘이었다.
반응형
테스트해본 소스코드로 영상은 다음과 같다.
< 생성 테스트 >
던전을 생성하는 여러가지 방법이 있을 텐데 이런 방식이 있다는 것에 대해서 알게 되어서 재미있다고 생각했다.
Unity 코드로는 룰에 의거한 임의의 DungeonRoom을 생성하고
그 이후에 FixedUpdate를 통해서 겹치지 않는 방으로 해당 방을 이동시키는 방식을 사용한다.
이후에 해당 방들을 연결한다.
반응형
< DungeonGenerator >
public IEnumerator GenerateFloor(FloorRules floorRules)
{
//Create room placer for this floor and generate rooms with correctly shaped colliders
InitialRoomPlacerAgent roomPlacer = new InitialRoomPlacerAgent(ref _random, floorRules);
_dungeon.Layout.AddRooms(roomPlacer.GenerateRooms());
//Rooms have rigidbodies and are being simulated
Debug.Log("Simulating rooms...");
//Wait for simulation to end
yield return new WaitForFixedUpdate();
yield return WaitForBodySimulationEnd();
//Convert to trigger, end simulation of bodies
_dungeon.Layout.ApplyToEachRoom((DungeonRoom r) => r.Collider.isTrigger = true);
//Then snap all rooms to the grid (overlap should not happen)
_dungeon.Layout.ApplyToEachRoom((DungeonRoom r) => GridUtility.SnapToCell(_dungeon.WorldGrid, r));
yield return new WaitForFixedUpdate();
yield return WaitForBodySimulationEnd();
//NOTE: Possibly check if rooms overlap?
Debug.Log("Physical simulation of dungeon rooms complete...");
//Search and set neighbours of the rooms
NeighbourSearchAgent neighbourSearcher = new NeighbourSearchAgent(_dungeon.Layout);
neighbourSearcher.SetNeighboursAllRooms();
TilePlacer tilePlacer = new TilePlacer(_dungeon.GroundTilemap, _dungeon.ObstacleTilemap);
_dungeon.Layout.ApplyToEachRoom(r => tilePlacer.TileStructure(r));
//Generate graph of connected rooms
GraphGenAgent graphGen = new GraphGenAgent(_dungeon.Layout, floorRules);
graphGen.Execute();
}
< DungoenRoom >
[ExecuteInEditMode]
public class DungeonRoom : MonoBehaviour
{
[SerializeField] int _id;
static int currentID = -1;
//For simulation
[SerializeField] Collider2D _collider;
[SerializeField] Rigidbody2D _rb;
Vector3 _lastFixedFramePosition;
[SerializeField] Vector3 _velocity;
[Header("Neighbourhood")]
[SerializeField] List<DungeonRoom> _neighbours;
[Header("Rules")]
[SerializeField] public RoomRules _rules;
public int ID { set => _id = value; get => _id; }
public Collider2D Collider { get => _collider; }
public Rigidbody2D Rb { get => _rb; }
public float Speed { get => Vector3.Magnitude(_velocity); }
public List<DungeonRoom> Neighbours { get => _neighbours; }
public void Awake()
{
_collider = GetComponent<Collider2D>();
_rb = GetComponent<Rigidbody2D>();
_lastFixedFramePosition = transform.position;
}
private void FixedUpdate()
{
SetVelocity();
}
/// <summary>
/// Sets velocity based on former position
/// </summary>
public void SetVelocity()
{
_velocity = transform.position - _lastFixedFramePosition;
_lastFixedFramePosition = transform.position;
}
public void SetNeighbourhood(List<DungeonRoom> neighbours)
{
_neighbours = neighbours;
}
public void SetName()
{
gameObject.name = "Room " + _id.ToString();
}
public static int GetNextID()
{
//I know I can just do ++currentID, but readable code is better!
currentID++;
return currentID;
}
public static void ResetNextID()
{
currentID = -1;
}
private void OnDrawGizmos()
{
Gizmos.DrawCube(transform.position, new Vector3(1, 1, 0));
Gizmos.DrawWireCube(_collider.bounds.center, _collider.bounds.size);
foreach (DungeonRoom room in _neighbours)
{
Gizmos.DrawLine(transform.position, room.transform.position);
}
}
}
Unity Source Code : [링크]
절차적 던전 생성 알고리즘 설명 : [링크]
추가 정보 : [링크]
★★★☆☆
반응형
'개발 > 기본) 알고리즘' 카테고리의 다른 글
알고리즘) 매치 메이킹 (Matching Algorithms) (0) | 2023.09.04 |
---|---|
알고리즘) 게일- 섀플리 알고리즘(Gale-Shapley Algorithm) (1) | 2023.07.31 |
알고리즘) 동적 계획법 (Dynamic Programmi (2) | 2020.08.22 |
알고리즘) 탐욕 알고리즘(Greedy Algorithm) (0) | 2020.06.22 |
알고리즘) 트리(Tree)의 종류 (2) | 2020.06.18 |
댓글