通过PolygonCollider2D生成多边形网格面片
在编辑器状态下生成多边形网格面片
网格生成脚本
通过EidtorWindow创建预制体,预制体需要挂载MeshFilter和MeshRenderer
点击查看代码
using System; using System.Collections.Generic; using System.Linq; using UnityEngine; [RequireComponent(typeof(PolygonCollider2D))] public class CreatePolygonMesh : MonoBehaviour { [SerializeField] private PolygonCollider2D polygonCollider2D; [SerializeField] private MeshFilter meshFilter; public int PointsCount => polygonCollider2D.points.Length; public void Create_Mesh_For_PolygonCollider2D() { //获取多边形碰撞体的顶点 var vVertices = new Vector3[polygonCollider2D.points.Length]; for (var i = 0; i < polygonCollider2D.points.Length; i++) { var points = polygonCollider2D.points; vVertices[i] = new Vector3(points[i].x, points[i].y, 0); } DoCreatPolygonMesh(vVertices); } private void DoCreatPolygonMesh(Vector3[] vertices) { //新建一个空物体进行进行绘制自定义多边形 var tMesh = new Mesh(); var tTriangles = Calculate_Triangles_CutEar_Method(vertices); tMesh.vertices = vertices; tMesh.triangles = tTriangles.ToArray(); tMesh.RecalculateBounds(); tMesh.RecalculateNormals(); meshFilter.mesh = tMesh; } private List<int> Calculate_Triangles_CutEar_Method(Vector3[] vertices) { var vVertices = new List<Vector3>(); for (var i = 0; i < vertices.Length; i++) { vVertices.Add(new Vector3(vertices[i].x, vertices[i].y, i)); } var tTriangles = new List<int>(); var sn = 0; var layer = 0; while (vVertices.Count > 3 && layer < 1000) { var vPoints = vVertices.Select(t => (Vector2) t).ToList(); var sna = sn - 1; if (sna < 0) sna = vPoints.Count - 1; var snb = sn; var snc = sn + 1; if (snc >= vPoints.Count) snc = 0; var vTriangle = new List<Vector2> { vPoints[sna], vPoints[snb], vPoints[snc] }; var blHaveOtherPointInTriangle = vPoints.Where((_, i) => i != sna && i != snb && i != snc) .Any(t => Check_Point_InPolygon(t, vTriangle)); var blCutEar = false; if (blHaveOtherPointInTriangle == false) { var vCenter = (vTriangle[0] + vTriangle[1] + vTriangle[2]) / 3; if (Check_Point_InPolygon(vCenter, vPoints)) { var ta = (int) vVertices[sna].z; var tb = (int) vVertices[snb].z; var tc = (int) vVertices[snc].z; tTriangles.Add(tc); tTriangles.Add(tb); tTriangles.Add(ta); vVertices.RemoveAt(snb); blCutEar = true; } } if (blCutEar == false) { sn++; } if (sn >= vVertices.Count) sn = 0; layer++; } if (vVertices.Count == 3) { var ta = (int) vVertices[0].z; var tb = (int) vVertices[1].z; var tc = (int) vVertices[2].z; tTriangles.Add(tc); tTriangles.Add(tb); tTriangles.Add(ta); } Debug.Log("tTriangles.Count : " + tTriangles.Count + " layer : " + layer); return tTriangles; } private bool Check_Point_InPolygon(Vector2 vCheck, IReadOnlyList<Vector2> vPoints) { //从检查点向右做线,若碰到两点之间的线段,则num_across++ var numAcross = 0; var count = 0; var i = 0; while (count < vPoints.Count) { var v1 = vPoints[i]; if (i == vPoints.Count - 1) i = -1; var v2 = vPoints[i + 1]; switch (Math.Abs(v1.y - v2.y) <= 0) { case false when Math.Abs(v1.y - vCheck.y) <= 0 && v1.x >= vCheck.x: case false when Math.Abs(v2.y - vCheck.y) <= 0 && v2.x >= vCheck.x: numAcross++; break; case false when Math.Abs(Mathf.Sign(v1.y - vCheck.y) - Mathf.Sign(v2.y - vCheck.y)) <= 0: break; case false: { var xLine = v1.x + (v2.x - v1.x) * (vCheck.y - v1.y) / (v2.y - v1.y); if (xLine >= vCheck.x) { numAcross++; } break; } } i++; count++; } return (numAcross % 2) switch { 1 => true, _ => false }; } }
编辑器下检测更改
通过EditorApplication.update每帧对比PolygonCollider2D顶点值的变化,实现在编辑器状态下动态生成多边形网格
点击查看代码
using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; [InitializeOnLoad] public class MapEditorTool { private static PolygonCollider2D _previousCollider; private static Vector2[] _previousPoints; static MapEditorTool() { EditorApplication.update += OnEditorUpdate; } private static void OnEditorUpdate() { var selectedObject = Selection.activeGameObject; if (selectedObject == null) return; var targetScript = selectedObject.GetComponent<CreatePolygonMesh>(); if (targetScript == null) return; var currentCollider = selectedObject.GetComponent<PolygonCollider2D>(); if (currentCollider == null) return; if (currentCollider != _previousCollider) { _previousCollider = currentCollider; _previousPoints = (Vector2[]) currentCollider.points.Clone(); } else { if (ComparePoints(currentCollider.points, _previousPoints)) return; _previousPoints = (Vector2[]) currentCollider.points.Clone(); targetScript.Create_Mesh_For_PolygonCollider2D(); } } private static bool ComparePoints(IReadOnlyCollection<Vector2> pointsA, IReadOnlyList<Vector2> pointsB) { if (pointsA.Count != pointsB.Count) return false; return !pointsA.Where((t, i) => t != pointsB[i]).Any(); } public static void ReSetSelectObj(GameObject select) { Selection.activeGameObject = select; SceneView.lastActiveSceneView.FrameSelected(); SceneView.lastActiveSceneView.in2DMode = true; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!