從零開始做一個SLG遊戲(三)
來自專欄 Unity開發日記
本文主要是使用mesh製作一些簡單的模型資源。
一般而言,模型的製作最好還是使用專業的軟體來做,但是製作一些簡單的模型,unity還是可以勝任的。
unity自帶的模型只有立方體,圓柱,球,膠囊,方塊等有限的幾個,所以稍微複雜一些的東西就不好做了,比如最常用到的圓錐,稜柱,稜台等,十分困難。
所以首先要做的是,將一些常用的基本模型,實現出來。
首先要做的是寫一個模型基類:
using System.Collections;using System.Collections.Generic;using UnityEngine;[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]public abstract class BasePoly : MonoBehaviour { Mesh mesh; private List<Vector3> vertices; private List<int> triangles; private List<Vector2> uvs; private float length = 100f; private void Awake() { mesh = GetComponent<MeshCollider>().sharedMesh = GetComponent<MeshFilter>().mesh = new Mesh(); mesh.name = "PolyMesh"; vertices = new List<Vector3>(); triangles = new List<int>(); uvs = new List<Vector2>(); } // Update is called once per frame void Update () { DrawMesh(); } private void DrawMesh() { Clear(); Draw(); UpdateMesh(); } protected void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3) { AddConer(v1); AddConer(v2); AddConer(v3); } protected void AddSquare(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4) { AddTriangle(v1, v3, v2); AddTriangle(v2, v3, v4); } private void AddConer(Vector3 point) { int count = vertices.Count; vertices.Add(point); triangles.Add(count); uvs.Add(new Vector2(point.x / (2 * length), point.z / (2 * length))); } private void UpdateMesh() { mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.uv = uvs.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); } private void Clear() { mesh.Clear(); vertices.Clear(); triangles.Clear(); uvs.Clear(); } public virtual void Draw() { }}
具體實現的原理,在上一篇文章里大部分都有講過。現在將之封裝了起來。
在子類中,重寫Draw()函數,調用下面兩個函數即可繪製各種想要的圖形。
AddTriangle(Vector3v1, Vector3 v2,Vector3 v3);AddSquare(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4);
首先實現一下正多邊形:
正多邊形其實和前面六邊形的製作方式類似,不過我們需要手動計算出正多邊形的各個頂點。
將正n邊形的各個頂點和中心點連線,可以得到n個等腰三角形,而等腰三角形頂角的大小為(360°/n)。
所以,如果知道一個頂點p的坐標,同時又知道原點坐標(0,0)的話,那下一個頂點p的坐標可以通過p圍繞原點旋轉(360°/n)的角度獲得。
那麼我們複習一下高中的空間幾何知識:
一個點圍繞原點逆時針旋轉θ角的時候,我們可以通過旋轉變換來獲得旋轉後的坐標。
旋轉變換的矩陣為:
具體用法為:
對於(x,y)進行旋轉變換後,得到的(x,y)有
x=x*cosθ-y*sinθ
y=x*sinθ+y*cosθ
θ為逆時針旋轉的角度。
所以寫一個函數來實現旋轉變換:
Vector3 RotationTranslate(Vector3 pos,float angle) { Vector3 Pos = pos; float[,] transRect = { { Mathf.Cos(angle),-Mathf.Sin(angle)}, { Mathf.Sin(angle),Mathf.Cos(angle)}, }; Pos.x = pos.x * transRect[0, 0] + pos.z * transRect[0, 1]; Pos.z = pos.x * transRect[1, 0] + pos.z * transRect[1, 1]; return Pos; }
angle為旋轉的角度。
正多邊形的各個點都有了,然後通過畫三角的方式,將正多邊形畫出來了。
代碼如下:
public class Polygon : BasePoly { public int edgeCount = 3; private float angle = 0f; private List<Vector3> coners = new List<Vector3>(); public override void Draw() { angle = 2f * Mathf.PI / count; Vector3 pos = new Vector3(1f, 0f, 0f); coners.Add(pos); for (int i = 0; i < count; i++) { pos = RotationTranslate(pos); coners.Add(pos); } for (int j = 0; j < count; j++) { AddTriangle(coners[j], Vector3.zero, coners[j + 1]); } coners.Clear(); } Vector3 RotationTranslate(Vector3 pos) { Vector3 Pos = pos; float[,] transRect = { { Mathf.Cos(angle),-Mathf.Sin(angle)}, { Mathf.Sin(angle),Mathf.Cos(angle)}, }; Pos.x = pos.x * transRect[0, 0] + pos.z * transRect[0, 1]; Pos.z = pos.x * transRect[1, 0] + pos.z * transRect[1, 1]; return Pos; }}
實現後,會發現一個問題,那就是每幀都要繪製一次,會非常消耗功能,所以我們需要加一個函數,用於判斷是否需要再繪製一遍:
using System.Collections;using System.Collections.Generic;using UnityEngine;[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]public abstract class BasePoly : MonoBehaviour {…… private void DrawMesh() { if (NeedDraw()) { Clear(); Draw(); UpdateMesh(); } } public virtual bool NeedDraw() { return true; }……}
然後再在子類中重寫NeedDraw()函數:
public class Polygon : BasePoly { public int edgeCount = 3; private int count = 0; private float angle = 0f; …… public override bool NeedDraw() { if (edgeCount == count) { return false; } else if (edgeCount < 3) { return false; } else { count = edgeCount; angle = 2f * Mathf.PI / count; return true; } } public override void Draw() { //angle = 2f * Mathf.PI / count; …… } ……}
其他圖形也可以通過類似的方法,一一繪製出來,並通過自己的賦值進行微調。
比較麻煩的一點是,這麼實現,需要先讓工程運行起來,繪製的圖形才能顯示出來。幸運的是,這並不影響搭建場景。
推薦閱讀: