Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

게임 프로그래밍

[Unity] Custom TileMap Creator 본문

프로그래밍/유니티

[Unity] Custom TileMap Creator

Junwe 2020. 3. 17. 18:14

유니티에서는 기본적으로 타일맵 기능을 제공하고 있습니다. 그러나 현재 만드는 게임에서 기본적으로 제공되는 타일맵으로 맵툴을 만들기에는 제한적인 기능이 많아 따로 커스텀 에디터를 만들어서 제작하고 있습니다. 그러므로 이 기능을 간단하게 정리해볼려고 합니다.

 

우선은 이러한 Grid가 필요할것입니다.

Scene View에 Grid를 그리는 방법은 간단합니다. OnDrawGizmos 함수를 사용하면 Gizmos를 그릴수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Grid : MonoBehaviour
{
    public float width = 1f;
    public float height = 1f;
 
    public Color color = Color.white;
 
    public GameObject[] prefabsList;
 
    void OnDrawGizmos()
    {
        Vector3 pos = Camera.current.transform.position;    // 현재 scene view 에서 보고 있는 카메라 좌표를 가져옵니다.
        Gizmos.color = color;
 
        if (width <= 0 || height <= 0)
            return;
 
        for (float y = pos.y - 540f; y < pos.y + 540f; y += height)
        {
            Gizmos.DrawLine(new Vector3(10000000.0f, Mathf.Floor(y / height) * height, 0f),
            new Vector3(-10000000, Mathf.Floor(y / height) * height, 0f));
        }
 
        for (float x = pos.x - 540f; x < pos.x + 540f; x += width)
        {
            Gizmos.DrawLine(new Vector3(Mathf.Floor(x / width) * width, 10000000, 0f),
            new Vector3(Mathf.Floor(x / width) * width, -10000000, 0f));
        }
    }
}
 
cs

Grid라는 스크립트를 만들고 이렇게 작성해줍니다. Gizmos.DrawLine을 이용해서 Grid를 그려주시면 됩니다. 

Grid 스크립트를 게임오브젝트안에 넣으면 선이 보이게 될것입니다. 이제 Editor 스크립트를 이용해서 맵을 그릴수 있게 만들어 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
 
[CustomEditor(typeof(Grid))]
public class MapGridEditor : Editor
{
    Grid grid;
int ObjectIndex;
int SelectIndex;
    void OnEanble()
    {
        grid = (Grid)target;
    }
    void OnSceneGUI()
    {
        grid = (Grid)target;
 
        int crtID = GUIUtility.GetControlID(FocusType.Passive);
        Event e = Event.current;
 
        var mousePosition = Event.current.mousePosition * EditorGUIUtility.pixelsPerPoint;
        mousePosition.y = Camera.current.pixelHeight - mousePosition.y;
        Ray ray = Camera.current.ScreenPointToRay(mousePosition);
 
        if (Event.current.button == 0) // 마우스 왼쪽 버튼 클릭한 작동하도록 합니다.
        {
            if (SelectIndex == 0)
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    GUIUtility.hotControl = crtID;
                    e.Use();
                    DrawObject(true, ray.origin);
                }
                if (Event.current.type == EventType.MouseDrag)
                {
                    DrawObject(false, ray.origin);
                }
            }
            else if (SelectIndex == 1)
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    GUIUtility.hotControl = crtID;
                    e.Use();
                    DestoryObject(ray.origin);
                }
                if (Event.current.type == EventType.MouseDrag)
                {
                    DestoryObject(ray.origin);
                }
            }
        }
    }
 
    private void DrawObject(bool drag, Vector3 pos)
    {
        grid = (Grid)target;
        Vector3 createPos = new Vector3(Mathf.Floor(pos.x / grid.width) * grid.width + grid.width / 2f,
         Mathf.Floor(pos.y / grid.height) * grid.height + grid.height / 2f, 0f);
        if (CheckCompareObject(createPos, drag))
        {
            GameObject createObject = (GameObject)PrefabUtility.InstantiatePrefab(grid.prefabsList[grid.ObjectIndex]);
            createObject.transform.parent = grid.parent;
            createObject.transform.position = createPos;
            Undo.RegisterCreatedObjectUndo(createObject, "create Object");
        }
    }
 
    private void DestoryObject(Vector3 pos)
    {
        grid = (Grid)target;
        Vector3 createPos = new Vector3(Mathf.Floor(pos.x / grid.width) * grid.width + grid.width / 2f,
         Mathf.Floor(pos.y / grid.height) * grid.height + grid.height / 2f, 0f);
        if (CheckCompareObject(createPos, true))
        {
        }
    }    
 
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        grid = (Grid)target;
        EditorGUILayout.BeginHorizontal();
        string[] ObjectOptions = new string[grid.prefabsList.Length];
        string[] selectOptions = { "그리기""지우기" };
 
        for (int i = 0; i < ObjectOptions.Length; ++i)
        {
            if (grid.prefabsList[i] != null)
                ObjectOptions[i] = grid.prefabsList[i].name;
        }
      ObjectIndex = EditorGUILayout.Popup(grid.ObjectIndex, ObjectOptions);
      SelectIndex = EditorGUILayout.Popup(grid.SelectIndex, selectOptions);
 
        EditorGUILayout.EndHorizontal();
 
    }
 
    bool CheckCompareObject(Vector3 newPos, bool destoryObject)
    {
        Transform[] girdobjList = grid.parent.GetComponentsInChildren<Transform>();
        foreach (var obj in girdobjList)
        {
            if (obj.transform.position == newPos)
            {
                if (destoryObject)
                {
                    Undo.DestroyObjectImmediate(obj.gameObject);
                }
                return false;
            }
        }
        return true;
    }
}
 
