공부/유니티 디펜스 게임 만들기

맵 생성

원클릭쓰리버그 2022. 4. 3. 15:18
728x90

맵 생성 중 잘 못 설계했다는 점을 깨달음.

 

천천히 다시 코드를 리마인드하며 맵 생성을 설계.

 

우선 맵의 각 꼭지점을 선언하였음.  (맵 전체 직사각형에서의 모서리)

 

using System.Collections.Generic;
using UnityEngine;

public class _Grid : MonoBehaviour
{
    enum Vertex
    {
        LEFT_DOWN,
        LEFT_UP,
        RIGHT_DOWN,
        RIGHT_UP,
        CENTER,
        MAX
    }

    public LayerMask unwalkableMask;

    Node[,] grid;

    Vector3[] vertices;
    Vector2 gridSize;
    float grid_Width;
    float grid_Height;

    float nodeRadius;              //노드 반지름
    float nodeDiameter;            //노드 지름
    int gridXCount, gridYCount;   //Grid X축 Node 갯수, Grid Y축 Node 갯수
    // 맵의 꼭지점을 위치를 받아 Grid의 갯수를 확정시킨다.
    //전체 Node 크기값
    public int MaxSize { get => gridXCount * gridYCount; }


    private void Start()
    {
        nodeRadius = 1f;
        nodeDiameter = nodeRadius * 2f;

        Set_Vertex();

        grid_Width = Mathf.Abs(vertices[(int)Vertex.LEFT_DOWN].x - vertices[(int)Vertex.RIGHT_DOWN].x );
        grid_Height = Mathf.Abs(vertices[(int)Vertex.LEFT_DOWN].z - vertices[(int)Vertex.LEFT_UP].z );
        gridSize = new Vector2(grid_Width, grid_Height);

        gridXCount = Mathf.RoundToInt(gridSize.x / nodeDiameter);
        gridYCount = Mathf.RoundToInt(gridSize.y / nodeDiameter);

        CreateGrid();
    }
    /// <summary>
    /// set Ground Grid Vertex point
    /// </summary>
    void Set_Vertex()
    {
        vertices = new Vector3[(int)Vertex.MAX];

        vertices[(int)Vertex.LEFT_DOWN] = new Vector3(-50 - nodeRadius, 0, -100 - nodeRadius);
        vertices[(int)Vertex.LEFT_UP] = new Vector3(-50 - nodeRadius, 0, 100 + nodeRadius);
        vertices[(int)Vertex.RIGHT_UP] = new Vector3(50 + nodeRadius, 0, 100 + nodeRadius);
        vertices[(int)Vertex.RIGHT_DOWN] = new Vector3(50 + nodeRadius, 0, -100 - nodeRadius);
        vertices[(int)Vertex.CENTER] = new Vector3(0, 0, 0);
        transform.position = vertices[(int)Vertex.CENTER];
    }

    public List<Node> GetNearByNode(Node currentNode)
    {
        List<Node> NearByNodes = new List<Node>();

        // 해당되는 노드의 붙어있는 노드를 체크하여 List에 담는다.
        for (int x = -1; x <= 1; x++)
        {
            for (int y = -1; y <= 1; y++)
            {
                // 본인 자신이면 넘어간다.
                if (x == 0 && y == 0)
                    continue;

                int check_X = currentNode.gridX + x;
                int check_Y = currentNode.gridY + y;
                // 범위내 주변노드가 맞다면 List에 저장한다.
                if ((0 <= check_X && check_X < gridXCount) &&
                    (0 <= check_Y && check_Y < gridYCount))
                    NearByNodes.Add(grid[check_X, check_Y]);
            }
        }
        return NearByNodes;
    }

    /// <summary>
    /// Creating Node Function
    /// </summary>
    private void CreateGrid()
    {
        grid = new Node[gridXCount, gridYCount];
        // 실질적 꼭지점의 중간 지점이어야 한다.
        Vector3 worldBottomLeft =transform.position - new Vector3((gridSize.x * 0.5f), 0, (gridSize.y * 0.5f));
        for (int x = 0; x < gridXCount; x++)
        {
            for (int y = 0; y < gridYCount; y++)
            {
                Vector3 worldPosition = worldBottomLeft + new Vector3((x * nodeDiameter + nodeRadius), 0, (y * nodeDiameter + nodeRadius));
                bool walkable = !(Physics.CheckSphere(worldPosition, nodeRadius, unwalkableMask));

                grid[x, y] = new Node(walkable, worldPosition, x, y);
            }
        }

    }

