/// <summary>
        /// Create a Voronoi Diagram using a list of points and a specified algorithm to use
        /// </summary>
        public static VoronoiDiagram CreateVoronoi(List <Point> points, GenerationSettings settings)
        {
            VoronoiDiagram voronoi;

            var startX = settings.StartX;
            var startY = settings.StartX;
            var width  = settings.Width;
            var length = settings.Length;

            //Select algorithm to use
            switch (settings.VoronoiAlgorithm)
            {
            // Voronoi according to Boywer-Watson Algorithm
            // http://paulbourke.net/papers/triangulate/
            case VoronoiAlgorithm.BoywerWatson:
            {
                voronoi = new BowyerWatsonGenerator().GetVoronoi(points);
                break;
            }

            // Voronoi according to Fortunes Algorithm
            // http://blog.ivank.net/fortunes-algorithm-and-implementation.html
            case VoronoiAlgorithm.Fortune:
            {
                voronoi = new FortuneGenerator().GetVoronoi(points);
                break;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(settings.VoronoiAlgorithm), settings.VoronoiAlgorithm, null);
            }



            voronoi.Bounds = new Rectangle(startX, startY, width, length);



            voronoi.Sites = points;

            voronoi.FinishVoronoi();

            return(voronoi);;
        }
示例#2
0
        /// <summary>
        /// Create a Voronoi Diagram using a list of points and a specified algorithm to use
        /// </summary>
        public static VoronoiDiagram CreateVoronoi(List<Point> points, GenerationSettings settings)
        {
            VoronoiDiagram voronoi;

            var startX = settings.StartX;
            var startY = settings.StartX;
            var width = settings.Width;
            var length = settings.Length;

            //Select algorithm to use
            switch (settings.VoronoiAlgorithm)
            {
                // Voronoi according to Boywer-Watson Algorithm
                // http://paulbourke.net/papers/triangulate/
                case VoronoiAlgorithm.BoywerWatson:
                {
                    voronoi = new BowyerWatsonGenerator().GetVoronoi(points);
                    break;
                }
                // Voronoi according to Fortunes Algorithm
                // http://blog.ivank.net/fortunes-algorithm-and-implementation.html
                case VoronoiAlgorithm.Fortune:
                {
                    voronoi = new FortuneGenerator().GetVoronoi(points);
                        break;
                }
                default:
                    throw new ArgumentOutOfRangeException(nameof(settings.VoronoiAlgorithm), settings.VoronoiAlgorithm, null);
            }

            voronoi.Bounds = new Rectangle(startX, startY, width, length);

            voronoi.Sites = points;

            voronoi.FinishVoronoi();

            return voronoi;;
        }
示例#3
0
        /// <summary>
        /// Generate points and store them into a list
        /// </summary>
        private void GeneratePoints(int amount)
        {
            //clear previous data
            _points.Clear();
            _voronoiDiagram.Clear();
            _cityData.Clear();

            //fill settings
            _voronoiSettings = new GenerationSettings
            {
                VoronoiAlgorithm = VoronoiAlgorithm,
                PointAlgorithm = PointAlgorithm,
                Width = Width,
                Length = Height,
                StartX = StartX,
                StartY = StartY,
                UseSeed = UseSeed,
                Seed = Seed,
                Amount = PointsToGenerate,
                CircleRadius = Radius
               
            };

            //generate points
            var timer = Stopwatch.StartNew();
            _points = PointGenerator.Generate(_voronoiSettings);
            timer.Stop();
            
            //update generation timer
            var time = timer.ElapsedMilliseconds/1000.0;
            GenerationTimeText = $"Generated {_points.Count} points in {time} seconds.";

            //update randomly generated seed
            if (UseSeed == false)
                Seed = _voronoiSettings.Seed;

            //update canvas
            RefreshCanvas();
        }
示例#4
0
        private static List<Point> CircleDistribution(GenerationSettings settings)
        {
            var points = new List<Point>();

            for (int i = 0; i < settings.Amount; i++)
            {
                var origin = new Point(settings.Width/2, settings.Length/2);
                var p = MathHelpers.GenerateRandomPointInCircle(origin, settings.CircleRadius);

                points.Add(p);
            }

            return points;
        }