cs

MapGridEditor라는 스크립트를 만드시면 됩니다. 간단하게 스크립트를 살펴보도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    void OnSceneGUI()
    {
        grid = (Grid)target;
        int crtID = GUIUtility.GetControlID(FocusType.Passive); // 씬뷰에 포커스를 유지 시키기 위함 입니다.
        Event e = Event.current;
        var mousePosition = Event.current.mousePosition * EditorGUIUtility.pixelsPerPoint;
        mousePosition.y = Camera.current.pixelHeight - mousePosition.y;
        Ray ray = Camera.current.ScreenPointToRay(mousePosition); // 클릭한 좌표를 Ray를 통해 가져옵니다.
        if (Event.current.button == 0)
        {
            if (SelectIndex == 0) // 그리기 모드
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    GUIUtility.hotControl = crtID;
                   e.Use(); // 포커스를 유지시켜 줍니다.
                    DrawObject(true, ray.origin);
                }
                if (Event.current.type == EventType.MouseDrag)
                {
                    DrawObject(false, ray.origin);
                }
            }
            else if (SelectIndex == 1) // 지우기 모드
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    GUIUtility.hotControl = crtID;
                    e.Use();
                    DestoryObject(ray.origin);
                }
                if (Event.current.type == EventType.MouseDrag)
                {
                    DestoryObject(ray.origin);
                }
            }
        }
    }
////cs

우선 OnSceneGUI 부분입니다. 이 함수는 Scene View 를 컨트롤 할수 있는 함수입니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
private void DrawObject(bool drag, Vector3 pos)
{
        grid = (Grid)target;
        Vector3 createPos = new Vector3(Mathf.Floor(pos.x / grid.width) * grid.width + grid.width / 2f,
         Mathf.Floor(pos.y / grid.height) * grid.height + grid.height / 2f, 0f);
        if (CheckCompareObject(createPos, drag))
        {
            GameObject createObject = (GameObject)PrefabUtility.InstantiatePrefab(grid.prefabsList[grid.ObjectIndex]);
            createObject.transform.parent = grid.parent;
            createObject.transform.position = createPos;
            Undo.RegisterCreatedObjectUndo(createObject, "create Object");
        }
}
cs

DrawObject 함수입니다. 실제로 타일 오브젝트를 생성하는곳 이라고 보시면 되겠습니다.

위치를 잡을때 위치입니다. 오브젝트는 Grid에 정중앙에 위치해야합니다.

우선 클릭한 좌표를 보정해줘야합니다. floor(posx/width)*width,floor(posy/height)*height를 하시면 그리드에 선과 선이 만나는 부분좌표가 나옵니다.

그후 (width/2),(height/2)를 더하면 정중앙이 나올것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void DestoryObject(Vector3 pos)
    {
        grid = (Grid)target;
        Vector3 createPos = new Vector3(Mathf.Floor(pos.x / grid.width) * grid.width + grid.width / 2f,
         Mathf.Floor(pos.y / grid.height) * grid.height + grid.height / 2f, 0f);// 클릭한 좌표
        if (CheckCompareObject(createPos, true)) // 삭제 함수
        {
        }
    }    
 
    bool CheckCompareObject(Vector3 newPos, bool destoryObject)
   {
// 자식 오브젝트를 전부 가져온다.
        Transform[] girdobjList = grid.parent.GetComponentsInChildren<Transform>();
        foreach (var obj in girdobjList)
        {
            if (obj.transform.position == newPos) // 똑같은 위치에 있는 오브젝트 삭제
            {
                if (destoryObject)
                {
                    Undo.DestroyObjectImmediate(obj.gameObject);
                }
                return false;
            }
        }
        return true;
    }
cs

오브젝트 삭제에 관련된 부분입니다. 클릭한 좌표 위치를찾은후 자식 오브젝트에서 같은 위치에 있는 오브젝트를 삭제 시켜주면 되겠습니다.

CheckCompareObject 함수 같은 경우에는 매개변수로 오브젝트를 삭제할것인지 결정하게 했습니다. 삭제하지 않고 체크만 하게도 만들었습니다.

이렇게만 넣어도 그리기와 삭제가 작동할것입니다. 이 다음에는 그리기 오브젝트 선택과 undo에 관련된 설명을 하도록 하겠습니다.

'프로그래밍 > 유니티' 카테고리의 다른 글

[unity] Unity Ads 넣는 방법  (0) 2020.04.02
[Unity3D] Script Templates  (0) 2020.03.19
[Unity] Custom Editor Undo  (0) 2020.03.14
[Unity] DrawGizmos  (0) 2020.03.13
[Unity] Scene view -> mousePosition 클릭한 위치 알아내기  (0) 2020.03.12
Comments