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

0시0분·2023년 6월 13일
0

Unity

목록 보기
4/19

결과


(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을 매개변수로 받아서 사용한다.

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개의 댓글