示例#5
0
        private static List<Point> UniformDistribution(GenerationSettings settings)
        {
            var points = new List<Point>();

            var width = settings.Width;
            var length = settings.Length;

            int gran = 20000;
            int widthM = 0, lengthM = 0;

            if (width > length)
            {
                lengthM = gran;
                widthM = (int)Math.Floor(gran*width/length);
            }
            else
            {
                widthM = gran;
                lengthM = (int)Math.Floor(gran * length / width);
            }

            for (int i = 0; i < settings.Amount; i++)
            {
                var p = Point.Zero;

                p.X = width*RandomHelper.RandomInt((int)settings.StartX, widthM)/widthM;
                p.Y = length * RandomHelper.RandomInt((int)settings.StartY, lengthM) / lengthM;

                points.Add(p);
            }

            return points;
        }
示例#6
0
        public static List<Point> Generate(GenerationSettings settings)
        {
            List<Point> generatedPoints;
            var startX = settings.StartX;
            var startY = settings.StartY;
            var width = settings.Width;
            var length = settings.Length;
            var amount = settings.Amount;

            // Seed random
            var seed = settings.UseSeed ? settings.Seed : DateTime.Now.GetHashCode();
            _rng = new Random(seed);

            //generate points according to chosen algorithm
            switch (settings.PointAlgorithm)
            {
                case PointGenerationAlgorithm.Simple:
                    generatedPoints = SimpleSpread(settings);
                    break;
                case PointGenerationAlgorithm.CityLike:
                    generatedPoints = CityLikeSpread(settings);
                    break;
                case PointGenerationAlgorithm.Uniform:
                    generatedPoints = UniformDistribution(settings);
                    break;
                case PointGenerationAlgorithm.Circle:
                    generatedPoints = CircleDistribution(settings);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            //generatedPoints = new List<Point>();

            generatedPoints.FilterDoubleValues();

            if (settings.PointAlgorithm != PointGenerationAlgorithm.Circle)
            {
                //Add Bounds as points
                var bounds = new Point(startX, startY);
                generatedPoints.Add(bounds);
                generatedPoints.Add(new Point(bounds.X + width, bounds.Y));
                generatedPoints.Add(new Point(bounds.X, bounds.Y + length));
                generatedPoints.Add(new Point(bounds.X + width, bounds.Y + length));

                var halfWidth = width/2;
                var halfLength = length/2;

                //Add half bounds as points
                generatedPoints.Add(new Point(bounds.X + halfWidth, bounds.Y));
                generatedPoints.Add(new Point(bounds.X + halfWidth, bounds.Y + length));

                generatedPoints.Add(new Point(bounds.X, bounds.Y + halfLength));
                generatedPoints.Add(new Point(bounds.X + width, bounds.Y + halfLength));
            }

            //restore back to original settings
            settings.StartX = startX;
            settings.StartY = startY;
            settings.Width = width;
            settings.Amount = amount;
            settings.Length = length;

            return generatedPoints;
        }
示例#7
0
        private static List<Point> CityLikeSpread(GenerationSettings settings)
        {
            var startX = (int)settings.StartX;
            var startY = (int)settings.StartY;
            var width  = (int)settings.Width;
            var length = (int)settings.Length;

            var offset = 0.20;

            //amount of points will be divided over both generations
            settings.Amount = (int)Math.Floor(settings.Amount * 0.3);

            //generate outer points
            var points = SimpleSpread(settings);

            //calculate new start point and bounds
            settings.StartX = startX + (width * offset);
            settings.StartY = startY + (length * offset);

            offset *= 2;

            settings.Width = width * (1-offset);
            settings.Length = length * (1-offset);

            //generate inner points
            settings.Amount = (int)Math.Floor(settings.Amount * 0.7);
            points.AddRange(SimpleSpread(settings));

            return points;
        }
示例#8
0
        private static List<Point> SimpleSpread(GenerationSettings settings)
        {
            //Create point list
            var points = new List<Point>();

            var startX = (int)settings.StartX;
            var startY = (int)settings.StartY;
            var width  = (int)settings.Width;
            var length = (int)settings.Length;

            //Generate points and add them to the collection
            for (var i = 0; i < settings.Amount; ++i)
            {
                var x = _rng.Next(startX, startX + width);
                var y = _rng.Next(startY, startY + length);

                var point = new Point(x, y);
                points.Add(point);
            }

            return points;
        }
        /// <summary>
        /// set required data for generating the terrain
        /// </summary>
        public void InitializeSettings(TerrainSettings terrainSettings, GenerationSettings voronoiSettings, GameObject parent, CitySettings citySettings)
        {
            //store settings
            _terrainSettings = terrainSettings;
            _voronoiSettings = voronoiSettings;
            _citySettings = citySettings;
            _parentGameObject = parent;

            //initialize noise
            //if no seed is specified generate a random one
            if (!terrainSettings.UseSeed)
            {
                _terrainSettings.GroundSeed = Random.Range(int.MinValue, int.MaxValue);
                _terrainSettings.MountainSeed = Random.Range(int.MinValue, int.MaxValue);
                _terrainSettings.TreeSeed = Random.Range(int.MinValue, int.MaxValue);
                _terrainSettings.DetailSeed = Random.Range(int.MinValue, int.MaxValue);
            }

            //create noise
            _groundNoise = new PerlinNoise(_terrainSettings.GroundSeed);
            _treeNoise = new PerlinNoise(_terrainSettings.TreeSeed);
            _detailNoise = new PerlinNoise(_terrainSettings.DetailSeed);

            //calculate total size of 1 terrain tile based on the city bounds
            _terrainSize = (int)(_voronoiSettings.Width * 2f);

            _grassLayers = 0;
            _meshLayers = 0;

            //create the prototypes used by the generator
            CreatePrototypes();
        }
        /// <summary>
        /// Initialize base settings
        /// </summary>
        public void Initialize()
        {
            //create a town generator object when it doesn't exist yet
            if (_townGenerator != null) return;

            //Access towngenerator
            _townGenerator = TownGenerator.GetInstance();

            //Set default settings
            _generationSettings = new GenerationSettings
            {
                VoronoiAlgorithm = VoronoiAlgorithm.Fortune,
                PointAlgorithm = PointGenerationAlgorithm.CityLike
            };

            //City settings
            _citySettings = new CitySettings();
            _citySettings.DebugMode = false;

            //Create a base district type
            CreatePrefabSelection("Grass");

            //Terrain settings editor
            _terrainEditor = new TerrainEditor(new TerrainSettings(), this);

            //Define a style for the foldout
            _foldoutStyle = new GUIStyle(EditorStyles.foldout)
            {
                fontStyle = FontStyle.Bold,
            };

            var c = Color.black;
            _foldoutStyle.onActive.textColor = c;
            _foldoutStyle.normal.textColor = c;
            _foldoutStyle.onNormal.textColor = c;
            _foldoutStyle.hover.textColor = c;
            _foldoutStyle.onHover.textColor = c;
            _foldoutStyle.focused.textColor = c;
            _foldoutStyle.onFocused.textColor = c;
            _foldoutStyle.active.textColor = c;
            _foldoutStyle.onActive.textColor = c;
        }
        private void LoadFromXml(string filename)
        {
            //Generation settings
            _generationSettings = new GenerationSettings();
            var root = XElement.Load(filename);

            //locate generation node
            var generation = root.Element("Generation");
            var district = root.Element("Districts");
            var terrain = root.Element("Terrain");

            if (generation == null)
                return;

            _generationSettings.UseSeed = bool.Parse(generation.Element("UseSeed").Value);
            _generationSettings.Seed = int.Parse(generation.Element("Seed").Value);

            _generationSettings.Width = double.Parse(generation.Element("Width").Value);
            _generationSettings.Length = double.Parse(generation.Element("Length").Value);

            _generationSettings.StartX = double.Parse(generation.Element("StartX").Value);
            _generationSettings.StartY = double.Parse(generation.Element("StartY").Value);

            _generationSettings.Amount = int.Parse(generation.Element("Amount").Value);

            _generationSettings.PointAlgorithm =
                (PointGenerationAlgorithm)
                    Enum.Parse(typeof(PointGenerationAlgorithm), generation.Element("Point").Value);
            _generationSettings.VoronoiAlgorithm =
                (VoronoiAlgorithm)Enum.Parse(typeof(VoronoiAlgorithm), generation.Element("Voronoi").Value);

            var parentname = generation.Element("Parent").Value;
            _townGenerator.Parent = null;
            if (parentname != string.Empty)
            {
                _townGenerator.Parent = GameObject.Find(parentname);
            }

            //Load in terrain settings
            var splatmaps = new List<SplatTexture>();
            foreach (var e in terrain.Element("Splatmaps").Elements())
            {
                var newSplat = new SplatTexture
                {
                    Texture = AssetDatabase.LoadAssetAtPath<Texture2D>(e.Value),
                    TileSize = float.Parse(e.Attribute("Tiling").Value)
                };
                splatmaps.Add(newSplat);
            }

            var trees = new List<GameObject>();
            foreach (var e in terrain.Elements("Trees").Elements())
            {
                var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(e.Value);
                trees.Add(prefab);
            }

            var props = new List<GameObject>();
            foreach (var e in terrain.Elements("Props").Elements())
            {
                var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(e.Value);
                props.Add(prefab);
            }

            var details = new List<DetailObject>();
            foreach (var e in terrain.Elements("Details").Elements())
            {
                var d = new DetailObject();

                var type = (DetailType)int.Parse(e.Attribute("Type").Value);

                switch (type)
                {
                    case DetailType.Texture:
                        d.Detail = AssetDatabase.LoadAssetAtPath<Texture2D>(e.Value);
                        d.Type = DetailType.Texture;
                        break;
                    case DetailType.GameObject:
                        d.Detail = AssetDatabase.LoadAssetAtPath<GameObject>(e.Value);
                        d.Type = DetailType.GameObject;
                        break;
                }

                details.Add(d);
            }

            //lakes
            _terrainEditor.Settings.GenerateLake = bool.Parse(terrain.Element("Lakes").Attribute("generate").Value);
            _terrainEditor.Settings.WaterPrefab =
                AssetDatabase.LoadAssetAtPath<GameObject>(terrain.Element("Lakes").Element("lake").Value);

            _terrainEditor.GetSettings().SplatMaps = splatmaps;
            _terrainEditor.GetSettings().Trees = trees;
            _terrainEditor.GetSettings().Props = props;
            _terrainEditor.GetSettings().Details = details;

            //Clear previous loaded districts
            _prefabSelectors.Clear();
            foreach (var districtElem in district.Elements())
            {
                //Create district
                var distictEditor = CreatePrefabSelection(districtElem.Name.ToString());

                if (distictEditor != null)
                {
                    distictEditor.GetSettings().Frequency = int.Parse(districtElem.Element("Frequency").Value);
                    distictEditor.GetSettings().Size = double.Parse(districtElem.Element("Size").Value);
                    distictEditor.GetSettings().Offset = int.Parse(districtElem.Element("Offset").Value);
                    distictEditor.GetSettings().Percentage = double.Parse(districtElem.Element("Interval").Value);

                    //Load in all buildings
                    distictEditor.ResetPrefabs();
                    foreach (var bElem in districtElem.Element("Buildings").Elements())
                    {
                        distictEditor.AddPrefab(bElem.Value);
                    }
                }
            }
        }
        /// <summary>
        /// Define preset settings based on a type
        /// </summary>
        private GenerationSettings GetSettingsFromPreset(CityType cityType)
        {
            var genSettings = new GenerationSettings();

            switch (cityType)
            {
                //Small
                case CityType.Village:
                    {
                        genSettings.Width = 150;
                        genSettings.Length = 150;
                        genSettings.PointAlgorithm = PointGenerationAlgorithm.Simple;
                        genSettings.Amount = 20;
                        _citySettings.GenerateInnerRoads = false;
                        break;
                    }

                //medium
                case CityType.Town:
                    {
                        genSettings.Width = 200;
                        genSettings.Length = 200;
                        genSettings.PointAlgorithm = PointGenerationAlgorithm.Simple;
                        genSettings.Amount = 50;
                        _citySettings.GenerateInnerRoads = true;
                        break;
                    }

                //large
                case CityType.Metropolis:
                    {
                        genSettings.Width = 350;
                        genSettings.Length = 350;
                        genSettings.PointAlgorithm = PointGenerationAlgorithm.CityLike;
                        genSettings.Amount = 100;
                        break;
                    }
                default:
                    break;
            }

            //still allow seed to be used with presets
            genSettings.UseSeed = _generationSettings.UseSeed;
            genSettings.Seed = _generationSettings.Seed;

            //prefer fortune algorithm for speed
            genSettings.VoronoiAlgorithm = VoronoiAlgorithm.Fortune;

            return genSettings;
        }
        /// <summary>
        /// The buttons for generating, building and resetting
        /// </summary>
        private void GenerationButtons()
        {
            GUILayout.BeginHorizontal();

            //Generate a terrain and a voronoi diagram on the terrain
            if (GUILayout.Button("Generate"))
            {
                //Use custom settings or a preset
                _generationSettings = _showAdvancedSettings ? _generationSettings : GetSettingsFromPreset(_cityType);

                //Store district information
                _citySettings.DistrictSettings = MakeDistrictSettings();
                _townGenerator.PrefabsPerZone = MakePrefabList();

                _townGenerator.Generate(_generationSettings, _citySettings, _terrainEditor.GetSettings());

            }

            ////Using the voronoi data, create a city and build it
            //if (GUILayout.Button("Build"))
            //{
            //    _townGenerator.Build();
            //}

            //Clear all generated data
            if (GUILayout.Button("Clear"))
            {
                _townGenerator.Clear();
            }

            GUILayout.EndHorizontal();
        }