Class GameDev* SheepAdult

[Unity2D] 내 마음대로 만들어 보는 아이작식 랜덤 맵 생성 (3) - 미니맵 본문

Unity

[Unity2D] 내 마음대로 만들어 보는 아이작식 랜덤 맵 생성 (3) - 미니맵

SheepAdult 2024. 3. 28. 19:41

깃허브 : https://github.com/devminjae97/GP1/tree/GP1-2_MapGeneratorTest

개요

미니맵은 아래와 같이 아이작과 비슷한 형태로 구현할 것이다.

아이작 미니맵

플레이어가 방에 들어가면 minimap camera와 main camera가 방의 중앙을 가리키도록 할 것이며 현재 있는 방의 색을 밝게 하여 현재 어디에 있는지 사용자가 알 수 있도록 할 것이다. 또한, 한 번도 방문하지 않은 방은 보여주지 않고 방문했던 방만 보여줄 것이다.

 

미니맵 생성

미니맵을 생성하기 위해 Render Texture를 활용했다. Render Texture를 활용한 카메라 설정은 아래의 링크를 참고하여 구현했다.

 

영상 링크: https://www.youtube.com/watch?v=pd17u2SFdSk

 

Render Texture를 활용한 미니맵 구현 시, layer를 통해 보여줄 오브젝트만 보여주는데, 이를 위해 맵에 표시할 오브젝트에 자식 오브젝트를 생성한 후 layer를 미니맵으로 설정했다.

 

미니맵 카메라의 Culling Mask도 설정해 준다.

 

그렇다면 생성되는 셀 오브젝트의 자식 오브젝트에 적절한 모양의 Sprite를 넣어주고 layer를 minimap으로 설정해 주는 것이 적당해 보인다. 그래서 타일을 깔았던 것과 마찬가지로 같은 id의 셀을 탐색하며 어떤 방향의 sprite를 사용할지 결정해 주었다.

먼저 3가지의 sprite를 준비한다.

내가 만드는 방은 위의 세 가지 sprite를 회전시켜 가며 만들 수 있다. 예를 들어 4 방향 중 2 방향이 막혀 있다면 2 walls sprite를 사용하면 된다. 타일 모양은 아래와 같이 선정한다. 그리고 처음에 방문한 셀은 모두 보이지 않게 해야 하므로 투명하게 한다.

// MapGenerator.cs
foreach (Cell cell in cells)
{ 
	// rx: right x, y
    rx = cell.pos.x + xdir[0];
    ry = cell.pos.y + ydir[0];
    // ... 생략
	
    // rOk: right에 같은 id 셀이 있으면 true, 없으면(벽이면) false
    rOk = 0 <= rx && rx < cellList.GetLength( 1 ) && 0 <= ry && ry < cellList.GetLength( 0 ) && cellList[rx, ry].id == cell.id;
    lOk = 0 <= lx && lx < cellList.GetLength( 1 ) && 0 <= ly && ly < cellList.GetLength( 0 ) && cellList[lx, ly].id == cell.id;
    // ... 생략
    
    // 타일과 방향 결정
    if (!dOk && !uOk && !lOk && !rOk)
    {
        cell.InitMinimapSprite( minimap4Walls, Quaternion.Euler( 0, 0, 0 ) );
    }
    else if (!dOk && !uOk && !lOk)
    {
        cell.InitMinimapSprite( minimap3Walls, Quaternion.Euler( 0, 0, 90 ) );
    }
    // ... 생략
}

// Cell.cs
 public void InitMinimapSprite(Sprite _sprite, Quaternion _rotate)
 {
     minimapSprite.sprite = _sprite;
     minimapSprite.transform.transform.rotation = _rotate;
 }

그럼 아래와 같이 미니맵이 그려진다.

현재 방 색 변경

이제 플레이어가 현재 어느 방에 있는지 id를 구한 후 해당 방의 셀 색을 밝게 변경해 준다. 방 ID를 키, 방의 셀들을 값으로 갖는 public Dictionary<int, List<FTileInfoByCellID>> 자료형을 사용하여 방을 색칠해 줄 것이다. FTileInfoByCellID 구조체는 아래와 같다. 문, 벽의 타일맵에 맞게 변경하기 위한 Tilemap 변수와 GetTile을 위한 Vector3Int 변수를 두었다.

public struct FTileInfoByCellID
{
    public Tilemap tilemap;
    public Vector3Int pos;

    public FTileInfoByCellID(Tilemap _tilemap, Vector3Int _pos)
    {
        tilemap = _tilemap;
        pos = _pos;
    }
};

 

플레이어가 현재 있는 방에 대한 정보를 갖게 하고 싶지 않았고(로비에 있을 경우도 있으니) 그렇다고 방이 플레이어의 정보를 가지고 있는 것은 더욱 맘에 들지 않으니 DungeonManager 이름의 싱글톤 클래스를 만들어 방과 플레이어 사이의 상호관계를 담당하게 했다. 해당 클래스에 위에서 언급한 Dictionary를 두었으며, 방을 생성할 때 위의 자료구조에 (키 : 값 = ID : Cell[] )에 대한 정보를 담아 주었다.

문을 통해 다음 셀로 이동할 때마다 플레이어가 있는 방의 셀 ID를 갱신한다. 방의 중심에 카메라의 시야를 맞추고 미니맵의 색상을 바꾼다.

 // Door.cs
 private void OnTriggerEnter2D( Collider2D other )
 {
     Player player = other.gameObject.GetComponentInParent<Player>();
     if (player)
     {
     	// 플레이어가 존재하는 RoomID의 값을 갱신
         DungeonManager.GetInstance().SetPlayerRoomID( nextDoor.ownerCell.id );
         // 카메라의 위치를 방의 각 셀들 중심으로 설정
         DungeonManager.GetInstance().SetMainCameraPos();

	// 타일들과 미니맵의 상태를 변경
         DungeonManager.GetInstance().SetVisibilityTiles( nextDoor.ownerCell.id, true );
         DungeonManager.GetInstance().SetVisibilityTiles( ownerCell.id, false );

         DungeonManager.GetInstance().ActivateMinimap( nextDoor.ownerCell.id, true );
         DungeonManager.GetInstance().ActivateMinimap( ownerCell.id, false );
     }
 }

 

결과

결과는 아래와 같다.