Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class MDTerrainController2D : MonoBehaviour
- {
- private GameObject detailObject;
- public float startHeight, endHeight, roughness, resolution;
- public SpriteRenderer backgroundRenderer;
- public Texture terrainTexture, detailTexture;
- private void Awake()
- {
- float[] heightMap = GenerateHeightmap(startHeight, endHeight, Mathf.CeilToInt(backgroundRenderer.bounds.size.x) * Mathf.CeilToInt(resolution));
- Vector2[] terrainVertices = CreateVertices(heightMap, resolution);
- Vector2[] terrainUVs = GenerateTerrainUVs(heightMap);
- int[] terrainTriangles = Triangulate(terrainVertices.Length);
- GenerateTerrainMesh(terrainVertices, terrainTriangles, terrainUVs, "Generated Terrain", terrainTexture, 0);
- Vector2[] grassVertices = GenerateGrassVertices(heightMap, resolution);
- Vector2[] grassUVs = GenerateGrassUVs(heightMap);
- int[] grassTriangles = Triangulate(terrainVertices.Length);
- CalculateCollider(GenerateTerrainMesh(grassVertices, grassTriangles, grassUVs, "Generated Terrain Detail", detailTexture, -2, out detailObject));
- }
- private Mesh GenerateTerrainMesh(Vector2[] vertices, int[] triangles, Vector2[] uvs, string name, Texture texture, int z)
- {
- List<Vector3> meshVertices = new List<Vector3>();
- foreach(Vector2 vertex in vertices)
- {
- meshVertices.Add(new Vector3(vertex.x, vertex.y, z));
- }
- Mesh mesh = new Mesh();
- mesh.vertices = meshVertices.ToArray();
- mesh.uv = uvs;
- mesh.triangles = triangles;
- mesh.RecalculateNormals();
- mesh.RecalculateBounds();
- GameObject terrainObject = new GameObject(name);
- terrainObject.AddComponent<MeshRenderer>();
- MeshFilter meshFilter = terrainObject.AddComponent<MeshFilter>();
- meshFilter.mesh = mesh;
- terrainObject.GetComponent<MeshRenderer>().material.SetTexture("_MainTex", texture);
- terrainObject.transform.parent = transform;
- terrainObject.transform.localPosition = transform.InverseTransformPoint(transform.position);
- return mesh;
- }
- private Mesh GenerateTerrainMesh(Vector2[] vertices, int[] triangles, Vector2[] uvs, string name, Texture texture, int z, out GameObject meshObject)
- {
- List<Vector3> meshVertices = new List<Vector3>();
- foreach(Vector2 vertex in vertices)
- {
- meshVertices.Add(new Vector3(vertex.x, vertex.y, z));
- }
- Mesh mesh = new Mesh();
- mesh.vertices = meshVertices.ToArray();
- mesh.uv = uvs;
- mesh.triangles = triangles;
- mesh.RecalculateNormals();
- mesh.RecalculateBounds();
- GameObject terrainObject = new GameObject(name);
- terrainObject.AddComponent<MeshRenderer>();
- MeshFilter meshFilter = terrainObject.AddComponent<MeshFilter>();
- meshFilter.mesh = mesh;
- terrainObject.GetComponent<MeshRenderer>().material.SetTexture("_MainTex", texture);
- terrainObject.transform.parent = transform;
- terrainObject.transform.localPosition = transform.InverseTransformPoint(transform.position);
- meshObject = terrainObject;
- meshObject.AddComponent(typeof(PolygonCollider2D));
- mesh.name = meshObject.name;
- return mesh;
- }
- private float[] GenerateHeightmap(float startHeight, float endHeight, int length)
- {
- float[] heightmap = new float[length + 1];
- heightmap[0] = startHeight;
- heightmap[heightmap.Length - 1] = endHeight;
- GenerateMidpoint(0, heightmap.Length - 1, roughness, heightmap);
- return heightmap;
- }
- private void GenerateMidpoint(int start, int end, float passedRoughness, float[] heightmap)
- {
- int midpoint = Mathf.FloorToInt((start + end) / 2);
- if(midpoint != start)
- {
- float midHeight = (heightmap[start] + heightmap[end]) / 2;
- heightmap[midpoint] = midHeight + Random.Range(-passedRoughness, passedRoughness);
- GenerateMidpoint(start, midpoint, passedRoughness / 2, heightmap);
- GenerateMidpoint(midpoint, end, passedRoughness / 2, heightmap);
- }
- }
- private Vector2[] CreateVertices(float[] heightmap, float resolution)
- {
- resolution = Mathf.Max(1, resolution);
- List<Vector2> vertices = new List<Vector2>();
- for(int i = 0; i < heightmap.Length; i++)
- {
- vertices.Add(new Vector2(i / resolution, heightmap[i]));
- vertices.Add(new Vector2(i / resolution, 0));
- }
- return vertices.ToArray();
- }
- private Vector2[] GenerateTerrainUVs(float[] heightmap)
- {
- List<Vector2> uvs = new List<Vector2>();
- float factor = 1.0f / heightmap.Length;
- for(int i = 0; i < heightmap.Length; i++)
- {
- uvs.Add(new Vector2(factor * i * 20, heightmap[i] / 20));
- uvs.Add(new Vector2(factor * i * 20, 0));
- }
- return uvs.ToArray();
- }
- private Vector2[] GenerateGrassVertices(float[] heightmap, float resolution)
- {
- resolution = Mathf.Max(1, resolution);
- List<Vector2> vertices = new List<Vector2>();
- for(int i = 0; i < heightmap.Length; i++)
- {
- vertices.Add(new Vector2(i / resolution, heightmap[i]));
- vertices.Add(new Vector2(i / resolution, heightmap[i] - 1));
- }
- return vertices.ToArray();
- }
- private Vector2[] GenerateGrassUVs(float[] heightmap)
- {
- List<Vector2> uvs = new List<Vector2>();
- float factor = 1.0f / heightmap.Length;
- for(int i = 0; i < heightmap.Length; i++)
- {
- uvs.Add(new Vector2(i % 2, 1));
- uvs.Add(new Vector2(i % 2, 0));
- }
- return uvs.ToArray();
- }
- private void CalculateCollider(Mesh mesh)
- {
- int[] triangles = mesh.triangles;
- Vector3[] vertices = mesh.vertices;
- // Get just the outer edges from the mesh's triangles (ignore or remove any shared edges)
- Dictionary<string, KeyValuePair<int, int>> edges = new Dictionary<string, KeyValuePair<int, int>>();
- for (int i = 0; i < triangles.Length; i += 3)
- {
- for (int e = 0; e < 3; e++)
- {
- int vert1 = triangles[i + e];
- int vert2 = triangles[i + e + 1 > i + 2 ? i : i + e + 1];
- string edge = Mathf.Min(vert1, vert2) + ":" + Mathf.Max(vert1, vert2);
- if (edges.ContainsKey(edge))
- {
- edges.Remove(edge);
- }
- else
- {
- edges.Add(edge, new KeyValuePair<int, int>(vert1, vert2));
- }
- }
- }
- // Create edge lookup (Key is first vertex, Value is second vertex, of each edge)
- Dictionary<int, int> lookup = new Dictionary<int, int>();
- foreach (KeyValuePair<int, int> edge in edges.Values)
- {
- if (lookup.ContainsKey(edge.Key) == false)
- {
- lookup.Add(edge.Key, edge.Value);
- }
- }
- // Create empty polygon collider
- PolygonCollider2D polygonCollider = detailObject.AddComponent(typeof(PolygonCollider2D)) as PolygonCollider2D;
- polygonCollider.pathCount = 0;
- // Loop through edge vertices in order
- int startVert = 0;
- int nextVert = startVert;
- int highestVert = startVert;
- List<Vector2> colliderPath = new List<Vector2>();
- while (true)
- {
- // Add vertex to collider path
- colliderPath.Add(vertices[nextVert]);
- // Get next vertex
- nextVert = lookup[nextVert];
- // Store highest vertex (to know what shape to move to next)
- if (nextVert > highestVert)
- {
- highestVert = nextVert;
- }
- // Shape complete
- if (nextVert == startVert)
- {
- // Add path to polygon collider
- polygonCollider.pathCount++;
- polygonCollider.SetPath(polygonCollider.pathCount - 1, colliderPath.ToArray());
- colliderPath.Clear();
- // Go to next shape if one exists
- if (lookup.ContainsKey(highestVert + 1))
- {
- // Set starting and next vertices
- startVert = highestVert + 1;
- nextVert = startVert;
- // Continue to next loop
- continue;
- }
- for(int i = 0; i < polygonCollider.pathCount; i++)
- {
- detailObject.GetComponent<PolygonCollider2D>().SetPath(i, polygonCollider.GetPath(i));
- }
- detailObject.AddComponent<Rigidbody2D>().isKinematic = true;
- // No more verts
- break;
- }
- }
- }
- private int[] Triangulate(int count)
- {
- List<int> indices = new List<int>();
- for(int i = 0; i <= count - 4; i += 2)
- {
- indices.Add(i);
- indices.Add(i + 3);
- indices.Add(i + 1);
- indices.Add(i + 3);
- indices.Add(i);
- indices.Add(i + 2);
- }
- return indices.ToArray();
- }
- }
Add Comment
Please, Sign In to add comment