본문 바로가기
게임 프로그래밍/유니티 활용

[유니티] 타일맵을 이용한 무한맵 생성

by 레오란다 2024. 6. 4.
반응형

1. 타일맵 만들기

 

메뉴에서 [GameObject > 2D object > Tilemap > Rectangular] 선택합니다.

타일맵 만들기

 

 

메뉴의 [Window > 2D > Tile Palette] 를 선택하거나 Hierarchy 창에서 Tilemap 을 선택하면 Scene 창 밑에 표시되는 [Open Tile Palette] 를 클릭해 Tile Palette 대화 상자를 엽니다.

Tile Palette

 

아래와 같이 Tile Palette 윈도우에서 빨간색 테두리 영역을 클릭해 새로운 팔레트를 생성하고 타일 이미지를 등록한 다음 Scene 창에 20x20 크기로 타일맵을 만들어 줍니다. 기본 타일맵은 반드시 원점을 중심으로 대칭이 되도록 그려주셔야 합니다

20x20 타일맵 생성

 

2. 간단한 캐릭터 이동

캐릭터

 

캐릭터 객체를 하나 만들고 카메라를 해당 캐릭터의 자식 객체로 이동한 다음 아래와 같은 스크립트를 작성해 추가합니다

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
   public float moveSpeed;

   // Start is called before the first frame update
   void Start()
   {      

   }

   // Update is called once per frame
   void Update()
   {
      float horizontalInput = 0f;
      float verticalInput = 0f;

      if (Input.GetKey(KeyCode.UpArrow))
      {
         verticalInput = 1f;
      }
      else if (Input.GetKey(KeyCode.DownArrow))
      {
         verticalInput = -1f;
      }

      if (Input.GetKey(KeyCode.LeftArrow))
      {
         horizontalInput = -1f;
      }
      else if (Input.GetKey(KeyCode.RightArrow))
      {
         horizontalInput = 1f;
      }

      Vector2 moveDirection = new Vector2(horizontalInput, verticalInput).normalized;
      transform.Translate(moveDirection * moveSpeed * Time.deltaTime);
   }
}

 

3. 무한 타일맵 스크립트

새로운 GameObject 를 생성하고 이름을 InfiniteTilemapManager 라고 변경한 다음 다음의 스크립트를 작성해 추가합니다

 

타일맵

 

using UnityEngine;
using System.Collections;
using UnityEngine.Tilemaps;

public class InfiniteTilemap : MonoBehaviour
{
   public GameObject grid; // Grid 오브젝트
   public Transform player;
   private Vector3Int playerGridPosition;
   private Vector3Int lastPlayerGridPosition;

   private Vector2 tilemapSize; // 타일맵 크기

   void Start()
   {
      var tile = grid.transform.GetChild(0);

      tilemapSize = CalculateTileSize(tile.GetComponent<Tilemap>());
      
      // 타일맵 복사
      for (int i = 0; i < 3; i++)
      {
         Instantiate(tile).transform.SetParent(grid.transform);
      }

      int index = 0;

	  // 타일맵 배치
      for (float x = -tilemapSize.x / 2; x <= tilemapSize.x / 2; x += tilemapSize.x)
      {
         for (float y = -tilemapSize.y / 2; y <= tilemapSize.y / 2; y += tilemapSize.y)
         {
            grid.transform.GetChild(index++).position = new Vector3(x, y, 0);
         }
      }

      // 플레이어를 중앙 타일맵의 중앙에 위치시키기
      PlayerController.Instance.transform.position = new Vector3(0, 0, 0);

      // 초기 플레이어 위치 저장
      playerGridPosition = GetGridPosition(player.position);
      lastPlayerGridPosition = playerGridPosition;
   }

   Vector2 CalculateTileSize(Tilemap tilemap)
   {
      // 타일맵의 셀 경계를 가져옵니다.
      BoundsInt bounds = tilemap.cellBounds;

      // 실제로 타일이 있는 영역을 계산합니다.
      Vector3Int? min = null;
      Vector3Int? max = null;

      foreach (var pos in bounds.allPositionsWithin)
      {
         if (tilemap.HasTile(pos))
         {
            if (min == null)
            {
               min = pos;
               max = pos;
            }
            else
            {
               min = Vector3Int.Min(min.Value, pos);
               max = Vector3Int.Max(max.Value, pos);
            }
         }
      }

      int width = -1;
      int height = -1;

      if (min.HasValue && max.HasValue)
      {
         width = max.Value.x - min.Value.x + 1;
         height = max.Value.y - min.Value.y + 1;
      }

      return new Vector2(width, height);
   }

   void Update()
   {
      // 현재 플레이어 위치를 그리드 좌표로 변환
      playerGridPosition = GetGridPosition(player.position);

      // 플레이어가 다른 그리드 칸으로 이동했는지 확인
      if (playerGridPosition != lastPlayerGridPosition)
      {
         UpdateTilemaps();
         lastPlayerGridPosition = playerGridPosition;
      }
   }

   // 월드 좌표를 그리드 좌표로 변환
   Vector3Int GetGridPosition(Vector3 position)
   {
      return new Vector3Int(Mathf.RoundToInt(position.x / tilemapSize.x), Mathf.RoundToInt(position.y / tilemapSize.y), 0);
   }

   // 타일맵 업데이트
   void UpdateTilemaps()
   {
      Vector3Int offset = playerGridPosition - lastPlayerGridPosition;

      foreach (Transform child in grid.transform)
      {         
         child.position += new Vector3(offset.x * tilemapSize.x, offset.y * tilemapSize.y, 0);
      }
   }
}

 

 

Inspector 에서 Grid와 Player를 연결하고 실행한 후 키보드의 방향키로 캐릭터를 움직이면 타일 4개를 이용한 무한맵이 완성된 것을 확인하실 수 있습니다

 

 

 

 

반응형

댓글