PageRenderTime 26ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/Assets/MeshGenerator.cs

https://gitlab.com/Bezerra/rpg
C# | 394 lines | 314 code | 76 blank | 4 comment | 48 complexity | 4546b22ebada90ac3d2fc83067601756 MD5 | raw file
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. public class MeshGenerator : MonoBehaviour {
  5. public SquareGrid squareGrid;
  6. public MeshFilter walls;
  7. public MeshFilter cave;
  8. public bool is2D;
  9. List<Vector3> vertices;
  10. List<int> triangles;
  11. Dictionary<int,List<Triangle>> triangleDictionary = new Dictionary<int, List<Triangle>> ();
  12. List<List<int>> outlines = new List<List<int>> ();
  13. HashSet<int> checkedVertices = new HashSet<int>();
  14. public void GenerateMesh(int[,] map, float squareSize) {
  15. triangleDictionary.Clear ();
  16. outlines.Clear ();
  17. checkedVertices.Clear ();
  18. squareGrid = new SquareGrid(map, squareSize);
  19. vertices = new List<Vector3>();
  20. triangles = new List<int>();
  21. for (int x = 0; x < squareGrid.squares.GetLength(0); x ++) {
  22. for (int y = 0; y < squareGrid.squares.GetLength(1); y ++) {
  23. TriangulateSquare(squareGrid.squares[x,y]);
  24. }
  25. }
  26. Mesh mesh = new Mesh();
  27. cave.mesh = mesh;
  28. mesh.vertices = vertices.ToArray();
  29. mesh.triangles = triangles.ToArray();
  30. mesh.RecalculateNormals();
  31. int tileAmount = 10;
  32. Vector2[] uvs = new Vector2[vertices.Count];
  33. for (int i =0; i < vertices.Count; i ++) {
  34. float percentX = Mathf.InverseLerp(-map.GetLength(0)/2*squareSize,map.GetLength(0)/2*squareSize,vertices[i].x) * tileAmount;
  35. float percentY = Mathf.InverseLerp(-map.GetLength(0)/2*squareSize,map.GetLength(0)/2*squareSize,vertices[i].z) * tileAmount;
  36. uvs[i] = new Vector2(percentX,percentY);
  37. }
  38. mesh.uv = uvs;
  39. if (is2D) {
  40. Generate2DColliders();
  41. } else {
  42. CreateWallMesh ();
  43. }
  44. }
  45. void CreateWallMesh() {
  46. CalculateMeshOutlines ();
  47. List<Vector3> wallVertices = new List<Vector3> ();
  48. List<int> wallTriangles = new List<int> ();
  49. Mesh wallMesh = new Mesh ();
  50. float wallHeight = 5;
  51. foreach (List<int> outline in outlines) {
  52. for (int i = 0; i < outline.Count -1; i ++) {
  53. int startIndex = wallVertices.Count;
  54. wallVertices.Add(vertices[outline[i]]); // left
  55. wallVertices.Add(vertices[outline[i+1]]); // right
  56. wallVertices.Add(vertices[outline[i]] - Vector3.up * wallHeight); // bottom left
  57. wallVertices.Add(vertices[outline[i+1]] - Vector3.up * wallHeight); // bottom right
  58. wallTriangles.Add(startIndex + 0);
  59. wallTriangles.Add(startIndex + 2);
  60. wallTriangles.Add(startIndex + 3);
  61. wallTriangles.Add(startIndex + 3);
  62. wallTriangles.Add(startIndex + 1);
  63. wallTriangles.Add(startIndex + 0);
  64. }
  65. }
  66. wallMesh.vertices = wallVertices.ToArray ();
  67. wallMesh.triangles = wallTriangles.ToArray ();
  68. walls.mesh = wallMesh;
  69. MeshCollider wallCollider = walls.gameObject.AddComponent<MeshCollider> ();
  70. wallCollider.sharedMesh = wallMesh;
  71. }
  72. void Generate2DColliders() {
  73. EdgeCollider2D[] currentColliders = gameObject.GetComponents<EdgeCollider2D> ();
  74. for (int i = 0; i < currentColliders.Length; i++) {
  75. Destroy(currentColliders[i]);
  76. }
  77. CalculateMeshOutlines ();
  78. foreach (List<int> outline in outlines) {
  79. EdgeCollider2D edgeCollider = gameObject.AddComponent<EdgeCollider2D>();
  80. Vector2[] edgePoints = new Vector2[outline.Count];
  81. for (int i =0; i < outline.Count; i ++) {
  82. edgePoints[i] = new Vector2(vertices[outline[i]].x,vertices[outline[i]].z);
  83. }
  84. edgeCollider.points = edgePoints;
  85. }
  86. }
  87. void TriangulateSquare(Square square) {
  88. switch (square.configuration) {
  89. case 0:
  90. break;
  91. // 1 points:
  92. case 1:
  93. MeshFromPoints(square.centreLeft, square.centreBottom, square.bottomLeft);
  94. break;
  95. case 2:
  96. MeshFromPoints(square.bottomRight, square.centreBottom, square.centreRight);
  97. break;
  98. case 4:
  99. MeshFromPoints(square.topRight, square.centreRight, square.centreTop);
  100. break;
  101. case 8:
  102. MeshFromPoints(square.topLeft, square.centreTop, square.centreLeft);
  103. break;
  104. // 2 points:
  105. case 3:
  106. MeshFromPoints(square.centreRight, square.bottomRight, square.bottomLeft, square.centreLeft);
  107. break;
  108. case 6:
  109. MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.centreBottom);
  110. break;
  111. case 9:
  112. MeshFromPoints(square.topLeft, square.centreTop, square.centreBottom, square.bottomLeft);
  113. break;
  114. case 12:
  115. MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreLeft);
  116. break;
  117. case 5:
  118. MeshFromPoints(square.centreTop, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft, square.centreLeft);
  119. break;
  120. case 10:
  121. MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.centreBottom, square.centreLeft);
  122. break;
  123. // 3 point:
  124. case 7:
  125. MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.bottomLeft, square.centreLeft);
  126. break;
  127. case 11:
  128. MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.bottomLeft);
  129. break;
  130. case 13:
  131. MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft);
  132. break;
  133. case 14:
  134. MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.centreBottom, square.centreLeft);
  135. break;
  136. // 4 point:
  137. case 15:
  138. MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.bottomLeft);
  139. checkedVertices.Add(square.topLeft.vertexIndex);
  140. checkedVertices.Add(square.topRight.vertexIndex);
  141. checkedVertices.Add(square.bottomRight.vertexIndex);
  142. checkedVertices.Add(square.bottomLeft.vertexIndex);
  143. break;
  144. }
  145. }
  146. void MeshFromPoints(params Node[] points) {
  147. AssignVertices(points);
  148. if (points.Length >= 3)
  149. CreateTriangle(points[0], points[1], points[2]);
  150. if (points.Length >= 4)
  151. CreateTriangle(points[0], points[2], points[3]);
  152. if (points.Length >= 5)
  153. CreateTriangle(points[0], points[3], points[4]);
  154. if (points.Length >= 6)
  155. CreateTriangle(points[0], points[4], points[5]);
  156. }
  157. void AssignVertices(Node[] points) {
  158. for (int i = 0; i < points.Length; i ++) {
  159. if (points[i].vertexIndex == -1) {
  160. points[i].vertexIndex = vertices.Count;
  161. vertices.Add(points[i].position);
  162. }
  163. }
  164. }
  165. void CreateTriangle(Node a, Node b, Node c) {
  166. triangles.Add(a.vertexIndex);
  167. triangles.Add(b.vertexIndex);
  168. triangles.Add(c.vertexIndex);
  169. Triangle triangle = new Triangle (a.vertexIndex, b.vertexIndex, c.vertexIndex);
  170. AddTriangleToDictionary (triangle.vertexIndexA, triangle);
  171. AddTriangleToDictionary (triangle.vertexIndexB, triangle);
  172. AddTriangleToDictionary (triangle.vertexIndexC, triangle);
  173. }
  174. void AddTriangleToDictionary(int vertexIndexKey, Triangle triangle) {
  175. if (triangleDictionary.ContainsKey (vertexIndexKey)) {
  176. triangleDictionary [vertexIndexKey].Add (triangle);
  177. } else {
  178. List<Triangle> triangleList = new List<Triangle>();
  179. triangleList.Add(triangle);
  180. triangleDictionary.Add(vertexIndexKey, triangleList);
  181. }
  182. }
  183. void CalculateMeshOutlines() {
  184. for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex ++) {
  185. if (!checkedVertices.Contains(vertexIndex)) {
  186. int newOutlineVertex = GetConnectedOutlineVertex(vertexIndex);
  187. if (newOutlineVertex != -1) {
  188. checkedVertices.Add(vertexIndex);
  189. List<int> newOutline = new List<int>();
  190. newOutline.Add(vertexIndex);
  191. outlines.Add(newOutline);
  192. FollowOutline(newOutlineVertex, outlines.Count-1);
  193. outlines[outlines.Count-1].Add(vertexIndex);
  194. }
  195. }
  196. }
  197. }
  198. void FollowOutline(int vertexIndex, int outlineIndex) {
  199. outlines [outlineIndex].Add (vertexIndex);
  200. checkedVertices.Add (vertexIndex);
  201. int nextVertexIndex = GetConnectedOutlineVertex (vertexIndex);
  202. if (nextVertexIndex != -1) {
  203. FollowOutline(nextVertexIndex, outlineIndex);
  204. }
  205. }
  206. int GetConnectedOutlineVertex(int vertexIndex) {
  207. List<Triangle> trianglesContainingVertex = triangleDictionary [vertexIndex];
  208. for (int i = 0; i < trianglesContainingVertex.Count; i ++) {
  209. Triangle triangle = trianglesContainingVertex[i];
  210. for (int j = 0; j < 3; j ++) {
  211. int vertexB = triangle[j];
  212. if (vertexB != vertexIndex && !checkedVertices.Contains(vertexB)) {
  213. if (IsOutlineEdge(vertexIndex, vertexB)) {
  214. return vertexB;
  215. }
  216. }
  217. }
  218. }
  219. return -1;
  220. }
  221. bool IsOutlineEdge(int vertexA, int vertexB) {
  222. List<Triangle> trianglesContainingVertexA = triangleDictionary [vertexA];
  223. int sharedTriangleCount = 0;
  224. for (int i = 0; i < trianglesContainingVertexA.Count; i ++) {
  225. if (trianglesContainingVertexA[i].Contains(vertexB)) {
  226. sharedTriangleCount ++;
  227. if (sharedTriangleCount > 1) {
  228. break;
  229. }
  230. }
  231. }
  232. return sharedTriangleCount == 1;
  233. }
  234. struct Triangle {
  235. public int vertexIndexA;
  236. public int vertexIndexB;
  237. public int vertexIndexC;
  238. int[] vertices;
  239. public Triangle (int a, int b, int c) {
  240. vertexIndexA = a;
  241. vertexIndexB = b;
  242. vertexIndexC = c;
  243. vertices = new int[3];
  244. vertices[0] = a;
  245. vertices[1] = b;
  246. vertices[2] = c;
  247. }
  248. public int this[int i] {
  249. get {
  250. return vertices[i];
  251. }
  252. }
  253. public bool Contains(int vertexIndex) {
  254. return vertexIndex == vertexIndexA || vertexIndex == vertexIndexB || vertexIndex == vertexIndexC;
  255. }
  256. }
  257. public class SquareGrid {
  258. public Square[,] squares;
  259. public SquareGrid(int[,] map, float squareSize) {
  260. int nodeCountX = map.GetLength(0);
  261. int nodeCountY = map.GetLength(1);
  262. float mapWidth = nodeCountX * squareSize;
  263. float mapHeight = nodeCountY * squareSize;
  264. ControlNode[,] controlNodes = new ControlNode[nodeCountX,nodeCountY];
  265. for (int x = 0; x < nodeCountX; x ++) {
  266. for (int y = 0; y < nodeCountY; y ++) {
  267. Vector3 pos = new Vector3(-mapWidth/2 + x * squareSize + squareSize/2, 0, -mapHeight/2 + y * squareSize + squareSize/2);
  268. controlNodes[x,y] = new ControlNode(pos,map[x,y] == 1, squareSize);
  269. }
  270. }
  271. squares = new Square[nodeCountX -1,nodeCountY -1];
  272. for (int x = 0; x < nodeCountX-1; x ++) {
  273. for (int y = 0; y < nodeCountY-1; y ++) {
  274. squares[x,y] = new Square(controlNodes[x,y+1], controlNodes[x+1,y+1], controlNodes[x+1,y], controlNodes[x,y]);
  275. }
  276. }
  277. }
  278. }
  279. public class Square {
  280. public ControlNode topLeft, topRight, bottomRight, bottomLeft;
  281. public Node centreTop, centreRight, centreBottom, centreLeft;
  282. public int configuration;
  283. public Square (ControlNode _topLeft, ControlNode _topRight, ControlNode _bottomRight, ControlNode _bottomLeft) {
  284. topLeft = _topLeft;
  285. topRight = _topRight;
  286. bottomRight = _bottomRight;
  287. bottomLeft = _bottomLeft;
  288. centreTop = topLeft.right;
  289. centreRight = bottomRight.above;
  290. centreBottom = bottomLeft.right;
  291. centreLeft = bottomLeft.above;
  292. if (topLeft.active)
  293. configuration += 8;
  294. if (topRight.active)
  295. configuration += 4;
  296. if (bottomRight.active)
  297. configuration += 2;
  298. if (bottomLeft.active)
  299. configuration += 1;
  300. }
  301. }
  302. public class Node {
  303. public Vector3 position;
  304. public int vertexIndex = -1;
  305. public Node(Vector3 _pos) {
  306. position = _pos;
  307. }
  308. }
  309. public class ControlNode : Node {
  310. public bool active;
  311. public Node above, right;
  312. public ControlNode(Vector3 _pos, bool _active, float squareSize) : base(_pos) {
  313. active = _active;
  314. above = new Node(position + Vector3.forward * squareSize/2f);
  315. right = new Node(position + Vector3.right * squareSize/2f);
  316. }
  317. }
  318. }