    public Node GetNodeFromWorldPosition(Vector3 WP)
    {
        float percen_X = (WP.x + gridSize.x * 0.5f) / gridSize.x;
        float percen_Y = (WP.z + gridSize.y * 0.5f) / gridSize.y;

        Debug.Log($"percet_X : {percen_X} , percent_Y : {percen_Y}");

        percen_X = Mathf.Clamp01(percen_X);
        percen_Y = Mathf.Clamp01(percen_Y);

        int x = Mathf.RoundToInt((gridXCount - 1) * percen_X);
        int y = Mathf.RoundToInt((gridYCount - 1) * percen_Y);

        return grid[x, y];
    }

    private void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position, new Vector3(gridSize.x, 1f, gridSize.y));

        if (grid != null)
        {
            foreach (var node in grid)
            {
                Gizmos.color = Color.white;

                Gizmos.DrawCube(node.worldPosition, new Vector3(nodeDiameter, 1, nodeDiameter));
            }
        }
        Gizmos.color = Color.black;
        Gizmos.DrawWireCube(transform.position, new Vector3(gridSize.x, 1f, gridSize.y));
    }

}

 

예전 코드에서 Gizmos에서 transform.position에서 그릴 경우 좌표 (0,0)에서 시작하게 됨. 하지만 Grid 생성은 0,0을 중심으로 정하지 않아 실제로 확인되는 Gizmos와 실제로 Seeker이 읽는 Node가 달랐음. 그걸 고려하지 않아 맵 생성을 엉뚱한 방향에 생성하였음. 

 

이번에는 이러한 오류를 방지하기 위해 Node의 크기와 Plane의 크기를 먼저 비교하고, (0,0)을 기준으로 맵을 생성하였음.

 

Plane의 실제 rect 크기를 확인하는 코드

public class Test : MonoBehaviour
{
    
    private void Start()
    {
        Vector3 rect = transform.GetComponent<MeshCollider>().bounds.size;    
        Debug.Log(rect);
    }
}

실제의 Object에 붙어있는 Collider의 정보를 받아와 크기를 측정한 결과 

 

Vector3(10,0,10)이 나옴. 그러므로 Node의 반지름을 0.5f로 잡고 지름을 1f로 한다면, Plane 1개에 Node 10개가 있다는 결론이 나왔음. 

 

Node가 너무 많이 생성한다는 생각에 Node의 지름을 2f 로 잡고 생성하였음

 

 nodeRadius = 1f;
        nodeDiameter = nodeRadius * 2f;

 

위의 맵을 (0,0)을 기준으로 잡고 생성하였으며, 

 

보는 거와 같이 필드와 맞춰주었다. 

1개의 Plane에 노드 5개가 들어가 있음을 볼 수 있음.

결과적으로 가로에 총 50개의 노드, 세로에 총 100개의 노드가 생성되었음.

 

고민 결과, 가로에 총 10개의 타워, 세로 20개 타워로 결정하였음. 후에 노드의 크기를 반지름 2.5에 지름 5로 변경해야함.

 

또한, 다음에 작업할 타워 짖기 UI에 대한 기획을 고민.

  1. UI에서 건물 짖기를 클릭
  2. 세부 타워 항목에서 타워를 선택
  3. 카메라 기준 중앙에 반 투명 상태 선택한 타워 UI가 나옴.
    • 지을 수 있는 곳이면 초록 반투명
    • 지을 수 없는 경우 빨간 반투명
  4. 클릭 시 확정, 바로 맵에 오브젝트에 생성.

'공부 > 유니티 디펜스 게임 만들기' 카테고리의 다른 글

Ground  (0) 2022.03.12
A* 알고리즘 with Unity 03  (0) 2022.01.23
A* 알고리즘 with Unity 02  (0) 2022.01.23
A* 알고리즘 with Unity 01  (0) 2022.01.22
2022-01-15  (0) 2022.01.15