├── .gitignore ├── README.txt └── UnitySimpleMapGenerator ├── AssemblyInfo.cs ├── BraveNewWorld ├── AssemblyInfo.cs ├── BraveNewWorld.csproj ├── Helpers │ └── MapPointToPointConverter.cs ├── Models │ ├── Center.cs │ ├── Corner.cs │ ├── Edge.cs │ ├── Factory.cs │ ├── IMapItem.cs │ ├── Map.cs │ └── Triangle.cs └── Services │ ├── IslandService.cs │ └── MapService.cs ├── FortuneVoronoi ├── AssemblyInfo.cs ├── Fortune.cs ├── FortuneVoronoi.csproj ├── GlobalSuppressions.cs ├── ToolBox.cs ├── VCircleEvent.cs ├── VDataEvent.cs ├── VDataNode.cs ├── VEdgeNode.cs ├── VEvent.cs ├── VNode.cs ├── VoronoiEdge.cs ├── VoronoiGraph.cs └── lib │ ├── NGenerics.dll │ ├── NGenerics.pdb │ └── NGenerics.xml ├── UnitySimpleMapGenerator.csproj └── UnitySimpleMapGenerator.sln /.gitignore: -------------------------------------------------------------------------------- 1 | *.pidb 2 | *.userprefs 3 | .DS_Store 4 | bin 5 | obj 6 | *.suo 7 | UnitySimpleMapGenerator/obj/Debug/ResolveAssemblyReference.cache 8 | UnitySimpleMapGenerator/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache 9 | UnitySimpleMapGenerator/obj/Debug/UnitySimpleMapGenerator.csproj.FileListAbsolute.txt -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This is a port of Baran Kahyaoglu's Simple Map Generator, which you can find 2 | here: 3 | 4 | http://www.barankahyaoglu.com/blog/post/2011/07/27/Simple-Map-Generator-Part-1.aspx 5 | 6 | Source Origins: 7 | 8 | The Simple Map Generator is based on an article and some code by Amit Patel: 9 | 10 | http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/ 11 | 12 | Baran's code makes use of Fortune's Voronoi code by BenDi on CodeProject: 13 | 14 | http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 15 | 16 | Unity3D Port: 17 | 18 | This port brings the Simple Map Generator code into Unity3D and produces a 19 | 3D mesh suitable for characters to walk around on. 20 | 21 | - Chris Herborth 22 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Use this code for whatever you want, just don't blame me if it breaks. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | using System; 8 | using System.Reflection; 9 | using System.Runtime.CompilerServices; 10 | 11 | // Information about this assembly is defined by the following attributes. 12 | // Change them to the values specific to your project. 13 | 14 | [assembly: AssemblyTitle("UnitySimpleMapGenerator")] 15 | [assembly: AssemblyDescription("A Unity3D port of Baran Kahyaoglu's Map Generator - http://www.barankahyaoglu.com/blog/page/MapGenerator.aspx")] 16 | [assembly: AssemblyConfiguration("")] 17 | [assembly: AssemblyCompany("Taffer")] 18 | [assembly: AssemblyProduct("")] 19 | [assembly: AssemblyCopyright("Free to use, copy, fork, etc. but don't blame me if it breaks.")] 20 | [assembly: AssemblyTrademark("")] 21 | [assembly: AssemblyCulture("")] 22 | 23 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 24 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 25 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 26 | 27 | [assembly: AssemblyVersion("1.0.*")] 28 | 29 | // The following attributes are used to specify the signing key for the assembly, 30 | // if desired. See the Mono documentation for more information about signing. 31 | 32 | //[assembly: AssemblyDelaySign(false)] 33 | //[assembly: AssemblyKeyFile("")] 34 | 35 | // Must be false due to UnityEngine. 36 | [assembly: CLSCompliant(false)] 37 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Use this code for whatever you want, just don't blame me if it breaks. 4 | // 5 | // ----------------------------------------------------------------------- 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | 9 | // Information about this assembly is defined by the following attributes. 10 | // Change them to the values specific to your project. 11 | 12 | [assembly: AssemblyTitle("BraveNewWorld")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("")] 17 | [assembly: AssemblyCopyright("Chris Herborth (chrish@pobox.com)")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 22 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 23 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 24 | 25 | [assembly: AssemblyVersion("1.0.*")] 26 | 27 | // The following attributes are used to specify the signing key for the assembly, 28 | // if desired. See the Mono documentation for more information about signing. 29 | 30 | //[assembly: AssemblyDelaySign(false)] 31 | //[assembly: AssemblyKeyFile("")] 32 | 33 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/BraveNewWorld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.0 7 | 2.0 8 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76} 9 | Library 10 | BraveNewWorld 11 | BraveNewWorld 12 | 13 | 14 | true 15 | full 16 | false 17 | bin\Debug 18 | DEBUG; 19 | prompt 20 | 4 21 | false 22 | 23 | 24 | none 25 | false 26 | bin\Release 27 | prompt 28 | 4 29 | false 30 | 31 | 32 | 33 | 34 | ..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A} 54 | FortuneVoronoi 55 | 56 | 57 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Helpers/MapPointToPointConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Data; 3 | using System.Windows.Media; 4 | using BraveNewWorld.Models; 5 | 6 | namespace BraveNewWorld.Helpers 7 | { 8 | public class MapPointToPointConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 11 | { 12 | var ps = (Center)value; 13 | 14 | PointCollection polygonPoints = new PointCollection(); 15 | 16 | foreach (Corner mp in ps.Corners) 17 | { 18 | polygonPoints.Add(new System.Windows.Point(mp.Point.X - ps.Point.X, mp.Point.Y - ps.Point.Y)); 19 | } 20 | 21 | return polygonPoints; 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 25 | { 26 | return null; 27 | } 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Center.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Windows; 6 | using System.Windows.Media; 7 | using System.Windows.Media.Media3D; 8 | 9 | namespace BraveNewWorld.Models 10 | { 11 | public class Center : DependencyObject, IEquatable
, IMapItem 12 | { 13 | public int Index { get; set; } 14 | 15 | public int Key { get; set; } 16 | public Point Point { get; set; } // location 17 | public Boolean Water { get; set; } // lake or ocean 18 | public Boolean Land { get { return !Water; } set { Water = !value; } } // lake or ocean 19 | public Boolean Ocean { get; set; } // ocean 20 | public Boolean Coast { get; set; } // land polygon touching an ocean 21 | public Boolean Border { get; set; } // at the edge of the map 22 | public Vector3D polyNorm { get; set; } 23 | 24 | private string _biome; 25 | public string Biome 26 | { 27 | get 28 | { 29 | return _biome; 30 | } 31 | set 32 | { 33 | if (value == "Ocean") 34 | PolygonBrush = new SolidColorBrush(new Color() { R = 54, G = 54, B = 97, A = 255 }); 35 | if (value == "ShallowWater") 36 | PolygonBrush = new SolidColorBrush(new Color() { R = 74, G = 74, B = 117, A = 255 }); 37 | else if (value == "Marsh") 38 | PolygonBrush = new SolidColorBrush(new Color() { R = 196, G = 204, B = 187 , A=255 }); 39 | else if (value == "Lake") 40 | PolygonBrush = new SolidColorBrush(new Color() { R = 54, G = 54, B = 97, A = 255 }); 41 | else if (value == "Beach") 42 | PolygonBrush = new SolidColorBrush(new Color() { R = 173, G = 161, B = 139, A = 255 }); 43 | else if (value == "Snow") 44 | PolygonBrush = new SolidColorBrush(Colors.White); 45 | else if (value == "Tundra") 46 | PolygonBrush = new SolidColorBrush(new Color() { R = 196, G = 204, B = 187, A = 255 }); 47 | else if (value == "Bare") 48 | PolygonBrush = new SolidColorBrush(new Color() { R = 187, G = 187, B = 187, A = 255 }); 49 | else if (value == "Scorched") 50 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 153, B = 153, A = 255 }); 51 | else if (value == "Taiga") 52 | PolygonBrush = new SolidColorBrush(new Color() { R = 204, G = 212, B = 187, A = 255 }); 53 | else if (value == "Shrubland") 54 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 166, B = 139, A = 255 }); 55 | else if (value == "TemperateDesert") 56 | PolygonBrush = new SolidColorBrush(new Color() { R = 228, G = 232, B = 202, A = 255 }); 57 | else if (value == "TemperateRainForest") 58 | PolygonBrush = new SolidColorBrush(new Color() { R = 84, G = 116, B = 88, A = 255 }); 59 | else if (value == "TemperateDeciduousForest") 60 | PolygonBrush = new SolidColorBrush(new Color() { R = 119, G = 139, B = 85, A = 255 }); 61 | else if (value == "Grassland") 62 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 180, B = 112, A = 255 }); 63 | else if (value == "TropicalRainForest") 64 | PolygonBrush = new SolidColorBrush(new Color() { R = 112, G = 139, B = 85, A = 255 }); 65 | else if (value == "TropicalSeasonalForest") 66 | PolygonBrush = new SolidColorBrush(new Color() { R = 85, G = 139, B = 85, A = 255 }); 67 | else if (value == "SubtropicalDesert") 68 | PolygonBrush = new SolidColorBrush(new Color() { R = 172, G = 159, B = 139, A = 255 }); 69 | 70 | _biome = value; 71 | } 72 | } 73 | 74 | public SolidColorBrush PolygonBrush { get; set; } 75 | 76 | //public string Biome { get; set; } // biome type (see article) 77 | public double Elevation { get; set; } // 0.0-1.0 78 | public double Moisture { get; set; } // 0.0-1.0 79 | 80 | public HashSet
Neighbours { get; set; } 81 | public HashSet Borders { get; set; } 82 | public HashSet Corners { get; set; } 83 | 84 | public Center(double x , double y) 85 | { 86 | polyNorm = new Vector3D(0, 0, 0); 87 | Point = new Point(x,y); 88 | Key = Point.GetHashCode(); 89 | Index = Point.GetHashCode(); 90 | 91 | Water = Coast = Ocean = Border = false; 92 | Elevation = Moisture = 0.0d; 93 | 94 | Neighbours = new HashSet
(new CenterComparer()); 95 | Borders = new HashSet(new EdgeComparer()); 96 | Corners = new HashSet(new CornerComparer()); 97 | } 98 | 99 | #region Methods 100 | public bool Equals(Center other) 101 | { 102 | return this.Point == other.Point; 103 | } 104 | 105 | public void OrderCorners() 106 | { 107 | Corner CurrentCorner = Corners.First(); 108 | List Ordered = new List(); 109 | Corner newdot; 110 | Edge ed; 111 | 112 | Ordered.Add(CurrentCorner); 113 | do 114 | { 115 | ed = CurrentCorner.Protrudes.FirstOrDefault(x => Borders.Contains(x) && !(Ordered.Contains(x.VoronoiStart) && (Ordered.Contains(x.VoronoiEnd)))); 116 | 117 | if (ed != null) 118 | { 119 | newdot = ed.Corners.FirstOrDefault(x => !Ordered.Contains(x)); 120 | Ordered.Add(newdot); 121 | CurrentCorner = newdot; 122 | } 123 | } while (ed != null); 124 | 125 | Corners.Clear(); 126 | 127 | foreach (var corner in Ordered) 128 | { 129 | Corners.Add(corner); 130 | } 131 | } 132 | 133 | public void FixBorders() 134 | { 135 | var ms = from p in Borders.SelectMany(x => x.Corners) 136 | group p by p.Point 137 | into grouped 138 | select new {point = grouped.Key, count = grouped.Count()}; 139 | 140 | var fpoint = ms.FirstOrDefault(x => x.count == 1); 141 | var spoint = ms.LastOrDefault(x => x.count == 1); 142 | 143 | if(fpoint != null & spoint != null) 144 | { 145 | Corner p1 = Corners.FirstOrDefault(x => x.Point == fpoint.point); 146 | Corner p2 = Corners.FirstOrDefault(x => x.Point == spoint.point); 147 | 148 | if (p1 == null || p2 == null) 149 | return; 150 | 151 | IFactory fact = new MapItemFactory(); 152 | Edge e = fact.EdgeFactory( 153 | p1, 154 | p2, 155 | this, null); 156 | 157 | e.MapEdge = true; 158 | 159 | p1.Protrudes.Add(e); 160 | p2.Protrudes.Add(e); 161 | 162 | this.Border = this.Ocean = this.Water = true; 163 | e.VoronoiStart.Border = e.VoronoiEnd.Border = true; 164 | e.VoronoiStart.Elevation = e.VoronoiEnd.Elevation = 0.0d; 165 | 166 | this.Borders.Add(e); 167 | } 168 | } 169 | 170 | 171 | #endregion 172 | 173 | public void SetBiome() 174 | { 175 | if (Ocean && Elevation < -0.1d) 176 | { 177 | Biome = "Ocean"; 178 | } 179 | else 180 | if (Ocean && Elevation > -0.1d) 181 | { 182 | Biome = "ShallowWater"; 183 | } 184 | else if (Water) 185 | { 186 | if (Elevation < 0.1) Biome = "Marsh"; 187 | if (Elevation > 0.8) Biome = "Ice"; 188 | Biome = "Lake"; 189 | } 190 | else if (Coast) 191 | { 192 | Biome = "Beach"; 193 | } 194 | else if (Elevation > 0.8) 195 | { 196 | if (Moisture > 0.50) Biome = "Snow"; 197 | else if (Moisture > 0.33) Biome = "Tundra"; 198 | else if (Moisture > 0.16) Biome = "Bare"; 199 | else Biome = "Scorched"; 200 | } 201 | else if (Elevation > 0.6) 202 | { 203 | if (Moisture > 0.66) Biome = "Taiga"; 204 | else if (Moisture > 0.33) Biome = "Shrubland"; 205 | else Biome = "TemperateDesert"; 206 | } 207 | else if (Elevation > 0.3) 208 | { 209 | if (Moisture > 0.83) Biome = "TemperateRainForest"; 210 | else if (Moisture > 0.50) Biome = "TemperateDeciduousForest"; 211 | else if (Moisture > 0.16) Biome = "Grassland"; 212 | else Biome = "TemperateDesert"; 213 | } 214 | else 215 | { 216 | if (Moisture > 0.66) Biome = "TropicalRainForest"; 217 | else if (Moisture > 0.33) Biome = "TropicalSeasonalForest"; 218 | else if (Moisture > 0.16) Biome = "Grassland"; 219 | else Biome = "SubtropicalDesert"; 220 | } 221 | } 222 | 223 | 224 | 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Corner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | 5 | namespace BraveNewWorld.Models 6 | { 7 | public class Corner : IEquatable , IMapItem 8 | { 9 | public Corner(double ax, double ay) 10 | { 11 | Point = new Point(ax,ay); 12 | Key = Point.GetHashCode(); 13 | Index = Point.GetHashCode(); 14 | Ocean = Water = Coast = Border = false; 15 | Moisture = 0.0d; 16 | Elevation = 100.0d; 17 | 18 | Touches = new HashSet
(new CenterComparer()); 19 | Protrudes = new HashSet(new EdgeComparer()); 20 | Adjacents = new HashSet(new CornerComparer()); 21 | 22 | River = WatershedSize = 0; 23 | } 24 | 25 | public int Index { get; set; } 26 | 27 | public int Key { get; set; } 28 | public Point Point { get; set; } // location 29 | public Boolean Ocean { get; set; } // ocean 30 | public Boolean Water { get; set; } // lake or ocean 31 | public Boolean Land { get { return !Water; } set { Water = !value; } } // lake or ocean 32 | public Boolean Coast { get; set; } // touches ocean and land polygons 33 | public Boolean Border { get; set; } // at the edge of the map 34 | public double Elevation { get; set; } // 0.0-1.0 35 | public double Moisture { get; set; } // 0.0-1.0 36 | 37 | public HashSet
Touches { get; set; } 38 | public HashSet Protrudes { get; set; } 39 | public HashSet Adjacents { get; set; } 40 | 41 | public int River { get; set; } // 0 if no river, or volume of water in river 42 | public Corner Downslope { get; set; } // pointer to adjacent corner most downhill 43 | public Corner Watershed { get; set; } // pointer to coastal corner, or null 44 | public int WatershedSize { get; set; } 45 | 46 | public bool Equals(Corner other) 47 | { 48 | return this.Point.Equals(other.Point); 49 | } 50 | 51 | public void AddProtrudes(Edge edge) 52 | { 53 | Protrudes.Add(edge); 54 | } 55 | 56 | public void AddAdjacent(Corner corner) 57 | { 58 | Adjacents.Add(corner); 59 | } 60 | 61 | public void AddTouches(Center center) 62 | { 63 | Touches.Add(center); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Edge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | namespace BraveNewWorld.Models 5 | { 6 | public class Edge : IEquatable , IMapItem 7 | { 8 | public Edge(Corner begin, Corner end, Center left, Center right) 9 | { 10 | River = 0; 11 | VoronoiStart = begin; 12 | VoronoiEnd = end; 13 | 14 | DelaunayStart = left; 15 | DelaunayEnd = right; 16 | 17 | Midpoint = new Point((VoronoiStart.Point.X + VoronoiEnd.Point.X) / 2, (VoronoiStart.Point.Y + VoronoiEnd.Point.Y) / 2); 18 | Key = Midpoint.GetHashCode(); 19 | Index = Midpoint.GetHashCode(); 20 | } 21 | 22 | public Edge(int index, Corner begin, Corner end) 23 | { 24 | Index = index; 25 | River = 0; 26 | VoronoiStart = begin; 27 | VoronoiEnd = end; 28 | Midpoint = new Point((VoronoiStart.Point.X + VoronoiEnd.Point.X) / 2, (VoronoiStart.Point.Y + VoronoiEnd.Point.Y) / 2); 29 | Key = Midpoint.GetHashCode(); 30 | } 31 | 32 | public int Index { get; set; } 33 | 34 | public int Key { get; set; } 35 | public Center DelaunayStart { get; set; } 36 | public Center DelaunayEnd { get; set; }// Delaunay edge 37 | public Corner VoronoiStart { get; set; } 38 | public Corner VoronoiEnd { get; set; }// Voronoi edge 39 | public Point Midpoint { get; set; } // halfway between v0,v1 40 | public int River { get; set; } // volume of water, or 0 41 | public bool MapEdge = false; 42 | public Point Point { get { return VoronoiStart.Point; } } 43 | 44 | public bool Coast 45 | { 46 | get 47 | { 48 | if (DelaunayStart != null && DelaunayEnd != null) 49 | return ((VoronoiStart.Coast) && (VoronoiEnd.Coast) 50 | && !(DelaunayStart.Water && DelaunayEnd.Water) 51 | && !(DelaunayStart.Land && DelaunayEnd.Land)); 52 | return false; 53 | } 54 | 55 | set { } 56 | } 57 | 58 | public Corner[] Corners { get { return new Corner[] {VoronoiStart, VoronoiEnd}; } } 59 | 60 | public double DiffX { get { return VoronoiEnd.Point.X - VoronoiStart.Point.X; } } 61 | public double DiffY { get { return VoronoiEnd.Point.Y - VoronoiStart.Point.Y; } } 62 | 63 | public bool Equals(Edge other) 64 | { 65 | return this.VoronoiStart.Equals(other.VoronoiStart) && 66 | this.VoronoiEnd.Equals(other.VoronoiEnd); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Factory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | 5 | namespace BraveNewWorld.Models 6 | { 7 | class CenterComparer : IEqualityComparer
8 | { 9 | public CenterComparer() { } 10 | public bool Equals(Center x, Center y) 11 | { 12 | //return (x.Point.X == y.Point.X) && (x.Point.Y == y.Point.Y); 13 | return GetHashCode(x) == GetHashCode(y); 14 | } 15 | 16 | public int GetHashCode(Center obj) 17 | { 18 | return obj.Point.GetHashCode(); 19 | } 20 | } 21 | 22 | class CornerComparer : IEqualityComparer 23 | { 24 | public CornerComparer() { } 25 | public bool Equals(Corner x, Corner y) 26 | { 27 | return x.Point.Equals(y.Point); 28 | } 29 | 30 | public int GetHashCode(Corner obj) 31 | { 32 | return obj.Point.GetHashCode(); 33 | } 34 | } 35 | 36 | class EdgeComparer : IEqualityComparer 37 | { 38 | public EdgeComparer() { } 39 | public bool Equals(Edge x, Edge y) 40 | { 41 | return x.Midpoint == y.Midpoint; 42 | } 43 | 44 | public int GetHashCode(Edge obj) 45 | { 46 | return obj.Midpoint.GetHashCode(); 47 | } 48 | } 49 | 50 | public interface IFactory 51 | { 52 | Center CenterFactory(double ax, double ay); 53 | Edge EdgeFactory(Corner begin, Corner end, Center Left, Center Right); 54 | Corner CornerFactory(double ax, double ay); 55 | } 56 | 57 | public class MapItemFactory : IFactory 58 | { 59 | #region Implementation of IFactory 60 | 61 | public Center CenterFactory(double ax, double ay) 62 | { 63 | Point p = new Point(ax, ay); 64 | int hash = p.GetHashCode(); 65 | if(App.AppMap.Centers.ContainsKey(hash)) 66 | { 67 | return App.AppMap.Centers[hash]; 68 | } 69 | else 70 | { 71 | var nc = new Center(ax, ay); 72 | App.AppMap.Centers.Add(nc.Key, nc); 73 | return nc; 74 | } 75 | } 76 | 77 | public Edge EdgeFactory(Corner begin, Corner end, Center Left, Center Right) 78 | { 79 | Point p = new Point((begin.Point.X + end.Point.X) / 2, (begin.Point.Y + end.Point.Y) / 2); 80 | int hash = p.GetHashCode(); 81 | if (App.AppMap.Edges.ContainsKey(hash)) 82 | { 83 | return App.AppMap.Edges[hash]; 84 | } 85 | else 86 | { 87 | var nc = new Edge(begin,end,Left,Right); 88 | App.AppMap.Edges.Add(nc.Key, nc); 89 | return nc; 90 | } 91 | } 92 | 93 | public Corner CornerFactory(double ax, double ay) 94 | { 95 | Point p = new Point(ax, ay); 96 | int hash = p.GetHashCode(); 97 | if (App.AppMap.Corners.ContainsKey(hash)) 98 | { 99 | return App.AppMap.Corners[hash]; 100 | } 101 | else 102 | { 103 | var nc = new Corner(ax, ay); 104 | App.AppMap.Corners.Add(nc.Key, nc); 105 | return nc; 106 | } 107 | } 108 | 109 | #endregion 110 | 111 | public void RemoveEdge(Edge edge) 112 | { 113 | App.AppMap.Edges.Remove(edge.Midpoint.GetHashCode()); 114 | } 115 | 116 | public void RemoveCorner(Corner corner) 117 | { 118 | App.AppMap.Corners.Remove(corner.Point.GetHashCode()); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/IMapItem.cs: -------------------------------------------------------------------------------- 1 | namespace BraveNewWorld.Models 2 | { 3 | public interface IMapItem 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Map.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace BraveNewWorld.Models 4 | { 5 | public class Map 6 | { 7 | public Dictionary Centers { get; set; } 8 | public Dictionary Corners { get; set; } 9 | public Dictionary Edges { get; set; } 10 | 11 | public Map() 12 | { 13 | Centers = new Dictionary(); 14 | Corners = new Dictionary(); 15 | Edges = new Dictionary(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Models/Triangle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | 7 | namespace BraveNewWorld.Models 8 | { 9 | public class Triangle 10 | { 11 | public List Corners { get; set; } 12 | public List Edges { get; set; } 13 | public List Neightbours { get; set; } 14 | public Point Point { get; set; } 15 | public Center Parent { get; set; } 16 | 17 | public Triangle() 18 | { 19 | Corners = new List(); 20 | Edges = new List(); 21 | Neightbours = new List(); 22 | 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Services/IslandService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using System.Windows.Media.Media3D; 7 | using BraveNewWorld.Models; 8 | 9 | namespace BraveNewWorld.Services 10 | { 11 | public interface IIslandService 12 | { 13 | void CreateIsland(); 14 | } 15 | 16 | public class IslandService : IIslandService 17 | { 18 | private double MapMaxHeight = 0.0d; 19 | private double MapDeepest = 1.0d; 20 | private int MapX, MapY; 21 | 22 | 23 | public IslandService(int mapX, int mapY) 24 | { 25 | MapX = mapX; 26 | MapY = mapY; 27 | } 28 | 29 | public void CreateIsland() 30 | { 31 | foreach (var c in App.AppMap.Corners.Values) 32 | { 33 | c.Water = !InLand(c.Point); // calculate land&water corners 34 | } 35 | 36 | FixCentersFloodFillOceans(); 37 | 38 | foreach (var c in App.AppMap.Corners.Values) 39 | { 40 | c.Coast = (c.Touches.Any(x => x.Water) && c.Touches.Any(x => x.Land)) ? true : false; 41 | 42 | c.Water = (c.Touches.Any(x => x.Land)) ? false : true; 43 | 44 | c.Ocean = (c.Touches.All(x => x.Ocean)) ? true : false; 45 | } 46 | 47 | CalculateElevation(); 48 | 49 | RedistributeElevation(); 50 | 51 | CalculateDownslopes(); 52 | 53 | CalculateWatersheds(); 54 | 55 | CreateRivers(); 56 | 57 | CalculateCornerMoisture(); 58 | 59 | //RedistributeMoisture(); 60 | 61 | 62 | 63 | //Smooth1(); 64 | 65 | 66 | foreach (Center c in App.AppMap.Centers.Values) 67 | { 68 | c.Moisture = c.Corners.Sum(x => x.Moisture) / c.Corners.Count(); 69 | 70 | c.OrderCorners(); 71 | 72 | c.Elevation = c.Corners.Sum(x => x.Elevation) / c.Corners.Count; 73 | 74 | c.SetBiome(); 75 | } 76 | } 77 | 78 | private void RedistributeMoisture() 79 | { 80 | var locations = App.AppMap.Corners.Values.OrderBy(x => x.Moisture).ToArray(); 81 | 82 | for (int i = 0; i < locations.Count(); i++) 83 | { 84 | locations[i].Moisture = (float) i/(locations.Count() - 1); 85 | } 86 | } 87 | 88 | private void CalculateCornerMoisture() 89 | { 90 | var queue = new Queue(); 91 | 92 | foreach (var q in App.AppMap.Corners.Values) 93 | { 94 | if ((q.Water || q.River > 0) && !q.Ocean) 95 | { 96 | q.Moisture = q.River > 0 ? Math.Min(3.0, (0.2 * q.River)) : 1.0; 97 | queue.Enqueue(q); 98 | } 99 | else 100 | { 101 | q.Moisture = 0.0; 102 | } 103 | } 104 | 105 | while (queue.Count > 0) 106 | { 107 | var q = queue.Dequeue(); 108 | 109 | foreach (var r in q.Adjacents) 110 | { 111 | var newMoisture = q.Moisture * 0.9; 112 | if (newMoisture > r.Moisture) 113 | { 114 | r.Moisture = newMoisture; 115 | queue.Enqueue(r); 116 | } 117 | } 118 | } 119 | 120 | foreach (var q in App.AppMap.Corners.Values) 121 | { 122 | if (q.Ocean || q.Coast) 123 | { 124 | q.Moisture = 1.0; 125 | } 126 | } 127 | } 128 | 129 | private void CreateRivers() 130 | { 131 | for (int i = 0; i < MapX / 2; i++) 132 | { 133 | Corner q = App.AppMap.Corners.Values.ElementAt(App.Random.Next(0, App.AppMap.Corners.Values.Count - 1)); 134 | 135 | if (q.Ocean || q.Elevation < 0.3 || q.Elevation > 0.9) continue; 136 | 137 | while (!q.Coast) 138 | { 139 | if (q == q.Downslope) 140 | { 141 | break; 142 | } 143 | 144 | Edge edge = q.Protrudes.FirstOrDefault(ed => ed.VoronoiStart == q.Downslope || ed.VoronoiEnd == q.Downslope); 145 | edge.River = edge.River + 1; 146 | q.River = q.River + 1; 147 | q.Downslope.River = q.Downslope.River + 1; 148 | q = q.Downslope; 149 | } 150 | } 151 | } 152 | 153 | private void CalculateWatersheds() 154 | { 155 | 156 | foreach (var q in App.AppMap.Corners.Values) 157 | { 158 | q.Watershed = q; 159 | 160 | if (!q.Ocean && !q.Coast) 161 | { 162 | q.Watershed = q.Downslope; 163 | } 164 | } 165 | 166 | for (int i = 0; i < 100; i++) 167 | { 168 | var changed = false; 169 | 170 | foreach (var q in App.AppMap.Corners.Values) 171 | { 172 | if (!q.Ocean && !q.Coast && !q.Watershed.Coast) 173 | { 174 | var r = q.Downslope.Watershed; 175 | 176 | if (!r.Ocean) 177 | q.Watershed = r; 178 | 179 | changed = true; 180 | } 181 | } 182 | 183 | if (!changed) 184 | break; 185 | } 186 | 187 | foreach (var q in App.AppMap.Corners.Values) 188 | { 189 | var r = q.Watershed; 190 | r.WatershedSize = 1 + r.WatershedSize; 191 | } 192 | 193 | } 194 | 195 | private void CalculateDownslopes() 196 | { 197 | foreach (Corner corner in App.AppMap.Corners.Values) 198 | { 199 | var buf = corner; 200 | 201 | foreach (var adj in corner.Adjacents) 202 | { 203 | if (adj.Elevation <= buf.Elevation) 204 | { 205 | buf = adj; 206 | } 207 | } 208 | 209 | corner.Downslope = buf; 210 | } 211 | } 212 | 213 | private void RedistributeElevation() 214 | { 215 | double scaleFactor = 1.1; 216 | var locations = App.AppMap.Corners.Values.Where(x => !x.Ocean).OrderBy(x => x.Elevation).ToArray(); 217 | 218 | for (int i = 0; i < locations.Count(); i++) 219 | { 220 | double y = (double)i / (locations.Count() - 1); 221 | 222 | var x = 1.04880885 - Math.Sqrt(scaleFactor * (1 - y)); 223 | if (x > 1.0) 224 | x = 1.0; 225 | locations[i].Elevation = x; 226 | } 227 | } 228 | 229 | private void CalculateElevation() 230 | { 231 | var queue = new Queue(); 232 | 233 | foreach (var q in App.AppMap.Corners.Values) 234 | { 235 | if (q.Border) 236 | { 237 | q.Elevation = 0.0; 238 | queue.Enqueue(q); 239 | } 240 | else 241 | { 242 | q.Elevation = double.MaxValue; 243 | } 244 | } 245 | 246 | while (queue.Count > 0) 247 | { 248 | var corner = queue.Dequeue(); 249 | 250 | foreach (var adj in corner.Adjacents) 251 | { 252 | double newElevation = 0.01 + corner.Elevation; 253 | 254 | if (!corner.Water && !adj.Water) 255 | { 256 | newElevation += 1; 257 | } 258 | 259 | if (newElevation < adj.Elevation) 260 | { 261 | adj.Elevation = newElevation; 262 | queue.Enqueue(adj); 263 | } 264 | } 265 | } 266 | 267 | 268 | } 269 | 270 | 271 | private void Smooth1() 272 | { 273 | var ordered = new List(); 274 | var first = App.AppMap.Corners.Values.First(x => x.Coast && x.Touches.Any(z=>z.Ocean)); 275 | var start = first; 276 | ordered.Add(first); 277 | var next = first.Adjacents.First(x => x.Coast); 278 | 279 | while (next != start) 280 | { 281 | var nexte = next.Protrudes.FirstOrDefault(x => x.Coast && (x.VoronoiStart != ordered.Last() && x.VoronoiEnd != ordered.Last())); 282 | ordered.Add(next); 283 | next = nexte.VoronoiStart == next ? nexte.VoronoiEnd : nexte.VoronoiStart; 284 | } 285 | 286 | for (int a = 0; a < 2; a++) 287 | { 288 | for (int i = 2; i < ordered.Count - 2; i++) 289 | { 290 | ordered[i].Point = PointOnCurve(ordered[i - 2].Point, ordered[i - 1].Point, ordered[i + 1].Point, 291 | ordered[i + 2].Point, 0.5f); 292 | } 293 | } 294 | } 295 | 296 | public Point PointOnCurve(Point p0, Point p1, Point p2, Point p3, float t) 297 | { 298 | Point ret = new Point(); 299 | 300 | float t2 = t * t; 301 | float t3 = t2 * t; 302 | 303 | ret.X = 0.5f * ((2.0f * p1.X) + 304 | (-p0.X + p2.X) * t + 305 | (2.0f * p0.X - 5.0f * p1.X + 4 * p2.X - p3.X) * t2 + 306 | (-p0.X + 3.0f * p1.X - 3.0f * p2.X + p3.X) * t3); 307 | 308 | ret.Y = 0.5f * ((2.0f * p1.Y) + 309 | (-p0.Y + p2.Y) * t + 310 | (2.0f * p0.Y - 5.0f * p1.Y + 4 * p2.Y - p3.Y) * t2 + 311 | (-p0.Y + 3.0f * p1.Y - 3.0f * p2.Y + p3.Y) * t3); 312 | 313 | return ret; 314 | } 315 | 316 | private void FixCentersFloodFillOceans() 317 | { 318 | foreach (var ct in App.AppMap.Centers.Values) 319 | { 320 | ct.FixBorders(); //Fix edges at map border , set "border" and "ocean" values 321 | ct.OrderCorners(); //Order corners clockwise as we'Ll need it for polygons and 3d stuff 322 | 323 | //if it touches any water corner , it's water ; there will be leftovers tho 324 | ct.Water = (ct.Corners.Any(x => x.Water)) ? true : false; 325 | } 326 | 327 | var Oceans = new Queue
(); 328 | //start with oceans at the borders 329 | foreach (Center c in App.AppMap.Centers.Values.Where(c => c.Ocean)) 330 | { 331 | Oceans.Enqueue(c); 332 | } 333 | 334 | //floodfill oceans 335 | while (Oceans.Count > 0) 336 | { 337 | Center c = Oceans.Dequeue(); 338 | 339 | foreach (Center n in c.Neighbours.Where(x => !x.Ocean)) 340 | { 341 | if (n.Corners.Any(x => x.Water)) 342 | { 343 | n.Ocean = true; 344 | if (!Oceans.Contains(n)) 345 | Oceans.Enqueue(n); 346 | } 347 | else 348 | { 349 | n.Coast = true; 350 | } 351 | } 352 | } 353 | } 354 | 355 | private bool InLand(Point p) 356 | { 357 | return IsLandShape(new Point(2 * (p.X / MapX - 0.5), 2 * (p.Y / MapY - 0.5))); 358 | } 359 | 360 | private bool IsLandShape(Point point) 361 | { 362 | double ISLAND_FACTOR = 1.07; 363 | Random islandRandom = new Random(); 364 | int bumps = islandRandom.Next(1, 6); 365 | double startAngle = islandRandom.NextDouble() * 2 * Math.PI; 366 | double dipAngle = islandRandom.NextDouble() * 2 * Math.PI; 367 | double dipWidth = islandRandom.Next(2, 7) / 10; 368 | 369 | double angle = Math.Atan2(point.Y, point.X); 370 | double length = 0.5 * (Math.Max(Math.Abs(point.X), Math.Abs(point.Y)) + GetPointLength(point)); 371 | 372 | double r1 = 0.5 + 0.40 * Math.Sin(startAngle + bumps * angle + Math.Cos((bumps + 3) * angle)); 373 | double r2 = 0.7 - 0.20 * Math.Sin(startAngle + bumps * angle - Math.Sin((bumps + 2) * angle)); 374 | if (Math.Abs(angle - dipAngle) < dipWidth 375 | || Math.Abs(angle - dipAngle + 2 * Math.PI) < dipWidth 376 | || Math.Abs(angle - dipAngle - 2 * Math.PI) < dipWidth) 377 | { 378 | r1 = r2 = 0.2; 379 | } 380 | return (length < r1 || (length > r1 * ISLAND_FACTOR && length < r2)); 381 | } 382 | 383 | private double GetPointLength(Point point) 384 | { 385 | return Math.Sqrt((Math.Pow(point.X, 2)) + (Math.Pow(point.Y, 2))); 386 | } 387 | 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/BraveNewWorld/Services/MapService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using BenTools.Mathematics; 7 | using BraveNewWorld.Models; 8 | using Vector = BenTools.Mathematics.Vector; 9 | 10 | namespace BraveNewWorld.Services 11 | { 12 | //do I need this? meh 13 | public class LoadMapParams 14 | { 15 | public IEnumerable Points; 16 | public bool Fix; 17 | public int MapX; 18 | public int MapY; 19 | 20 | public LoadMapParams(IEnumerable points, bool fix = false) 21 | { 22 | Points = points; 23 | Fix = fix; 24 | } 25 | 26 | public LoadMapParams(IEnumerable points, bool fix, int mapX, int mapY) 27 | { 28 | Points = points; 29 | Fix = fix; 30 | MapX = mapX; 31 | MapY = mapY; 32 | } 33 | } 34 | 35 | public interface IMapService 36 | { 37 | void LoadMap(LoadMapParams loadMapParams); 38 | } 39 | 40 | public class MapService : IMapService 41 | { 42 | private int MapX, MapY; 43 | private IIslandService IslandHandler; 44 | 45 | public void LoadMap(LoadMapParams loadMapParams) 46 | { 47 | MapX = loadMapParams.MapX; 48 | MapY = loadMapParams.MapY; 49 | IslandHandler = new IslandService(MapX, MapY); 50 | 51 | VoronoiGraph voronoiMap = null; 52 | for (int i = 0; i < 3; i++) 53 | { 54 | voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points); 55 | foreach (Vector vector in loadMapParams.Points) 56 | { 57 | double v0 = 0.0d; 58 | double v1 = 0.0d; 59 | int say = 0; 60 | foreach (VoronoiEdge edge in voronoiMap.Edges) 61 | { 62 | if (edge.LeftData == vector || edge.RightData == vector) 63 | { 64 | double p0 = (edge.VVertexA[0] + edge.VVertexB[0]) / 2; 65 | double p1 = (edge.VVertexA[1] + edge.VVertexB[1]) / 2; 66 | v0 += double.IsNaN(p0) ? 0 : p0; 67 | v1 += double.IsNaN(p1) ? 0 : p1; 68 | say++; 69 | } 70 | } 71 | 72 | if (((v0 / say) < MapX) && ((v0 / say) > 0)) 73 | { 74 | vector[0] = v0 / say; 75 | } 76 | 77 | if (((v1 / say) < MapY) && ((v1 / say) > 0)) 78 | { 79 | vector[1] = v1 / say; 80 | } 81 | } 82 | } 83 | 84 | 85 | 86 | voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points); 87 | ImproveMapData(voronoiMap, loadMapParams.Fix); 88 | } 89 | 90 | private void ImproveMapData(VoronoiGraph voronoiMap, bool fix = false) 91 | { 92 | IFactory fact = new MapItemFactory(); 93 | 94 | foreach (VoronoiEdge edge in voronoiMap.Edges) 95 | { 96 | if (fix) 97 | { 98 | if (!FixPoints(edge)) 99 | continue; 100 | } 101 | 102 | Corner c1 = fact.CornerFactory(edge.VVertexA[0], edge.VVertexA[1]); 103 | Corner c2 = fact.CornerFactory(edge.VVertexB[0], edge.VVertexB[1]); 104 | Center cntrLeft = fact.CenterFactory(edge.LeftData[0], edge.LeftData[1]); 105 | Center cntrRight = fact.CenterFactory(edge.RightData[0], edge.RightData[1]); 106 | 107 | if(c1 == null || c2 == null) 108 | { 109 | 110 | } 111 | 112 | c1.AddAdjacent(c2); 113 | c2.AddAdjacent(c1); 114 | 115 | cntrRight.Corners.Add(c1); 116 | cntrRight.Corners.Add(c2); 117 | 118 | cntrLeft.Corners.Add(c1); 119 | cntrLeft.Corners.Add(c2); 120 | 121 | Edge e = fact.EdgeFactory(c1, c2, cntrLeft, cntrRight); 122 | 123 | 124 | cntrLeft.Borders.Add(e); 125 | cntrRight.Borders.Add(e); 126 | 127 | cntrLeft.Neighbours.Add(cntrRight); 128 | cntrRight.Neighbours.Add(cntrLeft); 129 | 130 | c1.AddProtrudes(e); 131 | c2.AddProtrudes(e); 132 | c1.AddTouches(cntrLeft); 133 | c1.AddTouches(cntrRight); 134 | c2.AddTouches(cntrLeft); 135 | c2.AddTouches(cntrRight); 136 | } 137 | 138 | foreach (Corner q in App.AppMap.Corners.Values) 139 | { 140 | if (!q.Border) 141 | { 142 | var point = new Point(0, 0); 143 | foreach (Center c in q.Touches) 144 | { 145 | point.X += c.Point.X; 146 | point.Y += c.Point.Y; 147 | } 148 | point.X = point.X / q.Touches.Count; 149 | point.Y = point.Y / q.Touches.Count; 150 | q.Point = point; 151 | } 152 | } 153 | 154 | //foreach (var c in App.AppMap.Centers) 155 | //{ 156 | // c.Value.FixBorders(); 157 | // c.SetEdgeAreas(); 158 | // c.Value.OrderCorners(); 159 | //} 160 | 161 | IslandHandler.CreateIsland(); 162 | } 163 | 164 | private bool FixPoints(VoronoiEdge edge) 165 | { 166 | double x1 = edge.VVertexA[0]; 167 | double y1 = edge.VVertexA[1]; 168 | 169 | double x2 = edge.VVertexB[0]; 170 | double y2 = edge.VVertexB[1]; 171 | 172 | 173 | 174 | //if both ends are in map, not much to do 175 | if ((DotInMap(x1, y1) && DotInMap(x2, y2))) 176 | return true; 177 | 178 | //if one end is out of map 179 | if ((DotInMap(x1, y1) && !DotInMap(x2, y2)) || (!DotInMap(x1, y1) && DotInMap(x2, y2))) 180 | { 181 | double b = 0.0d, slope = 0.0d; 182 | 183 | //and that point is actually a number ( not going to infinite ) 184 | if (!(double.IsNaN(x2) || double.IsNaN(y2))) 185 | { 186 | slope = ((y2 - y1) / (x2 - x1)); 187 | 188 | b = edge.VVertexA[1] - (slope * edge.VVertexA[0]); 189 | 190 | // y = ( slope * x ) + b 191 | 192 | 193 | if (edge.VVertexA[0] < 0) 194 | edge.VVertexA = new Vector(0, b); 195 | 196 | if (edge.VVertexA[0] > App.MapSize) 197 | edge.VVertexA = new Vector(App.MapSize, (App.MapSize * slope) + b); 198 | 199 | if (edge.VVertexA[1] < 0) 200 | edge.VVertexA = new Vector((-b / slope), 0); 201 | 202 | if (edge.VVertexA[1] > App.MapSize) 203 | edge.VVertexA = new Vector((App.MapSize - b) / slope, App.MapSize); 204 | 205 | 206 | 207 | if (edge.VVertexB[0] < 0) 208 | edge.VVertexB = new Vector(0, b); 209 | 210 | if (edge.VVertexB[0] > App.MapSize) 211 | edge.VVertexB = new Vector(App.MapSize, (App.MapSize * slope) + b); 212 | 213 | if (edge.VVertexB[1] < 0) 214 | edge.VVertexB = new Vector((-b / slope), 0); 215 | 216 | if (edge.VVertexB[1] > App.MapSize) 217 | edge.VVertexB = new Vector((App.MapSize - b) / slope, App.MapSize); 218 | 219 | } 220 | else 221 | { 222 | //and if that end is actually not a number ( going to infinite ) 223 | if (double.IsNaN(x2) || double.IsNaN(y2)) 224 | { 225 | var x3 = (edge.LeftData[0] + edge.RightData[0]) / 2; 226 | var y3 = (edge.LeftData[1] + edge.RightData[1]) / 2; 227 | 228 | slope = ((y3 - y1) / (x3 - x1)); 229 | 230 | slope = Math.Abs(slope); 231 | 232 | b = edge.VVertexA[1] - (slope * edge.VVertexA[0]); 233 | 234 | // y = ( slope * x ) + b 235 | var i = 0.0d; 236 | 237 | if(x3 < y3) 238 | { 239 | if(App.MapSize - x3 > y3) 240 | { 241 | i = b; 242 | if (i > 0 && i < MapY) 243 | edge.VVertexB = new Vector(0, i); 244 | 245 | } 246 | else 247 | { 248 | i = (MapX - b) / slope; 249 | if (i > 0 && i < MapY) 250 | edge.VVertexB = new Vector(i, MapY); 251 | 252 | } 253 | } 254 | else 255 | { 256 | if (MapX - x3 > y3) 257 | { 258 | i = (-b / slope); 259 | if (i > 0 && i < MapX) 260 | edge.VVertexB = new BenTools.Mathematics.Vector(i, 0); 261 | } 262 | else 263 | { 264 | i = (MapY * slope) + b; 265 | if (i > 0 && i < MapX) 266 | edge.VVertexB = new BenTools.Mathematics.Vector(MapX, i); 267 | 268 | } 269 | } 270 | } 271 | } 272 | return true; 273 | } 274 | return false; 275 | } 276 | 277 | private bool DotInMap(double x, double y) 278 | { 279 | if (x == double.NaN || y == double.NaN) 280 | return false; 281 | 282 | return (x > 0 && x < MapX) && (y > 0 && y < MapY); 283 | } 284 | 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | using System; 10 | using System.Reflection; 11 | using System.Runtime.CompilerServices; 12 | using System.Runtime.InteropServices; 13 | 14 | // Information about this assembly is defined by the following attributes. 15 | // Change them to the values specific to your project. 16 | 17 | [assembly: AssemblyTitle("FortuneVoronoi")] 18 | [assembly: AssemblyDescription("")] 19 | [assembly: AssemblyConfiguration("")] 20 | [assembly: AssemblyCompany("Taffer")] 21 | [assembly: AssemblyProduct("")] 22 | [assembly: AssemblyCopyright("Free to use, copy, fork, etc. but don't blame me if it breaks.")] 23 | [assembly: AssemblyTrademark("")] 24 | [assembly: AssemblyCulture("")] 25 | 26 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 27 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 28 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 29 | 30 | [assembly: AssemblyVersion("1.0.*")] 31 | 32 | // The following attributes are used to specify the signing key for the assembly, 33 | // if desired. See the Mono documentation for more information about signing. 34 | 35 | //[assembly: AssemblyDelaySign(false)] 36 | //[assembly: AssemblyKeyFile("")] 37 | 38 | // Must be false due to UnityEngine. 39 | [assembly: CLSCompliant(false)] 40 | [assembly: ComVisible(false)] 41 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/Fortune.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | using System.Collections; 13 | 14 | using NGenerics.DataStructures.Mathematical; 15 | using NGenerics.DataStructures.Queues; 16 | 17 | // VoronoiVertex or VoronoiDataPoint are represented as Vector 18 | 19 | public abstract class Fortune 20 | { 21 | /// 22 | /// The VV infinite. 23 | /// 24 | public static readonly Vector2D VVInfinite = new Vector2D(double.PositiveInfinity, double.PositiveInfinity); 25 | /// 26 | /// The VV unkown. 27 | /// 28 | public static readonly Vector2D VVUnkown = new Vector2D(double.NaN, double.NaN); 29 | 30 | internal static double ParabolicCut(double x1, double y1, double x2, double y2, double ys) 31 | { 32 | if(Math.Abs(x1-x2)<1e-10 && Math.Abs(y1-y2)<1e-10) 33 | { 34 | throw new Exception("Identical datapoints are not allowed!"); 35 | } 36 | 37 | if(Math.Abs(y1-ys)<1e-10 && Math.Abs(y2-ys)<1e-10) { 38 | return (x1+x2)/2; 39 | } 40 | 41 | if(Math.Abs(y1-ys)<1e-10) { 42 | return x1; 43 | } 44 | 45 | if(Math.Abs(y2-ys)<1e-10) { 46 | return x2; 47 | } 48 | 49 | double a1 = 1/(2*(y1-ys)); 50 | double a2 = 1/(2*(y2-ys)); 51 | if(Math.Abs(a1-a2)<1e-10) { 52 | return (x1+x2)/2; 53 | } 54 | 55 | double xs1 = (double)(0.5/(2*a1-2*a2)*(4*a1*x1-4*a2*x2+2*Math.Sqrt(-8*a1*x1*a2*x2-2*a1*y1+2*a1*y2+4*a1*a2*x2*x2+2*a2*y1+4*a2*a1*x1*x1-2*a2*y2))); 56 | double xs2 = (double)(0.5/(2*a1-2*a2)*(4*a1*x1-4*a2*x2-2*Math.Sqrt(-8*a1*x1*a2*x2-2*a1*y1+2*a1*y2+4*a1*a2*x2*x2+2*a2*y1+4*a2*a1*x1*x1-2*a2*y2))); 57 | xs1=(double)Math.Round(xs1,10); 58 | xs2=(double)Math.Round(xs2,10); 59 | if(xs1>xs2) 60 | { 61 | double h = xs1; 62 | xs1=xs2; 63 | xs2=h; 64 | } 65 | 66 | if(y1>=y2) { 67 | return xs2; 68 | } 69 | 70 | return xs1; 71 | } 72 | 73 | internal static Vector2D CircumCircleCenter(Vector2D A, Vector2D B, Vector2D C) 74 | { 75 | if(A==B || B==C || A==C) { 76 | throw new Exception("Need three different points!"); 77 | } 78 | 79 | double tx = (A.X + C.X)/2; 80 | double ty = (A.Y + C.Y)/2; 81 | 82 | double vx = (B.X + C.X)/2; 83 | double vy = (B.Y + C.Y)/2; 84 | 85 | double ux,uy,wx,wy; 86 | 87 | if(A.X == C.X) 88 | { 89 | ux = 1; 90 | uy = 0; 91 | } 92 | else 93 | { 94 | ux = (C.Y - A.Y)/(A.X - C.X); 95 | uy = 1; 96 | } 97 | 98 | if(B.X == C.X) 99 | { 100 | wx = -1; 101 | wy = 0; 102 | } 103 | else 104 | { 105 | wx = (B.Y - C.Y)/(B.X - C.X); 106 | wy = -1; 107 | } 108 | 109 | double alpha = (wy*(vx-tx)-wx*(vy - ty))/(ux*wy-wx*uy); 110 | 111 | return new Vector2D(tx+alpha*ux,ty+alpha*uy); 112 | } 113 | 114 | /// 115 | /// Computes the voronoi graph. 116 | /// 117 | /// 118 | /// The voronoi graph. 119 | /// 120 | /// 121 | /// Datapoints. 122 | /// 123 | /// 124 | /// Represents errors that occur during application execution. 125 | /// 126 | public static VoronoiGraph ComputeVoronoiGraph(IEnumerable Datapoints) 127 | { 128 | PriorityQueue PQ = new PriorityQueue(PriorityQueueType.Minimum); 129 | Hashtable CurrentCircles = new Hashtable(); 130 | VoronoiGraph VG = new VoronoiGraph(); 131 | VNode RootNode = null; 132 | 133 | foreach(Vector2D V in Datapoints) 134 | { 135 | PQ.Enqueue(new VDataEvent(V)); 136 | } 137 | 138 | while(PQ.Count>0) 139 | { 140 | VEvent VE = PQ.Dequeue() as VEvent; 141 | VDataNode[] CircleCheckList; 142 | 143 | if(VE is VDataEvent) 144 | { 145 | RootNode = VNode.ProcessDataEvent(VE as VDataEvent,RootNode,VG,VE.Y,out CircleCheckList); 146 | } 147 | else if(VE is VCircleEvent) 148 | { 149 | CurrentCircles.Remove(((VCircleEvent)VE).NodeN); 150 | if(!((VCircleEvent)VE).Valid) 151 | continue; 152 | RootNode = VNode.ProcessCircleEvent(VE as VCircleEvent,RootNode,VG,VE.Y,out CircleCheckList); 153 | } 154 | else { 155 | throw new Exception("Got event of type "+VE.GetType().ToString()+"!"); 156 | } 157 | 158 | foreach(VDataNode VD in CircleCheckList) 159 | { 160 | if(CurrentCircles.ContainsKey(VD)) 161 | { 162 | ((VCircleEvent)CurrentCircles[VD]).Valid=false; 163 | CurrentCircles.Remove(VD); 164 | } 165 | 166 | VCircleEvent VCE = VNode.CircleCheckDataNode(VD,VE.Y); 167 | if(VCE!=null) 168 | { 169 | PQ.Enqueue(VCE); 170 | CurrentCircles[VD]=VCE; 171 | } 172 | } 173 | 174 | if(VE is VDataEvent) 175 | { 176 | Vector2D DP = ((VDataEvent)VE).DataPoint; 177 | foreach(VCircleEvent VCE in CurrentCircles.Values) 178 | { 179 | if(MathTools.Dist(DP.X,DP.Y,VCE.Center.X,VCE.Center.Y)1e-10) { 180 | VCE.Valid = false; 181 | } 182 | } 183 | } 184 | } 185 | 186 | return VG; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/FortuneVoronoi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.0 7 | 2.0 8 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A} 9 | Library 10 | BenDi.FortuneVoronoi 11 | BenDi.FortuneVoronoi 12 | Fortune's Voronoi algorithm, based on code by BenDi on Code Project: 13 | http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug 21 | DEBUG; 22 | prompt 23 | 4 24 | false 25 | true 26 | AllRules.ruleset 27 | true 28 | 29 | 30 | none 31 | false 32 | bin\Release 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | lib\NGenerics.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click 8 | // "In Project Suppression File". 9 | // You do not need to add suppressions to this file manually. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Di", Scope = "namespace", Target = "BenDi.FortuneVoronoi", Justification="Original author's handle." )] 12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Voronoi", Scope = "namespace", Target = "BenDi.FortuneVoronoi", Justification="That's the correct spelling." )] 13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification="It's not mine, I'm not signing it." )] 14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Di", Justification="Original author's handle." )] 15 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Voronoi", Justification="That's the correct spelling." )] 16 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Scope = "type", Target = "BenDi.FortuneVoronoi.BinaryPriorityQueue", Justification="A queue is a collection." )] 17 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope = "type", Target = "BenDi.FortuneVoronoi.BinaryPriorityQueue", Justification="A queue is a collection." )] 18 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/ToolBox.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | using System.Collections; 13 | using System.IO; 14 | using System.Text; 15 | using System.Drawing; 16 | 17 | public abstract class MathTools 18 | { 19 | /// 20 | /// Dist the specified x1, y1, x2 and y2. 21 | /// 22 | /// 23 | /// X1. 24 | /// 25 | /// 26 | /// Y1. 27 | /// 28 | /// 29 | /// X2. 30 | /// 31 | /// 32 | /// Y2. 33 | /// 34 | public static double Dist(double x1, double y1, double x2, double y2) 35 | { 36 | return (double)Math.Sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); 37 | } 38 | 39 | /// 40 | /// Ccw the specified P0x, P0y, P1x, P1y, P2x, P2y and PlusOneOnZeroDegrees. 41 | /// 42 | /// 43 | /// P0x. 44 | /// 45 | /// 46 | /// P0y. 47 | /// 48 | /// 49 | /// P1x. 50 | /// 51 | /// 52 | /// P1y. 53 | /// 54 | /// 55 | /// P2x. 56 | /// 57 | /// 58 | /// P2y. 59 | /// 60 | /// 61 | /// Plus one on zero degrees. 62 | /// 63 | public static int ccw(double P0x, double P0y, double P1x, double P1y, double P2x, double P2y, bool PlusOneOnZeroDegrees) 64 | { 65 | double dx1, dx2, dy1, dy2; 66 | 67 | dx1 = P1x - P0x; 68 | dy1 = P1y - P0y; 69 | dx2 = P2x - P0x; 70 | dy2 = P2y - P0y; 71 | 72 | if (dx1*dy2 > dy1*dx2) { 73 | return +1; 74 | } 75 | 76 | if (dx1*dy2 < dy1*dx2) { 77 | return -1; 78 | } 79 | 80 | if ((dx1*dx2 < 0) || (dy1*dy2 < 0)) { 81 | return -1; 82 | } 83 | 84 | if ((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2) && PlusOneOnZeroDegrees) { 85 | return +1; 86 | } 87 | 88 | return 0; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VCircleEvent.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | using NGenerics.DataStructures.Mathematical; 14 | 15 | internal class VCircleEvent : VEvent 16 | { 17 | /// 18 | /// The node n. 19 | /// 20 | public VDataNode NodeN; 21 | 22 | /// 23 | /// The node l. 24 | /// 25 | public VDataNode NodeL; 26 | 27 | /// 28 | /// The node r. 29 | /// 30 | public VDataNode NodeR; 31 | 32 | /// 33 | /// The center. 34 | /// 35 | public Vector2D Center; 36 | 37 | /// 38 | /// The valid. 39 | /// 40 | public bool Valid = true; 41 | 42 | /// 43 | /// Gets the y. 44 | /// 45 | /// 46 | /// The y. 47 | /// 48 | public override double Y { 49 | get { 50 | return Math.Round( Center.Y + MathTools.Dist( NodeN.DataPoint.X, NodeN.DataPoint.Y, Center.X, Center.Y ), 10 ); 51 | } 52 | } 53 | 54 | /// 55 | /// Gets the x. 56 | /// 57 | /// 58 | /// The x. 59 | /// 60 | public override double X { 61 | get { 62 | return Center.X; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VDataEvent.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | using NGenerics.DataStructures.Mathematical; 14 | 15 | internal class VDataEvent : VEvent 16 | { 17 | /// 18 | /// The data point. 19 | /// 20 | public Vector2D DataPoint; 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// 26 | /// D. 27 | /// 28 | public VDataEvent( Vector2D DP ) 29 | { 30 | this.DataPoint = DP; 31 | } 32 | 33 | /// 34 | /// Gets the y. 35 | /// 36 | /// 37 | /// The y. 38 | /// 39 | public override double Y { 40 | get { 41 | return DataPoint.Y; 42 | } 43 | } 44 | 45 | /// 46 | /// Gets the x. 47 | /// 48 | /// 49 | /// The x. 50 | /// 51 | public override double X { 52 | get { 53 | return DataPoint.X; 54 | } 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VDataNode.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | using NGenerics.DataStructures.Mathematical; 14 | 15 | internal class VDataNode : VNode 16 | { 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// 21 | /// D. 22 | /// 23 | public VDataNode( Vector2D DP ) 24 | { 25 | this.DataPoint = DP; 26 | } 27 | 28 | /// 29 | /// The data point. 30 | /// 31 | public Vector2D DataPoint; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VEdgeNode.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | internal class VEdgeNode : VNode 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// 19 | /// E. 20 | /// 21 | /// 22 | /// Flipped. 23 | /// 24 | public VEdgeNode( VoronoiEdge E, bool Flipped ) 25 | { 26 | this.Edge = E; 27 | this.Flipped = Flipped; 28 | } 29 | 30 | /// 31 | /// The edge. 32 | /// 33 | public VoronoiEdge Edge; 34 | 35 | /// 36 | /// The flipped. 37 | /// 38 | public bool Flipped; 39 | 40 | /// 41 | /// Cut the specified ys and x. 42 | /// 43 | /// 44 | /// Ys. 45 | /// 46 | /// 47 | /// X. 48 | /// 49 | public double Cut( double ys, double x ) 50 | { 51 | if( !Flipped ) { 52 | return (double)Math.Round( x - Fortune.ParabolicCut( Edge.LeftData.X, Edge.LeftData.Y, Edge.RightData.X, Edge.RightData.Y, ys ) ); 53 | } 54 | 55 | return (double)Math.Round( x - Fortune.ParabolicCut( Edge.RightData.X, Edge.RightData.Y, Edge.LeftData.X, Edge.LeftData.Y, ys ) ); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VEvent.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | internal abstract class VEvent : IComparable 14 | { 15 | /// 16 | /// Gets the y. 17 | /// 18 | /// 19 | /// The y. 20 | /// 21 | public abstract double Y { get; } 22 | 23 | /// 24 | /// Gets the x. 25 | /// 26 | /// 27 | /// The x. 28 | /// 29 | public abstract double X { get; } 30 | 31 | #region IComparable Members 32 | 33 | /// 34 | /// Compares to a VEvent. 35 | /// 36 | /// 37 | /// The to. 38 | /// 39 | /// 40 | /// Object. 41 | /// 42 | /// 43 | /// Is thrown when an argument passed to a method is invalid. 44 | /// 45 | public int CompareTo( object obj ) 46 | { 47 | VEvent vObj = obj as VEvent; 48 | 49 | if( vObj == null ) { 50 | throw new ArgumentException( "obj not VEvent!" ); 51 | } 52 | 53 | int i = Y.CompareTo( vObj.Y ); 54 | if( i != 0 ) { 55 | return i; 56 | } 57 | 58 | return X.CompareTo( vObj.X ); 59 | } 60 | 61 | #endregion 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VNode.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | using NGenerics.DataStructures.Mathematical; 14 | 15 | internal abstract class VNode 16 | { 17 | private VNode _Parent = null; 18 | 19 | private VNode _Left = null; 20 | 21 | private VNode _Right = null; 22 | 23 | /// 24 | /// Gets or sets the left. 25 | /// 26 | /// 27 | /// The left. 28 | /// 29 | public VNode Left { 30 | get { 31 | return _Left; 32 | } 33 | 34 | set { 35 | _Left = value; 36 | value.Parent = this; 37 | } 38 | } 39 | 40 | /// 41 | /// Gets or sets the right. 42 | /// 43 | /// 44 | /// The right. 45 | /// 46 | public VNode Right { 47 | get { 48 | return _Right; 49 | } 50 | 51 | set { 52 | _Right = value; 53 | value.Parent = this; 54 | } 55 | } 56 | 57 | /// 58 | /// Gets or sets the parent. 59 | /// 60 | /// 61 | /// The parent. 62 | /// 63 | public VNode Parent { 64 | get { 65 | return _Parent; 66 | } 67 | 68 | set { 69 | _Parent = value; 70 | } 71 | } 72 | 73 | /// 74 | /// Replace the specified ChildOld and ChildNew. 75 | /// 76 | /// 77 | /// Child old. 78 | /// 79 | /// 80 | /// Child new. 81 | /// 82 | /// 83 | /// Represents errors that occur during application execution. 84 | /// 85 | public void Replace( VNode ChildOld, VNode ChildNew ) 86 | { 87 | if( Left == ChildOld ) { 88 | Left = ChildNew; 89 | } 90 | else if( Right == ChildOld ) { 91 | Right = ChildNew; 92 | } 93 | else { 94 | throw new Exception( "Child not found!" ); 95 | } 96 | 97 | ChildOld.Parent = null; 98 | } 99 | 100 | /// 101 | /// Firsts the data node. 102 | /// 103 | /// 104 | /// The data node. 105 | /// 106 | /// 107 | /// Root. 108 | /// 109 | public static VDataNode FirstDataNode( VNode Root ) 110 | { 111 | VNode C = Root; 112 | while( C.Left!=null ) { 113 | C = C.Left; 114 | } 115 | 116 | return C as VDataNode; 117 | } 118 | 119 | /// 120 | /// Lefts the data node. 121 | /// 122 | /// 123 | /// The data node. 124 | /// 125 | /// 126 | /// Current. 127 | /// 128 | public static VDataNode LeftDataNode( VDataNode Current ) 129 | { 130 | VNode C = Current; 131 | 132 | //1. Up 133 | do { 134 | if( C.Parent == null ) { 135 | return null; 136 | } 137 | if( C.Parent.Left == C ) { 138 | C = C.Parent; 139 | continue; 140 | } else { 141 | C = C.Parent; 142 | break; 143 | } 144 | } while(true); 145 | 146 | //2. One Left 147 | C = C.Left; 148 | 149 | //3. Down 150 | while( C.Right != null ) { 151 | C = C.Right; 152 | } 153 | 154 | return C as VDataNode; // Cast statt 'as' damit eine Exception kommt 155 | } 156 | 157 | /// 158 | /// Rights the data node. 159 | /// 160 | /// 161 | /// The data node. 162 | /// 163 | /// 164 | /// Current. 165 | /// 166 | public static VDataNode RightDataNode( VDataNode Current ) 167 | { 168 | VNode C = Current; 169 | 170 | //1. Up 171 | do { 172 | if( C.Parent == null ) { 173 | return null; 174 | } 175 | if( C.Parent.Right == C ) { 176 | C = C.Parent; 177 | continue; 178 | } else { 179 | C = C.Parent; 180 | break; 181 | } 182 | } while(true); 183 | 184 | //2. One Right 185 | C = C.Right; 186 | 187 | //3. Down 188 | while( C.Left != null ) { 189 | C = C.Left; 190 | } 191 | 192 | return C as VDataNode; // Cast statt 'as' damit eine Exception kommt 193 | } 194 | 195 | /// 196 | /// Edges to right data node. 197 | /// 198 | /// 199 | /// The to right data node. 200 | /// 201 | /// 202 | /// Current. 203 | /// 204 | /// 205 | /// Represents errors that occur during application execution. 206 | /// 207 | public static VEdgeNode EdgeToRightDataNode( VDataNode Current ) 208 | { 209 | VNode C = Current; 210 | 211 | //1. Up 212 | do { 213 | if( C.Parent == null ) { 214 | throw new Exception( "No Left Leaf found!" ); 215 | } 216 | if( C.Parent.Right == C ) { 217 | C = C.Parent; 218 | continue; 219 | } else { 220 | C = C.Parent; 221 | break; 222 | } 223 | } while(true); 224 | 225 | return C as VEdgeNode; 226 | } 227 | 228 | /// 229 | /// Finds the data node. 230 | /// 231 | /// 232 | /// The data node. 233 | /// 234 | /// 235 | /// Root. 236 | /// 237 | /// 238 | /// Ys. 239 | /// 240 | /// 241 | /// X. 242 | /// 243 | /// 244 | /// Represents errors that occur during application execution. 245 | /// 246 | public static VDataNode FindDataNode( VNode Root, double ys, double x ) 247 | { 248 | VNode C = Root; 249 | 250 | do { 251 | if( C is VDataNode ) { 252 | return C as VDataNode; 253 | } 254 | 255 | VEdgeNode cEdge = C as VEdgeNode; 256 | if( cEdge == null ) { 257 | throw new Exception( "Can't cast to edge node" ); 258 | } 259 | if( cEdge.Cut( ys, x ) < 0 ) { 260 | C = C.Left; 261 | } 262 | else { 263 | C = C.Right; 264 | } 265 | } while(true); 266 | } 267 | 268 | /// 269 | /// Will return the new root (unchanged except in start-up) 270 | /// 271 | /// 272 | /// Processes the data event. 273 | /// 274 | /// 275 | /// The data event. 276 | /// 277 | /// 278 | /// E. 279 | /// 280 | /// 281 | /// Root. 282 | /// 283 | /// 284 | /// V. 285 | /// 286 | /// 287 | /// Ys. 288 | /// 289 | /// 290 | /// Circle check list. 291 | /// 292 | /// 293 | /// Represents errors that occur during application execution. 294 | /// 295 | public static VNode ProcessDataEvent( VDataEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList ) 296 | { 297 | if( Root == null ) { 298 | Root = new VDataNode( e.DataPoint ); 299 | CircleCheckList = new VDataNode[] {Root as VDataNode}; 300 | return Root; 301 | } 302 | 303 | //1. Find the node to be replaced 304 | VNode C = VNode.FindDataNode( Root, ys, e.DataPoint.X ); 305 | VDataNode cData = C as VDataNode; 306 | 307 | if( cData == null ) { 308 | throw new Exception( "Can't cast to data node" ); 309 | } 310 | 311 | //2. Create the subtree (ONE Edge, but two VEdgeNodes) 312 | VoronoiEdge VE = new VoronoiEdge(); 313 | VE.LeftData = cData.DataPoint; 314 | VE.RightData = e.DataPoint; 315 | VE.VVertexA = Fortune.VVUnkown; 316 | VE.VVertexB = Fortune.VVUnkown; 317 | VG.Edges.Add( VE ); 318 | 319 | VNode SubRoot; 320 | if( Math.Abs( VE.LeftData.Y - VE.RightData.Y ) < 1e-10 ) { 321 | if( VE.LeftData.X < VE.RightData.X ) { 322 | SubRoot = new VEdgeNode( VE, false ); 323 | SubRoot.Left = new VDataNode( VE.LeftData ); 324 | SubRoot.Right = new VDataNode( VE.RightData ); 325 | } else { 326 | SubRoot = new VEdgeNode( VE, true ); 327 | SubRoot.Left = new VDataNode( VE.RightData ); 328 | SubRoot.Right = new VDataNode( VE.LeftData ); 329 | } 330 | 331 | CircleCheckList = new VDataNode[] {SubRoot.Left as VDataNode, SubRoot.Right as VDataNode}; 332 | } else { 333 | SubRoot = new VEdgeNode( VE, false ); 334 | SubRoot.Left = new VDataNode( VE.LeftData ); 335 | SubRoot.Right = new VEdgeNode( VE, true ); 336 | SubRoot.Right.Left = new VDataNode( VE.RightData ); 337 | SubRoot.Right.Right = new VDataNode( VE.LeftData ); 338 | CircleCheckList = new VDataNode[] {SubRoot.Left as VDataNode, SubRoot.Right.Left as VDataNode, SubRoot.Right.Right as VDataNode}; 339 | } 340 | 341 | //3. Apply subtree 342 | if( C.Parent == null ) { 343 | return SubRoot; 344 | } 345 | 346 | C.Parent.Replace( C, SubRoot ); 347 | 348 | return Root; 349 | } 350 | 351 | /// 352 | /// Processes the circle event. 353 | /// 354 | /// 355 | /// The circle event. 356 | /// 357 | /// 358 | /// E. 359 | /// 360 | /// 361 | /// Root. 362 | /// 363 | /// 364 | /// V. 365 | /// 366 | /// 367 | /// Ys. 368 | /// 369 | /// 370 | /// Circle check list. 371 | /// 372 | public static VNode ProcessCircleEvent( VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList ) 373 | { 374 | VDataNode a; 375 | VDataNode b; 376 | VDataNode c; 377 | VEdgeNode eu; 378 | VEdgeNode eo; 379 | 380 | b = e.NodeN; 381 | a = VNode.LeftDataNode( b ); 382 | c = VNode.RightDataNode( b ); 383 | if( a == null || b.Parent == null || c == null || !a.DataPoint.Equals( e.NodeL.DataPoint ) || !c.DataPoint.Equals( e.NodeR.DataPoint ) ) { 384 | CircleCheckList = new VDataNode[]{}; 385 | 386 | return Root; // Abbruch da sich der Graph ver 0/00ndert hat 387 | } 388 | 389 | eu = b.Parent as VEdgeNode; 390 | CircleCheckList = new VDataNode[] {a,c}; 391 | 392 | //1. Create the new Vertex 393 | Vector2D VNew = new Vector2D( e.Center.X, e.Center.Y ); 394 | 395 | VG.Vertizes.Add( VNew ); 396 | 397 | //2. Find out if a or c are in a distand part of the tree (the other is then b's sibling) and assign the new vertex 398 | if( eu.Left == b ) { // c is sibling 399 | eo = VNode.EdgeToRightDataNode( a ); 400 | 401 | // replace eu by eu's Right 402 | eu.Parent.Replace( eu, eu.Right ); 403 | } else { // a is sibling 404 | eo = VNode.EdgeToRightDataNode( b ); 405 | 406 | // replace eu by eu's Left 407 | eu.Parent.Replace( eu, eu.Left ); 408 | } 409 | 410 | eu.Edge.AddVertex( VNew ); 411 | eo.Edge.AddVertex( VNew ); 412 | 413 | //2. Replace eo by new Edge 414 | VoronoiEdge VE = new VoronoiEdge(); 415 | VE.LeftData = a.DataPoint; 416 | VE.RightData = c.DataPoint; 417 | VE.AddVertex( VNew ); 418 | VG.Edges.Add( VE ); 419 | 420 | VEdgeNode VEN = new VEdgeNode( VE, false ); 421 | VEN.Left = eo.Left; 422 | VEN.Right = eo.Right; 423 | if( eo.Parent == null ) { 424 | return VEN; 425 | } 426 | 427 | eo.Parent.Replace( eo, VEN ); 428 | 429 | return Root; 430 | } 431 | 432 | /// 433 | /// Circles the check data node. 434 | /// 435 | /// 436 | /// The check data node. 437 | /// 438 | /// 439 | /// N. 440 | /// 441 | /// 442 | /// Ys. 443 | /// 444 | public static VCircleEvent CircleCheckDataNode( VDataNode n, double ys ) 445 | { 446 | VDataNode l = VNode.LeftDataNode( n ); 447 | VDataNode r = VNode.RightDataNode( n ); 448 | if( l == null || r == null || l.DataPoint == r.DataPoint || l.DataPoint == n.DataPoint || n.DataPoint == r.DataPoint ) { 449 | return null; 450 | } 451 | 452 | if( MathTools.ccw( l.DataPoint.X, l.DataPoint.Y, n.DataPoint.X, n.DataPoint.Y, r.DataPoint.X, r.DataPoint.Y, false ) <= 0 ) { 453 | return null; 454 | } 455 | 456 | Vector2D Center = Fortune.CircumCircleCenter( l.DataPoint, n.DataPoint, r.DataPoint ); 457 | VCircleEvent VC = new VCircleEvent(); 458 | VC.NodeN = n; 459 | VC.NodeL = l; 460 | VC.NodeR = r; 461 | VC.Center = Center; 462 | VC.Valid = true; 463 | if( VC.Y >= ys ) { 464 | return VC; 465 | } 466 | 467 | return null; 468 | } 469 | } 470 | } 471 | 472 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VoronoiEdge.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | 13 | using NGenerics.DataStructures.Mathematical; 14 | 15 | public class VoronoiEdge 16 | { 17 | /// 18 | /// The right data. 19 | /// 20 | public Vector2D RightData; 21 | 22 | /// 23 | /// The left data. 24 | /// 25 | public Vector2D LeftData; 26 | 27 | /// 28 | /// The V vertex a. 29 | /// 30 | public Vector2D VVertexA = Fortune.VVUnkown; 31 | 32 | /// 33 | /// The V vertex b. 34 | /// 35 | public Vector2D VVertexB = Fortune.VVUnkown; 36 | 37 | /// 38 | /// Adds the vertex. 39 | /// 40 | /// 41 | /// V. 42 | /// 43 | /// 44 | /// Represents errors that occur during application execution. 45 | /// 46 | public void AddVertex( Vector2D V ) 47 | { 48 | if( VVertexA == Fortune.VVUnkown ) { 49 | VVertexA = V; 50 | } 51 | else if( VVertexB == Fortune.VVUnkown ) { 52 | VVertexB = V; 53 | } 54 | else { 55 | throw new Exception( "Tried to add third vertex!" ); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/VoronoiGraph.cs: -------------------------------------------------------------------------------- 1 | // Original code by BenDi on CodeProject: 2 | // 3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx 4 | // 5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github: 6 | // 7 | // https://github.com/Taffer/UnitySimpleMapGenerator 8 | 9 | namespace BenDi.FortuneVoronoi 10 | { 11 | using System; 12 | using System.Collections.Generic; 13 | 14 | using NGenerics.DataStructures.Mathematical; 15 | 16 | public class VoronoiGraph 17 | { 18 | /// 19 | /// The vertizes. 20 | /// 21 | public HashSet Vertizes = new HashSet(); 22 | 23 | /// 24 | /// The edges. 25 | /// 26 | public HashSet Edges = new HashSet(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhimir/UnitySimpleMapGenerator/6eefde5a7ccd84503b7dc8cfb574650c1d4feaa2/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.dll -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhimir/UnitySimpleMapGenerator/6eefde5a7ccd84503b7dc8cfb574650c1d4feaa2/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.pdb -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/UnitySimpleMapGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.0 7 | 2.0 8 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35} 9 | Library 10 | Taffer.UnitySimpleMapGenerator 11 | Taffer.UnitySimpleMapGenerator 12 | This is a port of Baran Kahyaoglu's Simple Map Generator, which you can find 13 | here: 14 | 15 | http://www.barankahyaoglu.com/blog/post/2011/07/27/Simple-Map-Generator-Part-1.aspx 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug 22 | DEBUG; 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | none 29 | false 30 | bin\Release 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | 37 | 38 | ..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A} 48 | FortuneVoronoi 49 | 50 | 51 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76} 52 | BraveNewWorld 53 | 54 | 55 | -------------------------------------------------------------------------------- /UnitySimpleMapGenerator/UnitySimpleMapGenerator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitySimpleMapGenerator", "UnitySimpleMapGenerator.csproj", "{0BC32450-0FF3-4799-A091-3BD5FE66AB35}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FortuneVoronoi", "FortuneVoronoi\FortuneVoronoi.csproj", "{21803548-A68A-473A-BF1B-0AE5F63F9F1A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BraveNewWorld", "BraveNewWorld\BraveNewWorld.csproj", "{5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(MonoDevelopProperties) = preSolution 30 | StartupItem = UnitySimpleMapGenerator.csproj 31 | Policies = $0 32 | $0.DotNetNamingPolicy = $1 33 | $1.DirectoryNamespaceAssociation = Flat 34 | $1.ResourceNamePolicy = MSBuild 35 | $0.TextStylePolicy = $2 36 | $2.RemoveTrailingWhitespace = True 37 | $2.inheritsSet = VisualStudio 38 | $2.inheritsScope = text/plain 39 | $2.scope = text/x-csharp 40 | $0.CSharpFormattingPolicy = $3 41 | $3.BeforeMethodDeclarationParentheses = False 42 | $3.WithinMethodDeclarationParentheses = True 43 | $3.BeforeMethodCallParentheses = False 44 | $3.WithinMethodCallParentheses = True 45 | $3.BeforeConstructorDeclarationParentheses = False 46 | $3.WithinConstructorDeclarationParentheses = True 47 | $3.BeforeDelegateDeclarationParentheses = False 48 | $3.AfterDelegateDeclarationParameterComma = True 49 | $3.WithinDelegateDeclarationParentheses = True 50 | $3.NewParentheses = False 51 | $3.IfParentheses = False 52 | $3.WhileParentheses = False 53 | $3.ForParentheses = False 54 | $3.ForeachParentheses = False 55 | $3.CatchParentheses = False 56 | $3.SwitchParentheses = False 57 | $3.LockParentheses = False 58 | $3.UsingParentheses = False 59 | $3.WithinParentheses = True 60 | $3.WithinIfParentheses = True 61 | $3.WithinWhileParentheses = True 62 | $3.WithinForParentheses = True 63 | $3.WithinForEachParentheses = True 64 | $3.WithinCatchParentheses = True 65 | $3.WithinSwitchParentheses = True 66 | $3.WithinLockParentheses = True 67 | $3.WithinUsingParentheses = True 68 | $3.WithinNewParentheses = True 69 | $3.SpacesBeforeBrackets = False 70 | $3.inheritsSet = Mono 71 | $3.inheritsScope = text/x-csharp 72 | $3.scope = text/x-csharp 73 | $0.TextStylePolicy = $4 74 | $4.RemoveTrailingWhitespace = True 75 | $4.inheritsSet = Mono 76 | $4.inheritsScope = text/plain 77 | $4.scope = text/plain 78 | $0.StandardHeader = $5 79 | $5.Text = @-----------------------------------------------------------------------\n\nUse this code for whatever you want, just don't blame me if it breaks.\n\n----------------------------------------------------------------------- 80 | $5.IncludeInNewFiles = True 81 | $0.VersionControlPolicy = $6 82 | $6.inheritsSet = Mono 83 | $0.ChangeLogPolicy = $7 84 | $7.UpdateMode = None 85 | $7.MessageStyle = $8 86 | $8.LineAlign = 0 87 | $7.inheritsSet = Mono 88 | description = A Unity3D port of Baran Kahyaoglu's Map Generator - http://www.barankahyaoglu.com/blog/page/MapGenerator.aspx 89 | EndGlobalSection 90 | EndGlobal 91 | --------------------------------------------------------------------------------