生活随笔
收集整理的這篇文章主要介紹了
从零开始做一个SLG游戏(一):六边形网格
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文的主要工作是六邊形網格的繪制。
?
如圖所示。六邊形有6個方向,6個頂點,同時定義中心點到邊的最短距離為內徑innerRadius,定義中心點到頂點的距離為外徑outerRadius。
六邊形可以拆分為6個等邊三角形,所以很容易得出:
?
定義游戲中六邊形的邊長(即外徑)為10.
手游賬號買號用一個靜態類以及一個枚舉將這些定義下來:
using UnityEngine;public static class HexMetrics{? ?? ???/// <summary>? ?? ???/// 外徑,中心到頂點距離? ?? ???/// </summary>? ?? ???public const float outerRadius = 10f;? ?? ???/// <summary>? ?? ???/// 內徑,中心到邊距離,0.866025404為二分之根號三的近似值? ?? ???/// </summary>? ?? ???public const float innerRadius = outerRadius * 0.866025404f;? ?? ???? ?? ???/// <summary>? ?? ???/// 六邊形的六個頂點坐標? ?? ???/// </summary>? ?? ???public static readonly Vector3[] corners = {? ?? ?? ?? ?? ? new Vector3(0f, 0f, outerRadius),? ?? ?? ?? ?? ? new Vector3(innerRadius,0f,0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(innerRadius,0f,-0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(0f,0f,-outerRadius),? ?? ?? ?? ?? ? new Vector3(-innerRadius,0f,-0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(-innerRadius,0f,0.5f*outerRadius)? ?? ???};}/// <summary>/// 六邊形的方向///? ?? ?? ?? ?? ? NW /\ NE///? ?? ?? ?? ?? ? W |??|E///? ?? ?? ?? ?? ? SW \/ SE/// </summary>public enum HexDirection{? ?? ???NE,? ?? ???E,? ?? ???SE,? ?? ???SW,? ?? ???W,? ?? ???NW,}
復制代碼
之后開始寫關于圖片繪制的代碼:
將六邊形分解為6個等邊三角形,三角形的三個頂點分別為六邊形中心點,以及六邊形一條邊的兩個頂點:
即HexMetrics.corners和HexMetrics.corners[i+1]
因為第六條邊的時候,i=5,i+1=6,corners[6]不存在,所以在定義里加一個coners[6],和coners[0]相等:
?
public static readonly Vector3[] corners = {? ?? ?? ?? ?? ? new Vector3(0f, 0f, outerRadius),? ?? ?? ?? ?? ? new Vector3(innerRadius,0f,0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(innerRadius,0f,-0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(0f,0f,-outerRadius),? ?? ?? ?? ?? ? new Vector3(-innerRadius,0f,-0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(-innerRadius,0f,0.5f*outerRadius),? ?? ?? ?? ?? ? new Vector3(0f,0f,outerRadius),? ?? ???};
復制代碼
所以繪制三角形的時候,代碼可以寫成這樣:
? ?? ???
/// <summary>? ?? ???/// 繪制地形? ?? ???/// </summary>? ?? ???public void Draw()? ?? ???{? ?? ?? ?? ?? ? Clear();? ?? ?? ?? ?? ? Vector3 center = Vector3.zero;? ?? ?? ?? ?? ? for (HexDirection dir = HexDirection.NE; dir <= HexDirection.NW; dir++)? ?? ?? ?? ?? ? {? ?? ?? ?? ?? ?? ?? ?? ?AddTriangle(center,? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???HexMetrics.corners[(int)dir],? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???HexMetrics.corners[(int)dir + 1]);? ?? ?? ?? ?? ? }? ?? ?? ?? ?? ? UpdateMesh();? ?? ???}
復制代碼
然后貼上全部代碼:
?
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]public class HexCell : MonoBehaviour {? ?? ???private Mesh mesh;? ?? ???private List<Vector3> vertices;? ?? ???private List<int> triangles;? ?? ???private void Awake()? ?? ???{? ?? ?? ?? ?? ? GetComponent<MeshFilter>().mesh = mesh = GetComponent<MeshCollider>().sharedMesh = new Mesh();? ?? ?? ?? ?? ? GetComponent<MeshCollider>().convex = true;? ?? ?? ?? ?? ? mesh.name = "Hex Cell";? ?? ?? ?? ?? ? vertices = new List<Vector3>();? ?? ?? ?? ?? ? triangles = new List<int>();? ?? ?? ?? ?? ? Draw();? ?? ???}? ?? ???// Use this for initialization? ?? ???void Start () {? ?? ?? ?? ?? ?? ?? ???}? ?? ???? ?? ???// Update is called once per frame? ?? ???void Update () {? ?? ?? ?? ?? ?? ?? ???}? ?? ???/// <summary>? ?? ???/// 繪制地形? ?? ???/// </summary>? ?? ???public void Draw()? ?? ???{? ?? ?? ?? ?? ? Clear();? ?? ?? ?? ?? ? Vector3 center = Vector3.zero;? ?? ?? ?? ?? ? for (HexDirection dir = HexDirection.NE; dir <= HexDirection.NW; dir++)? ?? ?? ?? ?? ? {? ?? ?? ?? ?? ?? ?? ?? ?AddTriangle(center,? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???HexMetrics.corners[(int)dir],? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???HexMetrics.corners[(int)dir + 1]);? ?? ?? ?? ?? ? }? ?? ?? ?? ?? ? UpdateMesh();? ?? ???}? ?? ???/// <summary>? ?? ???/// 清空mesh數據? ?? ???/// </summary>? ?? ???private void Clear()? ?? ???{? ?? ?? ?? ?? ? mesh.Clear();? ?? ?? ?? ?? ? vertices.Clear();? ?? ?? ?? ?? ? triangles.Clear();? ?? ???}? ?? ???/// <summary>? ?? ???/// 繪制mesh數據? ?? ???/// </summary>? ?? ???private void UpdateMesh()? ?? ???{? ?? ?? ?? ?? ? mesh.vertices = vertices.ToArray();? ?? ?? ?? ?? ? mesh.triangles = triangles.ToArray();? ?? ?? ?? ?? ? mesh.RecalculateNormals();? ?? ?? ?? ?? ? mesh.RecalculateBounds();? ?? ???}? ?? ???/// <summary>? ?? ???/// 添加三角形。? ?? ???/// </summary>? ?? ???/// <param name="v1"></param>? ?? ???/// <param name="v2"></param>? ?? ???/// <param name="v3"></param>? ?? ???private void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3)? ?? ???{? ?? ?? ?? ?? ? int count = triangles.Count;? ?? ?? ?? ?? ? vertices.Add(v1);? ?? ?? ?? ?? ? triangles.Add(count++);? ?? ?? ?? ?? ? vertices.Add(v2);? ?? ?? ?? ?? ? triangles.Add(count++);? ?? ?? ?? ?? ? vertices.Add(v3);? ?? ?? ?? ?? ? triangles.Add(count++);? ?? ???}}
復制代碼
在unity中新建一個空的物體,掛上這個腳本,然后隨便扔一個材質上去,運行就會出現如下圖片:
?
接下來就是構建地圖網格:
?
如圖,仔細觀察我們就可以我們可以發現:
1.同一行的相鄰六邊形的間距為2個內徑的距離
2.兩列六邊形,在縱坐標上相差1.5個外徑的距離
3.列數為奇數的六邊形在橫坐標上,會向右偏移1個內徑的距離。
所以我們可以通過如下方式將隊列上的坐標(x,y)轉換為空間上的坐標:
?
private Vector3 GetPos(int x, int y)? ?? ???{? ?? ?? ?? ?? ? float posX = x;? ?? ?? ?? ?? ? float posY = y;? ?? ?? ?? ?? ? if ((y & 1) != 0)? ?? ?? ?? ?? ? {? ?? ?? ?? ?? ?? ?? ?? ?posX += 0.5f;? ?? ?? ?? ?? ? }? ?? ?? ?? ?? ? Vector3 pos = new Vector3(2f * posX * HexMetrics.innerRadius, 0f, 1.5f * posY * HexMetrics.outerRadius);? ?? ?? ?? ?? ? return pos;? ?? ???}
復制代碼
? ?? ???
為了便于區分,再將網格的顏色變一下:
?
cell.GetComponent<MeshRenderer>().material.color = new Color(posX / width, (posX + posY) / (height + width), posY / height);
復制代碼
一個六邊形的網格地圖的雛形就做好了,運行一下,我們就可以得到下面圖片:
?
總結
以上是生活随笔為你收集整理的从零开始做一个SLG游戏(一):六边形网格的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。