[게임 개발] Tiny 2D RPG: 5 - Map 템플릿 (3)

이정석·2023년 10월 11일

Tiny 2D RPG

목록 보기
5/9

Tiny 2D RPG

📖 [Map 템플릿 (2)]에 이어서, Map 템플릿의 마지막 단계인 배경설정단계이다. 물론, 이후에 캐릭터의 소환 위치나 특정 Object의 위치설정을 템플릿화 시킬 수 있겠지만 지금은 배경설정 단계가 마지막 단계이다.

기존의 Map은 배경이 아래사진과 같이 배경 Object가 하나만 있는 맵이었지만, 게임이 실행되면 연속된 배경들이 생성되는 구조로 개선하고 싶다.

1. Background Prefab

배경을 설정하기 위해서는 하나의 Background Object가 필요한데 이를 Prefab으로 만들어 두면 Map을 불러올 때 Background도 같이 불러올 수 있다는 장점이 있다.

Prefab을 만들었으니 기존 Map Prefab에는 Background Object를 삭제할 수 있다.

BackGround Prefab의 구조는 아래 사진과 같다. 전체 Sprite Renderer를 가지고 있는 부모 Object내에 여러가지 Sprite Renderer Component를 가지고 있는 구조로 되어 있는 것을 알 수 있다.

2. Map Data

💻 [Map 템플릿 (2)]에서 Map의 정보를 추출하는 기능을 만들었는데 Background에 관련한 Map 정보를 추가할 필요가 있다.

  • 배경으로 어떤 Object를 사용할 것인가?
  • Background Object의 시작 y좌표는 어디인가?

Background Prefab으로 배경을 따로 분리해놓았기 때문에 어떤 배경을 사용할지 설정하는 것은 이해하기 쉽지만, Object의 시작 y좌표를 따로 설정해주어야 한다는 것은 이해하기 쉽지 않을 수 있다.

'Tiny 2D RPG'는 엄연한 횡스크롤 RPG이기 때문에 특정 배경을 가로로 반복배치를 한다. 그리고 Map이 무조건 (0, 0)을 포함한다는 가정을 할 수가 없다. 즉, X좌표는 TileMap의 MinX, MaxX로 반복생성하면 되지만 Y좌표는 그럴수 없다는 것이다.

배경을 미리 Map에다 올려주고 적절한 자리를 찾아 설정해주는 방법을 사용하면 실제 Map을 불러올 때 알맞은 위치에 배경을 띄울 수 있다.

        foreach (GameObject go in gameObjects)
        {
            Tilemap tmBase = Util.FindChild<Tilemap>(go, "Ground", true);
            Tilemap tm = Util.FindChild<Tilemap>(go, "Collision", true);

            using (var writer = File.CreateText($"{pathPrefix}/{go.name}.txt"))
            {
                writer.WriteLine(tmBase.cellBounds.xMin);
                writer.WriteLine(tmBase.cellBounds.xMax);
                writer.WriteLine(tmBase.cellBounds.yMin);
                writer.WriteLine(tmBase.cellBounds.yMax);

                for (int y = tmBase.cellBounds.yMax; y >= tmBase.cellBounds.yMin; y--)
                {
                    for (int x = tmBase.cellBounds.xMin; x <= tmBase.cellBounds.xMax; x++)
                    {
                        TileBase tile = tm.GetTile(new Vector3Int(x, y, 0));
                        if (tile != null)
                            writer.Write("1");
                        else
                            writer.Write("0");
                    }
                    writer.WriteLine();
                }

                // 추가 세부사항 표기
                // 기본 배경ID는 1, Y값은 4
                writer.WriteLine("1");
                writer.WriteLine("4");
            }
        }

3. Map Manager

Map을 불러오는 Map Manager에 배경을 불러오는 부분을 추가해야하는데 우선 맵을 불러오는 LoadMap같은 경우 아래와 같이 수정한다.

    public void LoadMap(int mapId)
    {
		/*
        	... 생략
        */
        
        // 배경 설정하기
        int backgroundId = int.Parse(reader.ReadLine());
        float settingY = float.Parse(reader.ReadLine());
        SetBackground(go, backgroundId, settingY);
    }

이제 배경을 설정하는 SetBackground를 구현하면 되는데 배경을 가로방향으로 연속적으로 배치하기 위해 너비(Width)만큼 움직여주어야 한다. Sprite 역시 Center가 전체 이미지의 정중앙이라는 보장이 없다. 그래서, Center로 Width만큼 움직이며 Background Object를 생성해 주어야한다.

Width만큼 움직이며 배경을 설정하는 구조는 아래 그림과 같이 나타낼 수 있다.

구현한 SetBackground 함수는 아래와 같다. Background의 부모가 될 GameObject와 Background TemplateID, 시작 y좌표를 입력받아 이에 해당하는 Background Object를 찾고 이를 너비에 맞게 생성한다.

    public void SetBackground(GameObject parentGo, int backgroundId, float settingY)
    {
        string backgroundName = "Background" + backgroundId.ToString("000");
        float width = -1.0f, x = MinX;

        while (x < MaxX)
        {
            // 생성
            GameObject go = Managers.Resource.Instantiate($"BackGround/{backgroundName}", parentGo.transform);

            // 배경 너비 구하기
            if (width == -1.0f)
            {
                SpriteRenderer sprite = Util.FindChild<SpriteRenderer>(go, "Background1", false);
                width = sprite.bounds.size.x;
            }

            // 배경 위치 조정
            go.transform.position = new Vector3(x, settingY, 0);
            x += width;
        }
    }

결과

배경설정까지 완료함으로 Map 템플릿을 설정하는 과정은 여기서 마무리되었다. 다음단계로는 Scene에 캐릭터가 자동으로 생성되도록 구조를 바꾸고 아마 몬스터에 대한 기능까지 구현하고 서버를 붙이는 작업을 할 것 같다.

profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글