내일배움캠프 Unity 70일차 TIL - 팀 9와 4분의 3 - 개발일지

Wooooo·2024년 2월 2일
0

내일배움캠프Unity

목록 보기
72/94

[오늘의 키워드]

오늘은 섬의 절차적 생성 방식에 슬라이드 블럭을 추가하는 로직을 추가했다.

원래는 브러시 같은 툴을 만들어서 직접 하나하나 배치하려고 했지만, 코드로 자동으로 생성되게 하는게 더 편하고 빠를 것 같았다.


[트러블 슈팅]

슬라이드 블럭의 모든 머티리얼이 통일되는 문제

섬마다 슬라이드 블럭의 머티리얼이 다르다.

분명 섬마다 다른 머티리얼이 적용되도록 설정했는데, 생성 후에 보면 모든 슬라이드 블럭의 머티리얼이 가장 기본이 되는 Grass 머티리얼로 통일됐었다.

SharedMaterial

    private Material[] GetMaterials()
    {
        return GetMeshRenderer().sharedMaterials;
    }

이 문제는 SharedMaterial을 바꾸도록 해서 그런거였다.

메시렌더러의 프로퍼티를 보면 material이 있고 sharedMaterial이 있는데, material에 접근하면 오브젝트 하나에 하나씩 할당되는 새로운 머티리얼 인스턴스를 참조하는 것이고, sharedMaterial에 접근하면 같은 오브젝트들이 공유하는 하나의 머티리얼 인스턴스를 참조한다.

그래서 이 부분을 material을 바꾸도록 했더니 ..........

프레임이 엄청나게 떨어졌다.
현재 맵에는 수 천개의 슬라이드 블럭이 있을 것으로 예상된다. 이것들이 한 놈에 하나씩 새로운 인스턴스를 생성하여 갖게돼서 배치 수도 늘고, 메모리 점유율도 늘어서 발생한 현상이다.

결국 마지막 방법으로, 다른 머티리얼을 써야하는 슬라이드 블럭마다 프리팹을 새로 만들어서 쓰기로 했다.

뭔가 되게 허무한 해결 방법이다.

하나의 프리팹, 하나의 머티리얼로 여러 개의 슬라이드 블럭을 표현할 방법이 있을까? 생각해봤는데,
예상되는 해결 방법으로는 현재 청크가 일반 블럭들의 uv 좌표를 코드로 건드려서 텍스처 아틀라스를 사용하는 것처럼 슬라이드 블럭에도 uv 좌표를 코드로 건드려서 텍스처 아틀라스를 적용하는 방법이다.

나중에 시간이 되면 시도해봐야겠다.


[절차적 섬 생성에 슬라이드 블럭 생성 로직 추가하기]

처음에 맵 에디터를 만들었을 때도, 큐브를 배치하면서 섬을 디자인하려다가 때려치고 코드로 생성하게 했었는데 이번에도 슬라이드 블럭을 직접 배치하기 위해 에디터를 만드려다가 때려치고 코드로 생성하게 했다.

자연스럽게 배치하는 방법도 난 잘 모르겠고 ,, 맵도 은근 크기가 있어서 하나하나 배치할 시간도 모자랐다.

맵을 너무 오랜 시간 붙잡고 있는 것 같아서 후딱 해치우고 다른 기능도 구현해야겠다는 생각도 들고 ,, 뭐 그런 생각들이 들었다.

아무튼, 슬라이드 블럭을 생성하는 로직을 넣었다.

섬 데이터를 생성하고 나면, 블럭들을 하나하나 돌아다니면서 이 블럭이 전후좌우 중에 뚫린 곳이 한 곳만 있는 지를 먼저 판단했다.
언덕이나 산 같은 모양의 지형은 앞에는 트여있고, 뒤는 막혀있는, 약간 둥근 모양을 하고 있기 때문에 그렇다.

그 다음에는 뚫린 칸의 밑 칸이 Solid한 블럭인지 판단했다. 블럭이 허공에 둥둥 떠있으면 안되기 때문이다.

이렇게 하고 테스트로 생성을 해봤더니, 경사가 급박한 산 지형이 슬라이드 블럭으로 떡칠이 됐다. 뭔가 블럭을 이용한 맵 같지가 않고 엄청 딱딱한 로우폴리 맵처럼 보여서, 조건을 하나 더 추가했다.

결과적으로, 슬라이드 블럭이 생성되는 조건은 다음과 같아졌다.

  1. Solid한 임의의 블럭의 전후좌우 중, 한 방향으로만 뚫려있는지 판단
  2. 뚫린 칸의 아래 칸이 Solid한 블럭인지 판단
  3. 2번 칸의 앞 칸도 Solid한 블럭인지 판단

3번은 급격한 경사면에 슬라이드 블럭이 떡칠되는 것을 막기 위해 추가했다.

코드

        foreach (var block in worldMap.Values)
        {
            Vector3Int? pos = null;
            Vector3Int? forward = null;
            int openCount = 0;
            for (int i = 0; i < 4; i++)
            {
                Vector3Int checkPos = block.position + check[i];
                // 바라보는 칸이 아예 비었음.
                // 그 아래칸은 Solid임
                // 그 아래칸의 바라보는 칸도 Solid임

                if (worldMap.ContainsKey(checkPos) ||
                    !worldMap.TryGetValue(checkPos + Vector3Int.down, out var checkBlock) ||
                    !worldMap.TryGetValue(checkPos + Vector3Int.down + check[i], out var checkBlock2))
                    continue;

                if (checkBlock.type.IsSolid && checkBlock2.type.IsSolid)
                {
                    pos = checkPos;
                    forward = -check[i];
                    openCount++;
                }
            }

            if (pos.HasValue && forward.HasValue && openCount == 1)
            {
                MapData newSlideBlockData = new()
                {
                    forward = forward.Value,
                    type = _slideBlock.type,
                    typeIndex = _slideBlock.typeIndex,
                };
                _data.TryAdd(pos.Value, newSlideBlcokData);
            }
        }
profile
game developer

0개의 댓글