예제 #1
0
파일: Town.cs 프로젝트: twobob/Town
        private void BuildPatches()
        {
            var points = GetVoronoiPoints(NumPatches, Center).ToList();

            var v = Voronoi.Build(points);

            for (var i = 0; i < 3; i++)
            {
                var toRelax = v.Points.Take(3).ToList();
                toRelax.Add(v.Points[NumPatches]);
                v = Voronoi.Relax(v, toRelax);
            }

            v = Voronoi.Relax(v);

            var comparer = new Vector2LengthComparer();

            v.Points.Sort(comparer);

            var regions = v.Partitioning();

            Patches.Clear();
            foreach (var region in regions)
            {
                Patches.Add(Patch.FromRegion(this, region));
            }

            var patchesInTown = Patches.OrderBy(p => (Center - p.Center).Length).Take(NumPatches).ToList();

            // Find random patch at the outside of town to place water
            if (Options.Water)
            {
                var firstWaterPatch = patchesInTown.Where(p => p.GetAllNeighbours().Any(n => !n.WithinCity))
                                      .OrderBy(p => Rnd.NextDouble()).First();
                firstWaterPatch.Water = true;

                var waterDirection = Vector2.Normalize(firstWaterPatch.Center - Center);

                var toCheck = new List <Patch> {
                    firstWaterPatch
                };
                while (toCheck.Any())
                {
                    var checking = toCheck[0];
                    toCheck.RemoveAt(0);

                    var waterPatches = checking.GetAllNeighbours().Except(patchesInTown)
                                       .Where(n => Math.Abs((Center - n.Center).AngleComparedTo(waterDirection)) < Math.PI / 4)
                                       .Where(n => !n.Water).ToList();
                    foreach (var waterPatch in waterPatches)
                    {
                        waterPatch.Water = true;
                        toCheck.Add(waterPatch);
                    }
                }
            }

            patchesInTown = Patches.Where(p => !p.Water).OrderBy(p => (Center - p.Center).Length).Take(NumPatches)
                            .ToList();

            foreach (var patch in patchesInTown)
            {
                patch.WithinCity  = true;
                patch.WithinWalls = true;
            }

            Castle = new Castle(patchesInTown.Last());

            Market = patchesInTown.First();

            var circumference = FindCircumference(patchesInTown);
            var smoothAmount  = Math.Min(1f, 40f / circumference.Vertices.Count);

            if (Options.Walls)
            {
                SmoothPatches(circumference, smoothAmount);
            }

            if (Options.Water)
            {
                var waterCircumference = FindCircumference(Patches.Where(p => p.Water));
                SmoothPatches(waterCircumference, 0.2f);
                WaterBorder.Clear();
                WaterBorder.AddRange(waterCircumference.Vertices);
            }
        }
예제 #2
0
파일: Town.cs 프로젝트: twobob/Town
        public Town(TownOptions options)
        {
            Options  = options;
            Rnd.Seed = options.Seed.Value;

            var ok = false;

            while (!ok)
            {
                NumPatches  = options.Patches;
                Roads       = new List <List <Vector2> >();
                Streets     = new List <List <Vector2> >();
                Gates       = new List <Vector2>();
                Center      = new Vector2(Width / 2f * (1 + 0.1 * Rnd.NextDouble() - 0.1 * Rnd.NextDouble()), Height / 2f * (1 + 0.1 * Rnd.NextDouble() - 0.1 * Rnd.NextDouble()));
                Patches     = new List <Patch>();
                WaterBorder = new List <Vector2>();

                try
                {
                    BuildPatches();
                    OptimizePatches();
                    BuildWalls();
                    BuildRoads();
                    PopulateTown();

                    ok = Roads.Count > 1;
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception);
                }
            }
        }
예제 #3
0
        private static IEnumerable <Polygon> CreateAlleys(Polygon block, float minArea, float gridChaos, float sizeChaos, Func <Polygon, float> emptyProbabilityFunc, bool split, int levels = 0)
        {
            Vector2 point  = Vector2.Zero;
            var     length = float.MinValue;

            block.ForEachEdge((p1, p2, index) =>
            {
                var len = (p1 - p2).Length;
                if (len > length)
                {
                    length = len;
                    point  = p1;
                }
            });

            var spread = 0.8f * gridChaos;
            var ratio  = (1 - spread) / 2 + (float)Rnd.NextDouble() * spread;

            // Trying to keep buildings rectangular even in chaotic wards
            var angleSpread = (float)(Math.PI / 6 * gridChaos * (block.Area() < minArea * 4 ? 0 : 1));
            var angle       = ((float)Rnd.NextDouble() - 0.5f) * angleSpread;

            var halves = block.Bisect(point, ratio, angle, split ? Alley : 0f);

            var buildings = new List <Polygon>();

            foreach (var half in halves)
            {
                if (half.Area() < minArea * Math.Pow(2, 4 * sizeChaos * (Rnd.NextDouble() - 0.5f)) || levels > 5)
                {
                    if (!Rnd.NextBool(emptyProbabilityFunc(half)))
                    {
                        buildings.Add(half);
                    }
                }
                else
                {
                    buildings.AddRange(CreateAlleys(half, minArea, gridChaos, sizeChaos, emptyProbabilityFunc, half.Area() > minArea / (Rnd.NextDouble() * Rnd.NextDouble()), levels + 1));
                }
            }

            return(buildings);
        }