본문 바로가기
Development/Unity

무한 맵 만들기

by 식냥 2024. 6. 18.
728x90

[내일배움캠프 44일차 TIL]

 

'길건너 친구들'이라는 게임을 모작하면서, 가장 기본이 되는 맵을 어떻게 할 것인가에 대한 고민이 많았다.

똑같은 맵 지형이 반복되기 때문에 이걸 길게 만드는 것도 힘들뿐더러 끝이 정해져 있기 때문에 게임의 재미가 떨어진다.

그래서 하나의 맵 지형을 만들어서 프리팹화하고, 오브젝트 풀을 이용해 플레이어가 움직였을 때 일정 범위 내라면 맵을 생성하는 로직을 구현했다.

 

실제 동작 모습

 

[ 무한 맵 만들기 ]

전체 코드

using System.Collections.Generic;
using UnityEngine;

public class MapManager : MonoBehaviour
{
    [SerializeField] private Camera camera;
    public GameObject unitPrefab;
    public int unitNum; // 화면에 표시될 유닛 개수
    private Queue<GameObject> activeUnit = new Queue<GameObject>();
    private float unitLength = 31.3f;   // 유닛 길이
    private float spawnZ = 15.0f;   // 생성될 Z 위치

    void Start()
    {
        camera = GetComponent<Camera>();

        for (int i = 0; i < unitNum; i++)
        {
            SpawnUnit();
        }
    }

    void Update()
    {
        GameObject usedUnit = activeUnit.Peek();
        float cameraZ = camera.transform.position.z;

        // 생성 조건
        if (cameraZ + 8 > usedUnit.transform.position.z + unitLength)
        {
            SpawnUnit();
        }

        // 제거 조건(현재 제거 방식이 개수가 부족할 때 오래된 것을 가져다가 쓰는 거라서 해당 코드 미작동. 하지만 예외가 있을 수 있으므로 일단 구현)
        if (usedUnit.transform.position.z + unitLength < camera.transform.position.z)
        {
            RemoveUnit();
        }
    }

    private void SpawnUnit()
    {
        GameObject unitMap;
        if (activeUnit.Count < unitNum)     // 생성
        {
            unitMap = Instantiate(unitPrefab, new Vector3(50, 1.4f, spawnZ), Quaternion.identity);
            activeUnit.Enqueue(unitMap);
        }
        else    // 활성화
        {
            unitMap = activeUnit.Dequeue();
            unitMap.transform.position = new Vector3(50, 1.4f, spawnZ);
            unitMap.SetActive(true);
            activeUnit.Enqueue(unitMap);
        }
        spawnZ += unitLength;
    }

    private void RemoveUnit()
    {
        GameObject usedUnit = activeUnit.Peek();
        if (usedUnit.transform.position.z + unitLength < camera.transform.position.z)
        {
            usedUnit.SetActive(false);
            activeUnit.Dequeue();
        }
    }
}

먼저 Start 메서드에서 설정한 화면에 표시될 유닛 개수만큼 맵 유닛을 만들어서 오브젝트 풀에 미리 넣어놓는다.

 

맵이 생성되는 범위를 정하는 기준이 카메라이므로, 메인 카메라를 가져온다. 원래는 컴포너트에서 카메라를 직접 할당하는 것 없이 자동으로 찾게 하고 싶었는데, 원하는 대로 잘 작동하지 않아서 일단은 직접 할당하는 방법으로 진행했다. 이 부분은 리팩토링을 해보면 좋을 것 같다.

 

Update 메서드에서 메인 카메라의 Z위치를 가져온다. 생성 조건에서 8을 더한 것은 게임 화면에서의 시야를 의미한다.

usedUnit은 현재 활성화된 맵 유닛 중 가장 최신의 것을 가져온 것이다. 그래서 현재 활성화된 맵 + 맵 유닛 하나 더 들어갈 수 있는 공간보다 시야가 더 넓으면, 앞에 빈 공간이 보이게 되므로 유닛을 하나 생성한다.

 

근데 쓰다보니 코드가 뭔가 이상하다......... 리팩토링이 필요한 것 같다.

728x90
반응형