반응형
유니티 버전 : 2020.3.25f1
작업환경 : Mac (Monterey 12.3.1)
Youtube 주소 : https://www.youtube.com/watch?v=EPaSmQ2vtek
Game Dev Guide라는 유튜브 채널인데 좋은 정보가 많은 것 같습니다.
Hex모양을 만드는 스크립트와 그리드 스크립트를 작성합니다.
HexRendere.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public struct Face
{
public List<Vector3> vertices { get; private set; }
public List<int> triangles { get; private set; }
public List<Vector2> uvs { get; private set; }
public Face(List<Vector3> vertices, List<int> triangles, List<Vector2> uvs)
{
this.vertices = vertices;
this.triangles = triangles;
this.uvs = uvs;
}
}
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class HexRenderer : MonoBehaviour
{
Mesh m_mesh;
MeshFilter m_meshFilter;
MeshRenderer m_meshRenderer;
public Material material;
public float innerSize;
public float outerSize = 1;
public float height;
public bool isFlatTopped;
internal void SetMaterial(Material material)
{
m_meshRenderer.material = material;
}
List<Face> m_faces;
void Awake()
{
m_meshFilter = GetComponent<MeshFilter>();
m_meshRenderer = GetComponent<MeshRenderer>();
m_mesh = new Mesh();
m_mesh.name = "Hex";
m_meshFilter.mesh = m_mesh;
m_meshRenderer.material = material;
}
private void OnEnable()
{
DrawMesh();
}
private void OnValidate()
{
if (Application.isPlaying)
{
DrawMesh();
}
}
public void DrawMesh()
{
DrawFaces();
CombineFaces();
}
void DrawFaces()
{
m_faces = new List<Face>();
for(int point = 0; point < 6; point++)
{
m_faces.Add(CreateFace(innerSize, outerSize, height / 2f, height / 2f, point));
}
for(int point = 0; point < 6; point++)
{
m_faces.Add(CreateFace(innerSize, outerSize, -height / 2f, -height / 2f, point, true));
}
for (int point = 0; point < 6; point++)
{
m_faces.Add(CreateFace(outerSize, outerSize, height / 2f, -height / 2f, point, true));
}
for (int point = 0; point < 6; point++)
{
m_faces.Add(CreateFace(innerSize, innerSize, height / 2f, -height / 2f, point, false));
}
}
void CombineFaces()
{
List<Vector3> vertices = new List<Vector3>();
List<int> tris = new List<int>();
List<Vector2> uvs = new List<Vector2>();
for(int i = 0; i < m_faces.Count; i++)
{
vertices.AddRange(m_faces[i].vertices);
uvs.AddRange(m_faces[i].uvs);
int offset = (4 * i);
foreach(int triangle in m_faces[i].triangles)
{
tris.Add(triangle + offset);
}
}
if (m_mesh != null)
{
m_mesh.vertices = vertices.ToArray();
m_mesh.triangles = tris.ToArray();
m_mesh.uv = uvs.ToArray();
m_mesh.RecalculateNormals();
}
}
protected Vector3 GetPoint(float size, float height, int index)
{
float angle_deg = isFlatTopped ? 60 * index : 60*index-30;
float angle_rad = Mathf.PI / 180f * angle_deg;
return new Vector3((size * Mathf.Cos(angle_rad)), height, size * Mathf.Sin(angle_rad));
}
Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false)
{
Vector3 pointA = GetPoint(innerRad, heightB, point);
Vector3 pointB = GetPoint(innerRad, heightB, (point < 5) ? point + 1 : 0);
Vector3 pointC = GetPoint(outerRad, heightA, (point < 5) ? point + 1 : 0);
Vector3 pointD = GetPoint(outerRad, heightA, point);
List<Vector3> vertices = new List<Vector3>() { pointA, pointB, pointC, pointD };
List<int> triangles = new List<int>() { 0, 1, 2, 2, 3, 0 };
List<Vector2> uvs = new List<Vector2>() { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) };
if (reverse)
{
vertices.Reverse();
}
return new Face(vertices, triangles, uvs);
}
}
grid 작업을 위한 스크립트 입니다.
HexGridLayout.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HexGridLayout : MonoBehaviour
{
[Header("Grid Settings")]
public Vector2Int gridSize;
[Header("Tile Settings")]
public float outerSize = 1f;
public float innerSize = 0f;
public float height = 1f;
public bool isFlatTopped;
public Material material;
private void OnEnable()
{
LayoutGrid();
}
private void OnValidate()
{
if (Application.isPlaying)
{
LayoutGrid();
}
}
void LayoutGrid()
{
for(int y = 0; y < gridSize.y; y++)
{
for(int x = 0; x < gridSize.x; x++)
{
GameObject tile;
if (transform.childCount < gridSize.x * gridSize.y)
tile = new GameObject($"Hex {x},{y}", typeof(HexRenderer));
else tile = transform.Find($"Hex {x},{y}").gameObject;
tile.transform.position = GetPositionForHexFromCoordinate(new Vector2Int(x, y));
HexRenderer hexRenderer = tile.GetComponent<HexRenderer>();
hexRenderer.isFlatTopped = isFlatTopped;
hexRenderer.outerSize = outerSize;
hexRenderer.innerSize = innerSize;
hexRenderer.height = height;
hexRenderer.SetMaterial(material);
hexRenderer.DrawMesh();
tile.transform.SetParent(transform, true);
}
}
}
public Vector3 GetPositionForHexFromCoordinate(Vector2Int coordinate)
{
int column = coordinate.x;
int row = coordinate.y;
float width;
float height;
float xPosition;
float yPosition;
bool shouldOffset;
float horizontalDistance;
float verticalDistance;
float offset;
float size = outerSize;
if (!isFlatTopped)
{
shouldOffset = (row % 2) == 0;
width = Mathf.Sqrt(3f) * size;
height = 2f * size;
horizontalDistance = width;
verticalDistance = height * (3f / 4f);
offset = (shouldOffset) ? width / 2 : 0;
xPosition = (column * (horizontalDistance)) + offset;
yPosition = (row * verticalDistance);
}
else
{
shouldOffset = (column % 2) == 0;
width = 2f * size;
height = Mathf.Sqrt(3f) * size;
horizontalDistance = width * (3f / 4f);
verticalDistance = height;
offset = (shouldOffset) ? height / 2 : 0;
xPosition = (column * (horizontalDistance));
yPosition = (row * verticalDistance) - offset;
}
return new Vector3(xPosition, 0, -yPosition);
}
}
HexGrid.unitypackage
0.01MB
반응형
'유니티' 카테고리의 다른 글
PCG 기술을 사용한 유니티 RPG 게임 개발 - 1장 도전 문제? (0) | 2022.05.18 |
---|---|
Unity Mesh Renderer Size (0) | 2022.05.16 |
유니티 동영상 재생 + Youtube(유료 에셋) (0) | 2022.04.21 |
유니티 PlanarReflection (0) | 2022.04.20 |
유니티 Laser reflection 구현 (0) | 2022.04.19 |