using System; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(e2dTerrain))] public class e2dTerrainGenerator : MonoBehaviour { private class HeightComparer : IComparer> { public int Compare(KeyValuePair x, KeyValuePair y) { return (x.Key < y.Key) ? (-1) : ((x.Key > y.Key) ? 1 : 0); } } public bool FullRebuild = e2dConstants.INIT_FULL_REBUILD; public float NodeStepSize = e2dConstants.INIT_NODE_STEP_SIZE; public Vector2 TargetPosition = e2dConstants.INIT_TARGET_POSITION; public Vector2 TargetSize = e2dConstants.INIT_TARGET_SIZE; public float TargetAngle = e2dConstants.INIT_TARGET_ANGLE; public e2dCurvePerlinPreset Perlin = (e2dCurvePerlinPreset)e2dPresets.GetDefault(e2dGeneratorCurveMethod.PERLIN); public e2dCurveVoronoiPreset Voronoi = (e2dCurveVoronoiPreset)e2dPresets.GetDefault(e2dGeneratorCurveMethod.VORONOI); public e2dCurveMidpointPreset Midpoint = (e2dCurveMidpointPreset)e2dPresets.GetDefault(e2dGeneratorCurveMethod.MIDPOINT); public e2dCurveWalkPreset Walk = (e2dCurveWalkPreset)e2dPresets.GetDefault(e2dGeneratorCurveMethod.WALK); public List Peaks = new List(); public float[] CurveBlendingWeights = new float[4]; public int SmoothIterations; public int CliffTextureIndex; public float CliffStartAngle; public List TextureHeights; private e2dTerrain mTerrain; [NonSerialized] public UnityEngine.Object EditorReference; public e2dTerrain Terrain { get { if (mTerrain == null) { mTerrain = GetComponent(); } if (mTerrain == null) { e2dUtils.Error("Can't find the terrain component."); } return mTerrain; } } public int NodeCount { get { return 1 + Mathf.RoundToInt(TargetSize.x / NodeStepSize); } } private void OnEnable() { EditorReference = null; } private void SetPointsToCurve(Vector2[] points, bool fullRebuild) { if (fullRebuild || Terrain.TerrainCurve.Count == 0) { Terrain.AddCurvePoints(points, 0, Terrain.TerrainCurve.Count - 1); return; } int[] curveIndicesInTargetArea = GetCurveIndicesInTargetArea(); if (curveIndicesInTargetArea[0] == -2) { float sqrMagnitude = (Terrain.TerrainCurve[0].position - points[points.Length - 1]).sqrMagnitude; float sqrMagnitude2 = (Terrain.TerrainCurve[Terrain.TerrainCurve.Count - 1].position - points[0]).sqrMagnitude; if (sqrMagnitude < sqrMagnitude2) { curveIndicesInTargetArea[0] = 0; curveIndicesInTargetArea[1] = -1; } else { curveIndicesInTargetArea[0] = Terrain.TerrainCurve.Count; curveIndicesInTargetArea[1] = Terrain.TerrainCurve.Count - 1; } } Terrain.AddCurvePoints(points, curveIndicesInTargetArea[0], curveIndicesInTargetArea[1]); } private int[] GetCurveIndicesInTargetArea() { Vector2[] targetAreaBoundary = GetTargetAreaBoundary(); int num = -2; for (int i = 1; i < Terrain.TerrainCurve.Count; i++) { if (e2dUtils.SegmentIntersectsPolygon(Terrain.TerrainCurve[i - 1].position, Terrain.TerrainCurve[i].position, targetAreaBoundary)) { num = i; break; } } if (e2dUtils.PointInConvexPolygon(Terrain.TerrainCurve[0].position, targetAreaBoundary)) { num = 0; } int num2 = -2; for (int num3 = Terrain.TerrainCurve.Count - 1; num3 >= 1; num3--) { if (e2dUtils.SegmentIntersectsPolygon(Terrain.TerrainCurve[num3 - 1].position, Terrain.TerrainCurve[num3].position, targetAreaBoundary)) { num2 = num3 - 1; break; } } if (e2dUtils.PointInConvexPolygon(Terrain.TerrainCurve[Terrain.TerrainCurve.Count - 1].position, targetAreaBoundary)) { num2 = Terrain.TerrainCurve.Count - 1; } return new int[2] { num, num2 }; } public Rect GetTargetAreaBoundingBox() { Rect result = default(Rect); result.xMin = float.MaxValue; result.yMin = float.MaxValue; result.xMax = float.MinValue; result.yMax = float.MinValue; Vector2[] targetAreaBoundary = GetTargetAreaBoundary(); for (int i = 0; i < targetAreaBoundary.Length; i++) { Vector2 vector = targetAreaBoundary[i]; if (vector.x < result.xMin) { result.xMin = vector.x; } if (vector.y < result.yMin) { result.yMin = vector.y; } if (vector.x > result.xMax) { result.xMax = vector.x; } if (vector.y > result.yMax) { result.yMax = vector.y; } } return result; } public Vector2[] GetTargetAreaBoundary() { return new Vector2[4] { TransformPointFromTargetArea(new Vector3(-0.5f * TargetSize.x, -0.5f * TargetSize.y)), TransformPointFromTargetArea(new Vector3(-0.5f * TargetSize.x, 0.5f * TargetSize.y)), TransformPointFromTargetArea(new Vector3(0.5f * TargetSize.x, 0.5f * TargetSize.y)), TransformPointFromTargetArea(new Vector3(0.5f * TargetSize.x, -0.5f * TargetSize.y)) }; } public Rect GetTargetAreaLocalBox() { return new Rect(-0.5f * TargetSize.x, -0.5f * TargetSize.y, TargetSize.x, TargetSize.y); } public Vector3 TransformPointFromTargetArea(Vector3 point) { point = Quaternion.Euler(0f, 0f, TargetAngle) * point; point.x += TargetPosition.x; point.y += TargetPosition.y; return point; } public Vector3 TransformPointIntoTargetArea(Vector3 point) { point.x -= TargetPosition.x; point.y -= TargetPosition.y; point = Quaternion.Euler(0f, 0f, 0f - TargetAngle) * point; return point; } public void FixTargetArea() { TargetSize.x = Mathf.Max(TargetSize.x, float.Epsilon); TargetSize.y = Mathf.Max(TargetSize.y, float.Epsilon); Rect targetAreaLocalBox = GetTargetAreaLocalBox(); for (int i = 0; i < Peaks.Count; i++) { Vector3 vector = Peaks[i].position; if (vector.x < targetAreaLocalBox.xMin) { vector.x = targetAreaLocalBox.xMin; } if (vector.y < targetAreaLocalBox.yMin) { vector.y = targetAreaLocalBox.yMin; } if (vector.x > targetAreaLocalBox.xMax) { vector.x = targetAreaLocalBox.xMax; } if (vector.y > targetAreaLocalBox.yMax) { vector.y = targetAreaLocalBox.yMax; } Peaks[i].position = vector; } } public void GenerateCurve() { float[] debugHeightmap = null; GenerateCurve(ref debugHeightmap); } public void GenerateCurve(ref float[] debugHeightmap) { if (NodeCount < 2) { e2dUtils.Error("Map too small for generating."); return; } float num = 0f; float[] curveBlendingWeights = CurveBlendingWeights; foreach (float num2 in curveBlendingWeights) { num += num2; } float[] array = new float[NodeCount]; float[] array2 = new float[NodeCount]; for (int j = 0; j < NodeCount; j++) { array[j] = 0.5f; } bool flag = true; for (int k = 0; k < 4; k++) { if (num == 0f || CurveBlendingWeights[k] == 0f) { continue; } if (e2dUtils.DEBUG_FIXED_GENERATOR_SEED) { UnityEngine.Random.seed = 12345; } switch ((e2dGeneratorCurveMethod)k) { case e2dGeneratorCurveMethod.PERLIN: { bool flag2 = GenerateCurvePerlin(array2, GetTargetAreaLocalBox(), ref debugHeightmap); if (flag2) { NormalizeHeightmap(array2); } if (!flag2) { flag = false; } break; } case e2dGeneratorCurveMethod.VORONOI: if (!GenerateCurveVoronoi(array2, GetTargetAreaLocalBox(), ref debugHeightmap)) { flag = false; } break; case e2dGeneratorCurveMethod.MIDPOINT: { bool flag2 = GenerateCurveMidpoint(array2, GetTargetAreaLocalBox(), ref debugHeightmap); if (flag2) { NormalizeHeightmap(array2); } if (!flag2) { flag = false; } break; } case e2dGeneratorCurveMethod.WALK: { bool flag2 = GenerateCurveWalk(array2, GetTargetAreaLocalBox(), ref debugHeightmap); if (flag2) { NormalizeHeightmap(array2); } if (!flag2) { flag = false; } break; } } for (int l = 0; l < array.Length; l++) { array[l] += (array2[l] - 0.5f) * CurveBlendingWeights[k] / num; } } if (flag) { NormalizeHeightmap(array); } Vector2[] targetAreaBoundary = GetTargetAreaBoundary(); Vector2[] array3 = new Vector2[NodeCount]; for (int m = 0; m < NodeCount; m++) { float num3 = (float)m / (float)(NodeCount - 1); array3[m] = (1f - num3) * targetAreaBoundary[0] + num3 * targetAreaBoundary[3]; array3[m] += array[m] * (targetAreaBoundary[1] - targetAreaBoundary[0]); } SetPointsToCurve(array3, FullRebuild); Terrain.CurveClosed = false; Terrain.FixCurve(); Terrain.FixBoundary(); Terrain.RebuildAllMaterials(); Terrain.RebuildAllMeshes(); } private void NormalizeHeightmap(float[] heightMap) { float num = float.MaxValue; float num2 = float.MinValue; foreach (float num3 in heightMap) { if (num3 < num) { num = num3; } if (num3 > num2) { num2 = num3; } } if (!(num2 - num <= float.Epsilon)) { for (int j = 0; j < heightMap.Length; j++) { heightMap[j] = (heightMap[j] - num) / (num2 - num); } } } private List PreparePeaks(int totalPeakCount, float peakRatio, bool includeCustomPeaks, Rect targetRect) { List list = new List(); totalPeakCount = Mathf.Max(totalPeakCount, 2); bool flag = true; if (includeCustomPeaks) { foreach (e2dGeneratorPeak peak in Peaks) { float x = (peak.position.x - targetRect.xMin) / targetRect.width; float num = (peak.position.y - targetRect.yMin) / targetRect.height; list.Add(new Vector2(x, num)); if (Mathf.Approximately(num, 1f)) { flag = false; } } } while (list.Count < totalPeakCount) { float y = 0f; if (UnityEngine.Random.value <= peakRatio) { y = UnityEngine.Random.value; } list.Add(new Vector2(UnityEngine.Random.value, y)); } if (flag) { float num2 = float.MinValue; int num3 = (includeCustomPeaks ? Peaks.Count : 0); for (int i = num3; i < list.Count; i++) { if (list[i].y > num2) { num2 = list[i].y; } } if (num2 > float.Epsilon) { for (int j = num3; j < list.Count; j++) { Vector2 value = list[j]; value.y /= num2; list[j] = value; } } } return list; } private bool GenerateCurvePerlin(float[] heightMap, Rect targetRect, ref float[] debugHeightmap) { int a = 1 + Mathf.RoundToInt(Perlin.frequencyPerUnit * targetRect.width); a = Mathf.Max(a, 2); e2dPerlinNoise e2dPerlinNoise2 = new e2dPerlinNoise(Perlin.octaves, 1f, a, Perlin.persistence); e2dPerlinNoise2.Regenerate(); for (int i = 0; i < heightMap.Length; i++) { float x = (float)i / (float)(heightMap.Length - 1); heightMap[i] = e2dPerlinNoise2.GetValue(x); } if (e2dUtils.DEBUG_GENERATOR_CURVE) { debugHeightmap = new float[10 * heightMap.Length]; for (int j = 0; j < debugHeightmap.Length; j++) { float x2 = (float)j / (float)(debugHeightmap.Length - 1); debugHeightmap[j] = e2dPerlinNoise2.GetValue(x2) * targetRect.height; } } return true; } private bool GenerateCurveVoronoi(float[] heightMap, Rect targetRect, ref float[] debugHeightmap) { int totalPeakCount = Mathf.RoundToInt(Voronoi.frequencyPerUnit * targetRect.width); List peaks = PreparePeaks(totalPeakCount, Voronoi.peakRatio, Voronoi.usePeaks, targetRect); e2dVoronoi e2dVoronoi2 = new e2dVoronoi(peaks, Voronoi.peakType, Voronoi.peakWidth); for (int i = 0; i < heightMap.Length; i++) { float x = (float)i / (float)(heightMap.Length - 1); heightMap[i] = e2dVoronoi2.GetValue(x); } if (e2dUtils.DEBUG_GENERATOR_CURVE) { debugHeightmap = new float[10 * heightMap.Length]; for (int j = 0; j < debugHeightmap.Length; j++) { float x2 = (float)j / (float)(debugHeightmap.Length - 1); debugHeightmap[j] = e2dVoronoi2.GetValue(x2) * targetRect.height; } } return !Voronoi.usePeaks; } private bool GenerateCurveMidpoint(float[] heightMap, Rect targetRect, ref float[] debugHeightmap) { List peaks = null; if (Midpoint.usePeaks) { peaks = PreparePeaks(Peaks.Count, 0f, true, targetRect); } int initialStep = Mathf.RoundToInt((float)heightMap.Length / (Midpoint.frequencyPerUnit * targetRect.width)); e2dMidpoint e2dMidpoint2 = new e2dMidpoint(heightMap.Length, initialStep, Midpoint.roughness, peaks); e2dMidpoint2.Regenerate(); for (int i = 0; i < heightMap.Length; i++) { heightMap[i] = e2dMidpoint2.GetValueAt(i); if (Midpoint.usePeaks) { heightMap[i] = Mathf.Clamp01(heightMap[i]); } } if (e2dUtils.DEBUG_GENERATOR_CURVE) { debugHeightmap = new float[heightMap.Length]; for (int j = 0; j < heightMap.Length; j++) { debugHeightmap[j] = e2dMidpoint2.GetValueAt(j) * targetRect.height; } } return !Midpoint.usePeaks; } private bool GenerateCurveWalk(float[] heightMap, Rect targetRect, ref float[] debugHeightmap) { float num = 1f / (float)(heightMap.Length - 1); float num2 = targetRect.width / (float)(heightMap.Length - 1); float value = 1f / (Walk.frequencyPerUnit * targetRect.width); value = Mathf.Clamp01(value); float num3 = 0.5f; float num4 = 0f; float num5 = num3; float num6 = num3; heightMap[0] = num3; for (int i = 1; i < heightMap.Length; i++) { float num7 = (float)i / (float)(heightMap.Length - 1); float num8 = Mathf.Min(num7 % value, value - num7 % value); num8 = 1f - num8 * 2f / value; num8 = Mathf.Pow(num8, 10f); float num9 = num8 * Walk.angleChangePerUnit * num2 * (2f * UnityEngine.Random.value - 1f); num4 = Mathf.Repeat(num4 + num9 + 180f, 360f) - 180f; num4 = Mathf.Clamp(num4, -80f, 80f); float num10 = Mathf.Tan(num4 * ((float)Math.PI / 180f)) * num; num3 += num10; float num11 = (e2dConstants.WALK_COHESION_MAX - Walk.cohesionPerUnit) * (float)i * num * 0.5f; float num12 = Mathf.Clamp(num3, num6 - num11, num5 + num11); if (num3 != num12) { num4 = 0f; } num3 = num12; num5 = Mathf.Min(num5, num3); num6 = Mathf.Max(num6, num3); heightMap[i] = num3; } if (e2dUtils.DEBUG_GENERATOR_CURVE) { debugHeightmap = new float[heightMap.Length]; for (int j = 0; j < heightMap.Length; j++) { debugHeightmap[j] = heightMap[j] * targetRect.height; } } return true; } public void SmoothCurve() { int[] curveIndicesInTargetArea = GetCurveIndicesInTargetArea(); int num = curveIndicesInTargetArea[1] - curveIndicesInTargetArea[0] + 1; if (curveIndicesInTargetArea[0] == -2 || num < 2) { return; } float[] array = new float[num]; float[] array2 = new float[num]; for (int i = 0; i < num; i++) { array[i] = ((Vector2)TransformPointIntoTargetArea(Terrain.TerrainCurve[curveIndicesInTargetArea[0] + i].position)).y; } for (int j = 0; j < SmoothIterations; j++) { for (int k = 1; k < num - 1; k++) { float num2 = 0.5f * (array[k - 1] + array[k + 1]); num2 = 0.5f * (num2 + array[k]); array2[k] = num2; } for (int l = 1; l < num - 1; l++) { array[l] = array2[l]; } } for (int m = 0; m < num; m++) { Vector2 vector = TransformPointIntoTargetArea(Terrain.TerrainCurve[curveIndicesInTargetArea[0] + m].position); vector.y = array[m]; Terrain.TerrainCurve[curveIndicesInTargetArea[0] + m].position = TransformPointFromTargetArea(vector); } Terrain.FixCurve(); Terrain.FixBoundary(); Terrain.RebuildAllMaterials(); Terrain.RebuildAllMeshes(); } public void TextureTerrain() { if (TextureHeights.Count != Terrain.CurveTextures.Count) { e2dUtils.Error("TextureTerrain: TextureHeights and CurveTextures have different number of elements"); return; } List> list = new List>(); float num = float.MinValue; foreach (float textureHeight in TextureHeights) { float b = textureHeight; num = Mathf.Max(num, b); } if (num <= 0f) { e2dUtils.Error("TextureTerrain: no texture heights defined above ground"); return; } for (int i = 0; i < TextureHeights.Count; i++) { if (TextureHeights[i] > 0f) { list.Add(new KeyValuePair(TextureHeights[i] / num, i)); } } list.Sort(new HeightComparer()); int[] curveIndicesInTargetArea = GetCurveIndicesInTargetArea(); int num2 = curveIndicesInTargetArea[1] - curveIndicesInTargetArea[0] + 1; if (curveIndicesInTargetArea[0] == -2 || num2 < 1) { return; } Rect targetAreaLocalBox = GetTargetAreaLocalBox(); for (int j = 0; j < num2; j++) { Vector2 vector = TransformPointIntoTargetArea(Terrain.TerrainCurve[curveIndicesInTargetArea[0] + j].position); float num3 = (vector.y + 0.5f * targetAreaLocalBox.height) / targetAreaLocalBox.height; foreach (KeyValuePair item in list) { if (num3 <= item.Key) { Terrain.TerrainCurve[curveIndicesInTargetArea[0] + j].texture = item.Value; break; } } if (j > 0 && j < num2 - 1) { Vector2 vector2 = TransformPointIntoTargetArea(Terrain.TerrainCurve[curveIndicesInTargetArea[0] + j - 1].position); Vector2 vector3 = TransformPointIntoTargetArea(Terrain.TerrainCurve[curveIndicesInTargetArea[0] + j + 1].position); float num4 = Mathf.Atan2(vector.y - vector2.y, vector.x - vector2.x) * 57.29578f; float num5 = Mathf.Atan2(vector3.y - vector.y, vector3.x - vector.x) * 57.29578f; if ((num4 >= CliffStartAngle && num5 >= CliffStartAngle) || (num4 <= 0f - CliffStartAngle && num5 <= 0f - CliffStartAngle)) { Terrain.TerrainCurve[curveIndicesInTargetArea[0] + j].texture = CliffTextureIndex; } } } Terrain.RebuildAllMaterials(); Terrain.RebuildAllMeshes(); } }