일단 새로 다시 작성하고자 하는 TileManager에서 해야하는 기능들은 아래와 같다.
- 자원타일 배치
- 자원의 수는 한정되어 있음
- 자원끼리는 겹치지 않아야 함
- 잠금타일 사이에 걸치지 않아야 함
- 잠금타일 배치
- 랜덤배치는 없음
- 초기 7칸은 해금되어있는 상태로 시작
잠금타일의 경우 랜덤배치가 없고 모든 스테이지는 7칸이 해금되어있는 상태로 시작되기 때문에 미리 만들어두는것도 괜찮지 않나? 라고 생각했는데 스크립트에서 동적으로 배치해주는게 더 괜찮다고 하여 그렇게 진행해주었다.
그리고 오늘 코딩은 나 혼자가 아닌 조원분과 같이 진행하였는데 이렇게 된 과정은 어제 저녁 회의하다가 리드개발자 분께서 나의 시너지와 조원분의 장점이 합쳐지면 더 좋은 효과가 있지 않을까 라고 하셨는데 나의 장점은 소통이고 조원분의 장점은 지식과 방향성이라고 하셨따. 그리하여 오늘 하하호호 재미있게 같이 진행 하였는데 조원분이 방향성을 가이드해주지 않으셨다면 며칠 걸렸을 작업이었겠지만 덕분에 하루만에 끝내게 되었다 (근데 이정도면 조원분께서 거의 다 해주신게 아닌가 싶었다)
- 코드 작성하면서 방향을 잘 못잡고있으면 바로잡아주시고 막히는 부분은 최대한 이해할수있게 설명해주시고 막히는 부분은 같이 고민해주셨다.
순서상 자원타일 배치가 먼저지만 코드 작성은 잠금타일부터 해주었다.
public class TileManager : Singleton<TileManager>
{
int gridCount = 20; // 전체 크기
[SerializeField] private GameObject lockTileObj; // 잠금타일 프리펩
[SerializeField] private Grid grid;
public void SetLockTileMap()
{
for (int x = 0; x < gridCount; x++)
{
for (int y = 0; y < gridCount; y++)
{
Vector3Int gridCell = new Vector3Int(x, y, 0); // grid 좌표로 변환
Vector3 worldPos = grid.CellToWorld(gridCell); // 월드 좌표로 변환
// adjustedPos : 최종 위치값
Vector3 adjustedPos = new Vector3(worldPos.x, 0f, worldPos.y); // y축은 0으로 고정
Instantiate(lockTilesPrefab, adjustedPos, Quaternion.identity, transform); // 프리팹을 addjustedPos 월드위치에 회전없이 생성
}
}
}
gridCount로 전체 그리드 크기를 정하고, lockTileObj로 생성할 타입 프리팹을 지정한다.
SetLockTileMap은 타일배치를 하기위한 메서드인데
이중 for문을 돌며 x, y셀 좌표를 전부 순회하고 각 셀을 월드 좌표로 변환해 타일을 배치하며 y는 0으로 고정한다.
일단 여기까지 작성하고 재생해보았는데

???

왜이러냐..?
근데 잘못된게 맞았다.
중간에 Vector3 adjustedPos = new Vector3(worldPos.x, 0f, worldPos.y); 부분의 worldPos.y를 wolrdPos.z로 바꿨더니 정상적으로 작동했다.
y는 높이이며 값이 잘못 적용되어 타일이 한줄로 깔리게 되었고 3D에선 x와 z로 해주는게 맞는데 중간에 오타가 이러한 결과를 불러왔다..

짠! 예쁘게 잘 배치되었다. 이제는 플레이어가 초기에 활동할 수 있는 공간을 만들어 줄 차례다.
초기엔 7개의 타일이 해금된 상태로 시작하며 해금된 모양도 2-3-2로 약간 육각형에 가까운 모양이다.
[SerializeField] private List<Vector2Int> excludedCells;
public void SetLockTileMap()
{
for (int x = 0; x < gridCount; x++)
{
for (int y = 0; y < gridCount; y++)
{
Vector2Int cell = new Vector2Int(x, y);
if (excludedCells.Contains(cell))
continue;
Vector3Int gridCell = new Vector3Int(x, y, 0);
Vector3 worldPos = grid.CellToWorld(gridCell);
Vector3 addjustedPos = new Vector3(worldPos.x, 0f, worldPos.z);
Instantiate(lockTileObj, addjustedPos, Quaternion.identity, transform);
}
}
}
이 해금 영역을 구현하기 위해 excludedCells 리스트를 만들어주었는데, 이 리스트는 잠금 타일을 배치할 때 제외할 좌표들을 담고있으며 인스펙터에서 좌표를 직접 입력해주면 해당 위치는 타일이 생성되지 않도록 설정할 수 있다.
그래서 타일이 생성되는 과정에서 excludedCells 리스트에 포함된 좌표를 검사하여 포함되어 있다면 해당 좌표는 건너뛰고 나머지 위치에만 잠금 타일을 배치하게 해주었다.
이 위치 확인은 어떻게 하였나면
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red; // 기즈모 설정 색
foreach (var cell in excludedCells)
{
Vector3Int gridCell = new Vector3Int(cell.x, cell.y, 0); // 3D좌표로 변환
Vector3 worldPos = grid.CellToWorld(gridCell); // 월드좌표로 변환
Vector3 pos = new Vector3(worldPos.x, 0f, worldPos.z); // 위치
Gizmos.DrawWireCube(pos, Vector3.one * 2f); // 와이어프레임 박스 표시 (222 크기의 정육면체)
}
}
기즈모 기능을 이용해주었다.
- 기즈모란 씬에 있는 게임오브젝트와 관련된 그래픽이며 시각적 디버깅을 위해 사용된다.
인스펙터에서 좌표를 입력하면 씬뷰에서 빨간 사각형의 박스로 위치가 어딘지 보여준다. 기즈모는 잘 모르는 기능이었는데 조원분덕에 사용해보았다.

