private void SetRegions() { Dictionary <Vector2Int, Vertex> posToVertex = new Dictionary <Vector2Int, Vertex>(); List <Region> regions = new List <Region>(); foreach (Vector2 sitePos in voronoi.SiteCoords()) { List <Vertex> vertices = new List <Vertex>(); foreach (Vector2Int vertPos in MathVert.ToVector2Int(voronoi.Region(sitePos))) { //Drawer.DrawHLine(edgePos, Color.blue); if (!posToVertex.ContainsKey(vertPos)) { posToVertex.Add(vertPos, new Vertex(vertPos)); } vertices.Add(posToVertex[vertPos]); } Region region = new Region(sitePos, vertices.ToArray()); siteToRegion[sitePos] = region; regions.Add(region); } foreach (Vector2 site in voronoi.SiteCoords()) { foreach (Vector2 nSite in voronoi.NeighborSitesForSite(site)) { siteToRegion[site].neighbours.Add(siteToRegion[nSite]); } } this.regions = regions.ToArray(); RegionsInfo.regions = this.regions; RegionsInfo.UpdateRegionsMap(); }
private List <SuperRegion> MakeTerrainRegions(List <Vector2> poisson, Voronoi voronoi) { var regions = new List <SuperRegion>(); foreach (var regionCentre in poisson) { var x = (int)regionCentre.x; var y = (int)regionCentre.y; var height = GetNoise(x, y, baseScale, baseOffset); var biome = height > 0.75f ? SuperBiome.Mountain : height < 0.3f ? SuperBiome.Lake : SuperBiome.Plains; var points = voronoi.Region(regionCentre); var bounds = GetBounds(points); var v = new Voronoi(points, null, bounds); regions.Add(new SuperRegion { Centre = regionCentre, Points = points, Bounds = bounds, Triangles = v.Triangles(), Biome = biome, Neighbours = voronoi.NeighborSitesForSite(regionCentre) }); } return(regions); }
void Update() { List <Vector2f> points = new List <Vector2f>(); // prepare for Fortunes algorithm and clear neighbours foreach (GinelliController sheep in sheepList) { // prepare data for Voronoi Vector2 point = new Vector2(sheep.transform.position.x, sheep.transform.position.z); points.Add(new Vector2f(point.x, point.y, sheep.id)); } // get metric neighbours List <GinelliController>[] metricNeighbours = new List <GinelliController> [sheepList.Count]; foreach (GinelliController sheep in sheepList) { metricNeighbours[sheep.id] = new List <GinelliController>(); } GinelliController firstSheep, secondSheep; for (int i = 0; i < sheepList.Count; i++) { firstSheep = sheepList[i]; for (int j = i + 1; j < sheepList.Count; j++) { secondSheep = sheepList[j]; // dist? if ((firstSheep.transform.position - secondSheep.transform.position).sqrMagnitude < GM.r_o2) { metricNeighbours[firstSheep.id].Add(secondSheep); metricNeighbours[secondSheep.id].Add(firstSheep); } } } foreach (GinelliController sheep in sheepList) { sheep.metricNeighbours = metricNeighbours[sheep.id]; } // voronoi neighbours Rectf bounds = new Rectf(0f, 0f, GM.fieldSize, GM.fieldSize); // bounds actually irrelevant as Fortunes algoritghm does not use them Voronoi voronoi = new Voronoi(points, bounds); foreach (Vector2f pt in points) { GinelliController sheep = sheepList[pt.id]; List <GinelliController> voronoiNeighbours = new List <GinelliController>(); foreach (Vector2f neighbourPt in voronoi.NeighborSitesForSite(pt)) { GinelliController neighbour = sheepList[neighbourPt.id]; voronoiNeighbours.Add(neighbour); } sheep.voronoiNeighbours = voronoiNeighbours; } }
private List <BiomeRegion> MakeBiomes(List <Vector2> poisson, Voronoi voronoi) { var regions = new List <BiomeRegion>(); foreach (var regionCentre in poisson) { var x = (int)regionCentre.x; var y = (int)regionCentre.y; var superBiome = GetSuperBiomesAt(regionCentre.x, regionCentre.y).OrderBy(b => b.Proportion).LastOrDefault(); Biome biome; if (superBiome != null && superBiome.BiomeDescriptor.Biome == SuperBiome.Lake) { biome = Biome.Lake; } else if (superBiome != null && superBiome.BiomeDescriptor.Biome == SuperBiome.Mountain) { biome = Biome.Mountain; } else { var temp = GetNoise(x, y, tempScale, tempOffset); var rain = GetNoise(x, y, rainScale, rainOffset); biome = GetBiome(rain, temp); } var points = voronoi.Region(regionCentre); var bounds = GetBounds(points); var v = new Voronoi(points, null, bounds); regions.Add(new BiomeRegion { Centre = regionCentre, Points = points, Bounds = bounds, Triangles = v.Triangles(), Biome = biome, Neighbours = voronoi.NeighborSitesForSite(regionCentre) }); } return(regions); }
private void UpdateNeighbours() { List <Vector2f> points = new List <Vector2f>(); // prepare for Fortunes algorithm and clear neighbours foreach (SheepController sheep in sheepList) { sheep.metricNeighbours.Clear(); sheep.voronoiNeighbours.Clear(); points.Add(new Vector2f(sheep.transform.position.x, sheep.transform.position.z, sheep.id)); } // get metric neighbours SheepController firstSheep, secondSheep; for (int i = 0; i < sheepList.Count; i++) { firstSheep = sheepList[i]; for (int j = i + 1; j < sheepList.Count; j++) { secondSheep = sheepList[j]; // dist? if ((firstSheep.transform.position - secondSheep.transform.position).sqrMagnitude < firstSheep.r_o2) { firstSheep.metricNeighbours.Add(secondSheep); secondSheep.metricNeighbours.Add(firstSheep); } } } // voronoi neighbours Rectf bounds = new Rectf(0.0f, 0.0f, fieldSize, fieldSize); Voronoi voronoi = new Voronoi(points, bounds); foreach (Vector2f pt in points) { SheepController sheep = sheepList[pt.id]; foreach (Vector2f neighbourPt in voronoi.NeighborSitesForSite(pt)) { SheepController neighbour = sheepList[neighbourPt.id]; sheep.voronoiNeighbours.Add(neighbour); } } }
private void MakeSettlements(Rect bounds) { var settlementPoissonEnum = Poisson.generate_poisson(random, size, settlementSeparation, poissonRetries); var settlementPoisson = new List <Vector2>(); while (settlementPoissonEnum.MoveNext()) { settlementPoisson.Add(settlementPoissonEnum.Current); } var settlementVoronoi = new Voronoi(settlementPoisson, null, bounds); settlements = settlementPoisson.Select(p => new Settlement { Centre = p, Biome = GetBiomeAt(p.x, p.y), Neighbours = settlementVoronoi.NeighborSitesForSite(p).Where(n => Vector2.Distance(p, n) < settlementSeparation * 2).ToList() }).ToList(); settlementLookup = settlements.ToDictionary(x => x.Centre); }
/// <summary> /// Generate a room by selecting a random cell from a given voronoi grid and adding the surrounding cells /// to it until the required size has been met. /// </summary> /// <param name="voronoi"></param> /// <returns></returns> public List <List <Vector2> > GenerateRoom(Voronoi voronoi, int size, string seed) { if (size < 1) { return(null); } //Select a random site from the voronoi diagram Vector2 coord = RandomUtil.RandomElement(voronoi.SiteCoords(), false, seed); //Start building the final room from the cell at the coord List <LineSegment> baseRoom = voronoi.VoronoiBoundaryForSite(coord); List <List <Vector2> > finalRoomVertices = new List <List <Vector2> >(); finalRoomVertices.Add(GetVerticesFromLineSegments(baseRoom)); //Get the sites neighboring the base room List <Vector2> neighborSites = voronoi.NeighborSitesForSite(coord); //Add neighboring cells to the final room until the required room size has been met. //WARNING: Currently adds duplicate vertices to the final room in order to be able to triangulate each room-piece seperately later on. for (int i = 0; i < size - 1; i++) { List <LineSegment> neighbor = voronoi.VoronoiBoundaryForSite(neighborSites[i]); finalRoomVertices.Add(GetVerticesFromLineSegments(neighbor)); } //Sort all room piece vertices clockwise for triangulation List <List <Vector2> > clockwiseVertices = new List <List <Vector2> >(); foreach (List <Vector2> vertexSet in finalRoomVertices) { clockwiseVertices.Add(VectorUtil.SortClockwise(vertexSet)); } return(clockwiseVertices); }
// Create a graph containing all connected empty areas private void CreateBaseGraph(int lloydIterations) { // Create uniform random point distribution and Voronoi Diagram var centers = new List <Vector2f>(); for (int i = 0; i < _voronoiSamples; i++) { var x = Random.Range(0f, MapSize); var y = Random.Range(0f, MapSize); centers.Add(new Vector2f(x, y)); } VoronoiDiagram = new Voronoi(centers, new Rectf(0, 0, MapSize, MapSize)); // Apply Lloyd Relaxation VoronoiDiagram.LloydRelaxation(lloydIterations); // Assign area segments to initial areas foreach (var site in VoronoiDiagram.SiteCoords()) { bool isOnBorder = false; var segments = VoronoiDiagram.VoronoiBoundaryForSite(site); foreach (var segment in segments) { if (!(segment.p0.x <= VoronoiDiagram.PlotBounds.left) && !(segment.p0.x >= VoronoiDiagram.PlotBounds.right) && !(segment.p0.y <= VoronoiDiagram.PlotBounds.top) && !(segment.p0.y >= VoronoiDiagram.PlotBounds.bottom) && !(segment.p1.x <= VoronoiDiagram.PlotBounds.left) && !(segment.p1.x >= VoronoiDiagram.PlotBounds.right) && !(segment.p1.y <= VoronoiDiagram.PlotBounds.top) && !(segment.p1.y >= VoronoiDiagram.PlotBounds.bottom)) { continue; } isOnBorder = true; break; } // Assign areaSegment to site and corresponding area var areaSegment = new AreaSegment(isOnBorder ? AreaSegment.EAreaSegmentType.Border : AreaSegment.EAreaSegmentType.Empty); var nodeID = AreaSegmentGraph.AddNode(areaSegment); _siteAreaSegmentMap.Add(site, nodeID); _areaSegmentCenterMap.Add(nodeID, site.ToUnityVector2()); } // Create navigation graph - for each area segment that is not a border, add reachable neighbors foreach (var id in _siteAreaSegmentMap) { var areaSegment = AreaSegmentGraph.GetNodeData(id.Value); if (areaSegment.Type == AreaSegment.EAreaSegmentType.Border) { continue; } Vector2 center = _areaSegmentCenterMap[id.Value]; foreach (var neighbor in VoronoiDiagram.NeighborSitesForSite(new Vector2f(center.x, center.y))) { var neighborSegment = AreaSegmentGraph.GetNodeData(_siteAreaSegmentMap[neighbor]); if (neighborSegment.Type != AreaSegment.EAreaSegmentType.Border) { AreaSegmentGraph.AddEdge(_siteAreaSegmentMap[neighbor], id.Value, (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable); } } } }
/// <summary> /// 取得指定地區的鄰居地區中心座標列表 /// </summary> /// <param name="point">地區中心座標</param> /// <returns>座標列表</returns> public Vector2f[] getNeighborCenters(Vector2f point) { return(voronoi.NeighborSitesForSite(point).ToArray()); }
void Draw() { texture = new Texture2D(mapWidth, mapHeight); cells = new List <MapCell>(); Debug.Log(map_points.Count); for (int i = 0; i < map_points.Count; i++) { Vector2 site = map_points[i]; MapCell cell = new MapCell { Position = site, edges = new List <MapEdge>(), neighbours = voronoi.NeighborSitesForSite(site), ID = i, }; //cell.isBorder = IsBorder(voronoi.VoronoiBoundaryForSite(site)); cell.isBorder = HullContainsSite(site); foreach (LineSegment segment in voronoi.VoronoiBoundaryForSite(site)) { cell.edges.Add(new MapEdge(segment.P0, segment.P1)); } // Paint edges for (int j = 0; j < cell.edges.Count; j++) { MapEdge edge = cell.edges[j]; List <Vector2> points = new List <Vector2> { edge.p0, edge.p1 }; Vector2 p0 = points[0]; Vector2 p1 = points[1]; int distance = (int)Mathf.Abs(Vector2.Distance(p0, p1)); for (int k = 0; k <= distance; k++) { Vector2 temp = p1 - p0; temp.Normalize(); Vector2 pos = k * temp + p0; int x; int y; if ((int)pos.x >= mapWidth) { x = ((int)pos.x) - 1; } else { x = (int)pos.x; } if ((int)pos.y >= mapHeight) { y = ((int)pos.y) - 1; } else { y = (int)pos.y; } texture.SetPixel(x, y, borderColour); } } //Fill Center //Temporary fill to have land and water int tempx = (int)site.x; int tempy = (int)site.y; if (cell.isBorder) { cell.biome = Biomes.GetBiome("Ocean"); texture.FloodFillBorder(tempx, tempy, cell.biome.biomeColour, borderColour); continue; } float[,] noiseLayer = Noise.GenerateNoiseMap(mapWidth, mapHeight, seed, NOISE_SCALE, OCTAVES, PERSISTANCE, LACUNARITY, new Vector2(0, 0)); if (noiseLayer[tempx, tempy] > waterThreshold) { cell.biome = Biomes.GetBiome("Grasslands"); texture.FloodFillBorder(tempx, tempy, cell.biome.biomeColour, borderColour); } else { cell.biome = Biomes.GetBiome("Ocean"); texture.FloodFillBorder(tempx, tempy, cell.biome.biomeColour, borderColour); } } texture.Apply(); plane.GetComponent <MeshRenderer>().sharedMaterial.mainTexture = texture; }