Unity/Final

Unity 내배캠 최종 프로젝트 6일차, 멍

Jee-U 2025. 4. 11. 21:50

오늘은 뭔가 한건 많은데 한게 없는것 같다.

뭔가 정신도 붕 떠있고 집중도 안되고 뭔가 붕 떠있는 느낌..? 그래서 주말에는 집 대청소도 하고 정리를 좀 해보려고 한다.

일단 오늘 한걸 최대한 정리를 해보자면

 

내가 짜야하는 스크립트의 구조는 아래와 같다.

 

맵 해금 - TileManager

낮과 밤, 시간변화 : TimeManager, MapManager 를 통하여 관리

TimeManager 게임시간 관리, 낮/밤 판별, 시간 이벤트 관리 TimeScreen 시간 정보를 UI에 표시, 시각적표현
MapManager 전체 맵 제어, 시간에 따른 맵 반응 처리 Map 개별 맵 상태, 조명 타일 등 구체요소 관리

TimeScreen과 Map은 각각 매니저를 통해 관리되는 용도이며 전체적으로 짜여져있는 스크립트를 용도에 맞게 구분한건데 뭔가 뭔가다.. 내가 아직 구조에 대해 이해를 못하고 있다는게 너무 느껴진다.

 

어제 작성한 TileManager도 오늘 테스트를 해보고자 했으나 코드 수정 및 다른 스크립트 작성으로 인해 테스트는 하지 못하였다..

 

일단 TileManager는 

public class TileManager : Singleton<TileManager>
{
    protected override bool IsPersistent => false;

    public GameObject lockBlockTile;

    // 초기 타일 위치 저장용 리스트
    private List<Vector3> OriginalTiles = new List<Vector3>();

    // Vector3Int : 월드 좌표나 그리드 좌표를 기준으로 씀
    // gird position, gridpos : 격자 좌표
    private Dictionary<Vector3Int, GameObject> tiles = new Dictionary<Vector3Int, GameObject>();


    private void Start()
    {
        StartCoroutine(ResetTilesCoroutine());
    }

    // 타일 초기화
    private void InitializeTiles()
    {
        tiles.Clear();
        OriginalTiles.Clear();

        foreach (Transform child in lockBlockTile.transform)
        {
            // 각 타일의 월드 위치를 그리드 좌표로 바꿈
            Vector3Int gridPos = GridPosition(child.position);
            // 그 좌표를 키로 딕셔너리에 저장
            tiles[gridPos] = child.gameObject;

            OriginalTiles.Add(child.position);
        }
    }

    // 상호작용 후 타일 제거, 플레이어용
    public void ClearTile(Vector3 worldPos)
    {
        if (CheckTile(worldPos))
        {
            RemoveTile(worldPos);
        }
    }

    // 그리드 좌표로 변환, 딕셔너리의 키로 만들어줄수있게 하는 함수
    private Vector3Int GridPosition(Vector3 worldPos)
    {
        return Vector3Int.RoundToInt(worldPos);
    }

    // 특정 그리드 위치에 타일이 존재하는지 확인
    public bool CheckTile(Vector3 worldPos)
    {
        return tiles.ContainsKey(GridPosition(worldPos));
    }

    // 상호작용한 위치의 타일 제거
    public void RemoveTile(Vector3 worldPos)
    {
        Vector3Int gridPos = GridPosition(worldPos);

        if (tiles.TryGetValue(gridPos, out GameObject tile))
        {
            Destroy(tile);
            tiles.Remove(gridPos);
        }
    }

    public IEnumerator ResetTilesCoroutine()
    {
        // 딕셔너리에 있는 기존 타일들을 전부 파괴
        foreach (var tile in tiles.Values)
        {
            if (tile != null)
                Destroy(tile);
        }
        // 다음 프레임까지 좀 기다려줘야함, 삭제중에 생성이 시작되면 문제가 있을 수 있기 때문
        yield return null;

        // 딕셔너리 정리
        tiles.Clear();

        // 한 프레임씩 쉬면서 타일 재생성
        foreach (Vector3 pos in OriginalTiles)
        {
            GameObject newTile = Instantiate(lockBlockTile, pos, Quaternion.identity, transform);
            Vector3Int gridPos = GridPosition(pos);
            tiles[gridPos] = newTile;
            yield return null; // 타일 하나 만들고 한 프레임 쉼
        }

        InitializeTiles();
    }
}

 

일단 딕셔너리에 맵을 저장하고 삭제해나가는 방식인데 이렇게 삭제하면 게임이 재시작될때 사라진 블럭이 복구가 되지 않기에 리스트를 추가하여 초기화하는 방식이다.

원래 초기화 메서드는 코루틴을 사용하지 않았는데 기존타일을 삭제함과 동시에 새 타일이 생성되고 있으면 문제가 생길 수 있다고 튜터님께서 조언해주셔서 딜레이를 주기위해 코루틴을 사용해주었다.

그리고 이 TileManager 스크립트는 타일팔레트가 있는 오브젝트에 적용해주었다.

 

사실 여기까지 작성하면서 내가 작성하기보단 ai 도움을 많이 받았다.. 그래서 내가 작성한 코드가 아니라는 느낌이 너무 들어 전체적인 흐름이랑 구조를 다잡기 위해 주말에 혼자 작성하면서 리팩토링 해보고자 한다.

그리고 코루틴에 대해서는 공부한적은 있으나 다시한번 제대로 공부하여 깔끔하고 좋게 사용해보려고 한다.

 

TimeManager의 경우 낮과밤을 전체적으로 제어해줄 수 있게 해주었고 밤일때 시간이 다 되면 낮으로 변경, 낮에는 적이 다 죽으면 밤이 될수있게 작성해주었으나 타일매니저 다 끝내놓고 다른 스크립트 리팩토링 하는게 주말까지의 목표다.

오늘은 진짜 내가 뭘 해야할지 몰라 방황한 느낌이었는데 정리하자면

 

- 코루틴 공부

- 타일매니저 리팩토링

- 임시 플레이어 생성하여 테스트

- 낮과 밤 기능쪽 테스트