Unity

[던전크롤링] 맵 툴 만들기

wny0320 2024. 3. 14. 23:16

우선 퀄리티를 로우 폴리곤이나 하이퀄리티보다 심플정도가 나을거라고 생각하여 심플로 가기로 했다.

(로우폴리곤보다는 좋은 그래픽이지만 엄청 좋진 않은 정도)

 

그래서 환경(던전 맵) 에셋을 정하였다

https://assetstore.unity.com/packages/3d/environments/dungeons/simple-modular-dungeon-259641

 

Simple Modular Dungeon | 3D 던젼 | Unity Asset Store

Elevate your workflow with the Simple Modular Dungeon asset from DanProps. Find this & other 던젼 options on the Unity Asset Store.

assetstore.unity.com

 

비교적 최신에 나왔으면서 평은 몇개 없더라도 좋았으며 선호도 300개가 있는 에셋이다.(2024.03.14 기준)

 

에셋을 받아보니 지형들이 다 프리팹화 되어있으며 크기도 비슷하여 맵툴을 만들면 생성, 유지보수가 쉽겠다는 생각을 하였다.

그런 짓은 하지 말아야 했는데, 난 그 사실을 몰랐어

 

그래서 만들기 시작한 맵툴

 

아래는 MapManager.cs 코드이다.

더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Linq;

[InitializeOnLoad]
public class MapManager : MonoBehaviour
{
    static MapManager()
    {
        EditorApplication.update += Update;
    }
    enum tags
    {
        wall,
        floor,
        pillar,
        stair,
    }
    [SerializeField]
    private string tagName = "topo";
    [SerializeField]
    private Vector3 mapSize;
    [SerializeField]
    private Vector3 basis = new Vector3(4, 4, 4);
    [SerializeField]
    private Vector3 gizmosOffset = new Vector3(0, 2, 0);
    [SerializeField]
    private Vector3 topoOffset = new Vector3(-2, 0, -2);

    private void mapSizeGizmos()
    {
        int basisX = (int)basis.x;
        int basisY = (int)basis.y;
        int basisZ = (int)basis.z;

        int offsetX = (int)gizmosOffset.x;
        int offsetY = (int)gizmosOffset.y;
        int offsetZ = (int)gizmosOffset.z;

        for (int x = offsetX; x < mapSize.x * 4; x += basisX)
        {
            for (int y = offsetY; y < mapSize.y * 4; y += basisY)
            {
                for (int z = offsetZ; z < mapSize.z * 4; z += basisZ)
                {
                    Gizmos.DrawWireCube(new Vector3(x, y, z), basis);
                }
            }
        }
    }
    private static void topographyManage(MapManager _map)
    {
        Selection.selectionChanged += () =>
        {
            List<string> tagList = Enum.GetNames(typeof(tags)).ToList();
            GameObject[] objList = Selection.gameObjects;
            foreach (GameObject targetObj in objList)
            {
                string targetTag = targetObj.gameObject.tag;
                if (tagList.Contains(targetTag) == true)
                {
                    Vector3 offset = Vector3.zero;
                    float angle = targetObj.transform.rotation.eulerAngles.y;
                    if (targetTag == tags.wall.ToString())
                    {
                        if ((int)(angle / 90) % 2 == 0)
                            offset = new Vector3(_map.topoOffset.x, 0, 0);
                        else
                            offset = new Vector3(0, 0, _map.topoOffset.z);
                    }
                    if (targetTag == tags.pillar.ToString())
                    {
                        offset = _map.topoOffset;
                    }
                    else
                    {
                        offset = -_map.topoOffset;
                    }
                    Vector3 targetPos = (targetObj.transform.position + offset) / 4;
                    if (targetPos.x > _map.mapSize.x || targetPos.y > _map.mapSize.y || targetPos.z > _map.mapSize.z
                        || targetPos.x < 0 || targetPos.y < 0 || targetPos.z < 0)
                        targetObj.SetActive(false);
                    else
                        targetObj.SetActive(true);
                }
            }
        };
    }
    private static void topographyMove(MapManager _map)
    {
        Vector3 dir = Vector3.zero;
        if (Input.GetKeyDown(KeyCode.I))
        {
            dir = Vector3.forward;
        }
        if (Input.GetKeyDown(KeyCode.J))
        {
            dir = Vector3.left;
        }
        if (Input.GetKeyDown(KeyCode.K))
        {
            dir = Vector3.back;
        }
        if (Input.GetKeyDown(KeyCode.L))
        {
            dir = Vector3.right;
        }
        if (Input.GetKeyDown(KeyCode.U))
        {
            dir = Vector3.down;
        }
        if (Input.GetKeyDown(KeyCode.O))
        {
            dir = Vector3.up;
        }
        if (dir != Vector3.zero)
        {
            GameObject[] targetList = Selection.gameObjects;
            foreach (GameObject go in targetList)
            {
                go.transform.position += new Vector3(dir.x * _map.basis.x, dir.y * _map.basis.y, dir.z * _map.basis.z);
            }
        }
    }
    private void OnDrawGizmos()
    {
        mapSizeGizmos();
    }
    static void Update()
    {
        MapManager mapManager = FindObjectOfType<MapManager>();
        if (mapManager == null)
        {
            GameObject go = new GameObject();
            mapManager = go.AddComponent<MapManager>();
            go.name = typeof(MapManager).Name;
        }
        topographyManage(mapManager);
        topographyMove(mapManager);
    }
}

 

처음에는 씬 화면에 그냥 기즈모 적용시켜서 하면 되는 간단한 작업인줄 알았는데..

 

기즈모 이후에 기본 단위별로 수치를 입력해서 배치하는 것이 마음에 안들어서 찾아봤다.

 

키를 입력하거나 씬에서 조정해서 움직일 수 있는 코드도 있는것을 확인한 후 다시 재작업에 들어가려고 한다.

 

키를 저기서 입력하는것은 작동하지 않을 뿐더라 할 이유도 없는 것이 유니티의 스크립트는 실행을 위해 만들어진 런타임 스크립트다.

 

나처럼 유니티 에디터 씬에서 작동하는 것을 만들기 위해서는 커스텀 에디터쪽을 찾아서 적용해야한다고 하더라..

 

이와 관련된 내용은 해당 블로그에서 양질의 정보를 많이 얻어 소개하고자 한다.

https://blog.naver.com/hammerimpact

 

HAMMER_IMPACT : 네이버 블로그

게임 프로그래머. 주로 번역글과 공부글을 올립니다.

blog.naver.com

 

해머 임팩트님의 유니티 에디터 확장 입문이 예전 자료이긴 하지만 전혀 지식이 없고 자료가 부족해서 매우 큰 도움이 되었다.

 

내가 구현해야하는 내용은 에디터 윈도우와 핸들러, 이벤트 콜백, 커스텀 유아이, 에디터 지유아이 쪽 내용이랑 관계가 있음을 알았다.

 

안그래도 유니티 닥스 열심히 찾으면서 구현하고 있었는데 그래도 기능쪽인 측면은 핸들러쪽만 구현해서 그냥 스크립트 파일이 아닌 에디터로 넘겨주면 끝날 것 같다. 

 

다음엔 구현이 완료되면 글을 쓰러 올 것 같다.