[Unity] 커스텀 타일맵 2 - Grid 위에 오브젝트 생성하기

0시0분·2024년 8월 13일
0

Unity

목록 보기
23/24

+24-08-13 수정(참고 링크 추가)

결과


(1) 마우스 좌표 → 격자 좌표 변환

Vector3 MousePosToGridPos(Vector2 clickPos)
{
    Ray ray = HandleUtility.GUIPointToWorldRay(clickPos);
    var floorPosition = editTilemap.transform.position + (Vector3.up * floorIndex);
    Plane plane = new Plane(Vector3.up, floorPosition);

    if (plane.Raycast(ray, out float enter))
    {
        Vector3 rayPoint = ray.GetPoint(enter);

        rayPoint.x = Mathf.Round(rayPoint.x);
        rayPoint.y = Mathf.Round(rayPoint.y);
        rayPoint.z = Mathf.Round(rayPoint.z);

        return rayPoint;
    }

    return Vector3.negativeInfinity;
}

Event.current.mousePosition을 매개변수로 받아서 사용한다.

에디터 클릭 이벤트
👀 https://tistory.wonsorang.com/m/979

Plane을 사용해 클릭 좌표를 계산했다. Event.current.mousePoint를 직접 변환해서 계산하는 방법을 시도했었는데 좌표계에 대한 이해가 부족해서인지 쉽지 않았다.

격자 칸의 정중앙에 오브젝트를 생성해야 하기 때문에 Mathf.Round()를 사용했다.

참고
👀 plane 사용법 : https://m.blog.naver.com/happybaby56/221365696057



(2) 격자 좌표로 오브젝트 생성 및 제거

void GetGridPosition(Event e)
{
    switch (e.type)
    {
        case EventType.MouseDown:
            if (e.button == 0)  // 좌클릭
            {
                if (editTilemap == null)  return;

                gridPos = MousePosToGridPos(e.mousePosition);

                if (!IsValidPos(gridPos)) return;
                if (drawTile == null)   return;

                CreateTile(gridPos);
            }
            else if (e.button == 1)  // 우클릭
            {
                if (editTilemap == null) return;

                gridPos = MousePosToGridPos(e.mousePosition);

                if (!IsValidPos(gridPos)) return;

                RemoveTile(IsExistAt(gridPos));		// 🐸
            }
            break;
    }
}

🎈 오브젝트 생성

void CreateTile(Vector3 position)
{
    RemoveTile(IsExistAt(position));	// 🐸

    GameObject tile = (GameObject)PrefabUtility.InstantiatePrefab(drawTile);
    tile.transform.SetParent(editFloor.transform);
    tile.transform.position = position;

    // *** rotate

    // *** replace

    editFloor.GetComponent<CustomFloor>().tiles.Add(tile);
}

생성한 타일 오브젝트는 해당 층의 정보를 저장하고 있는 CustomFloor 클래스 안에서 tiles라는 이름의 리스트로 관리한다.

🎈 오브젝트 제거

void RemoveTile(int index)	// 🐸
{
    List<GameObject> tiles = editFloor.GetComponent<CustomFloor>().tiles;

    if (index != -1)
    {
        DestroyImmediate(tiles[index]);
        tiles.RemoveAt(index);
    }
}

tiles 리스트에서 position 값이 클릭한 좌표와 일치하는 오브젝트가 있을 경우 제거한다.

🐸

int IsExistAt(Vector3 position)
{
    List<GameObject> tiles = editFloor.GetComponent<CustomFloor>().tiles;
    for (int i = 0; i < tiles.Count; ++i)
    {
        if (tiles[i].transform.position == position)
            return i;
    }
    return -1;
}

나중에, 타일을 생성하고자 하는 위치에 타일이 존재할 때
1) 지우고 그리기
2) 그리지 않기
의 옵션을 추가하기 위해 해당 위치에 타일이 존재하는지 검사하는 로직을 분리했다.



(3) 격자 밖의 영역 예외처리

bool IsValidPos(Vector3 position)
{
    int halfVal = gridSize / 2;

    if (gridSize % 2 == 0)
    {
        float x = position.x;
        float z = position.z;

        if ((x > 0 && x > halfVal)
            || (x < 0 && x <= -halfVal)
            || (z > 0 && z > halfVal)
            || (z < 0 && z <= -halfVal))
            return false;
    }
    else
    {
        float x = Mathf.Abs(position.x);
        float z = Mathf.Abs(position.z);

        if (x > halfVal || z > halfVal)
            return false;
    }

    if (position == Vector3.negativeInfinity)
        return false;

    return true;
}

Plane을 사용해 좌표를 구했기 때문에 Grid 밖의 영역을 클릭해도 오브젝트가 생성 되는 문제가 발생했다. 👉 Plane의 영역은 무한함

처음엔 막연히 좌표의 절대값을 구해 gridSize 크기의 절반 값(halfVal) 보다 크면 그리지 않도록 처리했는데, 그렇게 되자 gridSize가 짝수일 때 문제가 생겼다.
👉 Grid의 왼쪽과 아래쪽 바깥 한줄씩이 처리 되지 않음

결국 gridSize가 짝수일 때와 홀수일 때를 분리해서 처리했다.


참고
👀 https://velog.io/@gold715/Map-tool-%EA%B5%AC%ED%98%841
👀 https://junwe99.tistory.com/39
👀 https://bloodstrawberry.tistory.com/1063
👀 https://assetstore.unity.com/packages/tools/level-design/fabgrid-level-editor-175642

0개의 댓글