짜잔, 이렇게 설정해주고 실행하게 되면

추가로 잠금타일 파괴, RemoveTile()을 원래 TileManager에 작성해주고 상위 오브젝트에 붙여넣었었는데 이 메서드는 LockTile이란 스크립트를 새로 작성하여 그쪽으로 옮겨준 후 타일 프리팹에 적용시켜주었다.
그리고 플레이어와 잠금타일의 충돌 처리인데
public LayerMask playerLayerMask;
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.layer == playerLayerMask)
{
// 플레이어만 충돌처리하여 지나갈 수 없게 처리
}
}
충돌처리에 대해서는 원래 플레이어를 제외한 나머지는 충돌이 되지 않게 해야하여 오브젝트에 IsTrigger를 체크해두고 스크립트에 플레이어 레이어만 감지해서 충돌할 수 있게 하려고 하였는데
Collision도아니고 Trigger로 하려니 도저히 모르겠더라.. 둘이서 끙끙대다 결국 도움을 요청드리게 되었는데 Trigger로는 우리가 원하는 의도대로 하기 어렵다고 하셨는데 대신 다른 방안이 있었고 그 방안은 유니티에서 제공해주는 기능이었다.
일단 LockTile이라는 레이어를 하나 추가해주고 Project Settings > Physics > Layer Collision Matrix를 이용해 LockTile 레이어는 Player 레이어랑만 충돌할수 있게 해주었다.
- 언젠가 Layer Collision Matrix 기능에 대해 보기는 봤었는데 제대로 사용해본적은 없었다. 다만 이런식으로 사용이 가능하다는걸 이번에 알게되었고 다른 작업을 할때 유용하게 사용할수 있을듯 하다 (예를들면 혼자 하던 프로젝트에서 땅 혹은 장애물 등 충돌처리와 관련하여..?)

이제 진짜로 잠금타일 부분은 끝이다!
다음은 자원타일이다.
자원은 일단 임시로 Cube와 Capsule을 하나씩 만들어 두었다.

메서드명은 SetResourceTileMap(), 여기에 자원을 배치해주는 내용을 작성해주었다.
int resourceCount = 20; // 자원 갯수
[SerializeField] private List<GameObject> resourceTileObj; // 자원타일 프리펩 리스트
public void SetResourceTileMap()
{
// 자원타일이 이미 배치된 좌표 확인용
List<Vector2Int> useTileObj = new List<Vector2Int>();
for (int i = 0; i < resourceCount; i++)
{
int randomX = Random.Range(0, gridCount);
int randomY = Random.Range(0, gridCount);
int resourceType = Random.Range(0, resourceTileObj.Count);
Vector2Int cell = new Vector2Int(randomX, randomY); // 랜덤 좌표 생성
if (useTileObj.Contains(cell)) // 이미 배치된 좌표일경우 반복횟수 복원
{
i--;
continue;
}
useTileObj.Add(cell); // 좌표 등록
Vector3Int gridCell = new Vector3Int(randomX, randomY, 0); // grid 좌표로 변환
Vector3 worldPos = grid.CellToWorld(gridCell); // 월드좌표로 변환
Vector3 addjustedPos = new Vector3(worldPos.x, 0f, worldPos.z); // 최종위치값 = y축은 0으로 고정, xz평면위에 배치
Instantiate(resourceTileObj[resourceType], addjustedPos, Quaternion.identity, transform); // 프리팹들을 adjustedPos월드위치에 생성
}
}
for문을 이용해 resourceCount 만큼 반복하며 각 반복에서 0~gridCount 사이의 값을 랜덤으로 생성하여 좌표를 구한다.
잠금타일의 기능과 비슷한 부분이 많은데 차이점이 있다면 랜덤배치 및 제외 방식이다.
랜덤배치의 경우 Random.Range를 이용해주었으며
자원타일의 경우 랜덤생성이 베이스이기 때문에 중복생성이 되는경우가 있을듯 하여 그것을 방지하고자 useTileObj 리스트를 만들어주었으며 외부에서는 사용하지 않기에 지역변수로 만들어주게 되었다.
그리고 자원의 경우 하나가 아니기 때문에 잠금타일과는 다르게 자원타일은 List로 해주었는데 종류가 한개가 아니기 때문에 resourceType을 이용해 랜덤한 자원 타일의 인덱스를 선택하여 자원의 종류도 다양하게 배치되도록 하였다.
근데 이렇게 하고보니 나는 20개의 자원을 맵에 배치하려고 하였는데 중복 좌표로 인해 일부 자원이 생성되지 않는 문제가 발생할 수 있다고 하여 이부분을 보완하기 위해 if문 안에 i--를 넣어 이미 배치된 좌표일경우 반복횟수를 복원되게 해주었고 그 뒤에 좌표를 등록한 후 배치가 될수있게 해주었다.
이렇게 하여 자원배치도 끝.
+ 프리팹들은 TileManager 하위에 생성되고 있었는데 이게 너무 어지럽더라.. 그래서 프리팹을 각각 잠금타일 / 자원타일 빈 오브젝트의 하위에 생성해주고 싶었다.
public Transform lockt;
public Transform rockt;
이렇게 lockt, rockt(변수명은 임시로 대충지었다) 이름으로 Transform 변수를 선언 후

그리고 Instantiate 부분에 있는 transfrom 자리에 각각 lockt, rockt를 넣어주면 설정해둔 오브젝트 하위에 생성된다.
이부분은 나중에 수정될수도 있고 다른 수정 작업이 진행될수도 있어 제외했지만 이러한 기능이 있다는걸 알게되었고 정리를 좋아하는 나는 나중에 잘 써먹을듯 하다.
오늘 하루 알찻다~!
'Unity > Project' 카테고리의 다른 글
| [Unity] 내배캠 최종프로젝트 : 루시퍼 서바이벌 16일차, (0) | 2025.04.28 |
|---|---|
| [Unity] 내배캠 최종프로젝트 : 루시퍼 서바이벌 15일차, 배치지옥 (0) | 2025.04.25 |
| [Unity] 내배캠 최종프로젝트 : 루시퍼 서바이벌 13일차, 첫 병합 (0) | 2025.04.23 |
| [Unity] 내배캠 최종프로젝트 : 루시퍼 서바이벌 11일차, 맵 그리고 맵 (0) | 2025.04.21 |
| [Unity] 내배캠 최종프로젝트 : 루시퍼 서바이벌 10일차, 맵이 뭔데 (0) | 2025.04.18 |