public bool isSame(MapEdge e) { if (e.from != this.from || e.to != this.to) { return(false); } return(true); }
private void GenerateEdges(List <Vector2> points) { List <LineSegment> minimumSpanningTree; List <LineSegment> delaunayTriangulation; List <LineSegment> finalEdges = new List <LineSegment>(); // Create the Voronoi diagram using the AS3 Delaunay library List <uint> colors = new List <uint> (); for (int i = 0; i < points.Count; i++) { colors.Add(0); } Delaunay.Voronoi voronoi = new Delaunay.Voronoi(points, colors, new Rect(0, 0, _mapWidth, _mapHeight)); minimumSpanningTree = voronoi.SpanningTree(KruskalType.MINIMUM); delaunayTriangulation = voronoi.DelaunayTriangulation(); // First add any line segment in the minimum spanning tree to the list _edges for (int i = delaunayTriangulation.Count - 1; i >= 0; i--) { for (int j = 0; j < minimumSpanningTree.Count; j++) { if (LineSegmentEquals(minimumSpanningTree[j], delaunayTriangulation[i])) { finalEdges.Add(delaunayTriangulation[i]); delaunayTriangulation.RemoveAt(i); break; } } } // Add a random amount of line segments in the delaunay triangulation but NOT in the minimum spanning tree to the list _edges for (int i = 0, count = delaunayTriangulation.Count; i < count; i++) { float rand = UnityEngine.Random.value; if (rand <= 0.35) { finalEdges.Add(delaunayTriangulation[i]); } } // Create the edges on the map // Also update neighbours properties on the nodes for (int i = 0, count = finalEdges.Count; i < count; i++) { LineSegment line = finalEdges[i]; Vector3 p0 = new Vector3(line.p0.Value.x, line.p0.Value.y, 0); Vector3 p1 = new Vector3(line.p1.Value.x, line.p1.Value.y, 0); MapEdge mapEdge = CreateMapEdge(p0, p1); mapEdge.Initialize(p0, p1); } }
public void AddEdge(string from, string to) { Node fromNode; Node toNode; GameObject fromGameObject = null; GameObject toGameObject = null; for (int i = 0; i < this.gameObject.transform.childCount; i++) { GameObject gameObject = this.gameObject.transform.GetChild(i).gameObject; Node node = gameObject.GetComponent(typeof(Node)) as Node; if (node != null && node.id == from) { fromNode = node; fromGameObject = gameObject; } else if (node != null && node.id == to) { toNode = node; toGameObject = gameObject; } } GameObject mapEdge = Instantiate(mapEdgePrefab, new Vector3(), Quaternion.identity); MapEdge mapEdgeComponent = mapEdge.GetComponent(typeof(MapEdge)) as MapEdge; if (fromGameObject != null && toGameObject != null) { List <GameObject> connectedEdges = null; List <GameObject> connectedNodes = null; if (edgeObjectMap.TryGetValue(from, out connectedEdges)) { } else { connectedEdges = new List <GameObject>(); } if (edgeNodeMap.TryGetValue(from, out connectedNodes)) { } else { connectedNodes = new List <GameObject>(); } connectedEdges.Add(mapEdge); connectedNodes.Add(toGameObject); edgeObjectMap[from] = connectedEdges; edgeNodeMap[from] = connectedNodes; mapEdgeComponent.draw(fromGameObject.transform.position, toGameObject.transform.position); } }
public void AddEdge(MapEdge _mapEdge) { bool tIsUnique = true; for (int i = 0; i < edges.Count; i++) { MapEdge tOtherEdge = edges[i]; if (_mapEdge.CompareTo(tOtherEdge) == 0) { tIsUnique = false; } } if (tIsUnique) { edges.Add(_mapEdge); } }
private MapEdge CreateMapEdge(Vector3 p0, Vector3 p1) { GameObject graphEdgeGO = GameObject.Instantiate(_graphEdgePrefab) as GameObject; graphEdgeGO.transform.SetParent(transform); MapEdge mapEdge = graphEdgeGO.GetComponent <MapEdge>(); string node1Id = GetNodeIdFromVector3(p0); string node2Id = GetNodeIdFromVector3(p1); _mapNodes[node1Id].AddNeighbour(node2Id); _mapNodes[node2Id].AddNeighbour(node1Id); _mapNodes[node1Id].AddEdge(mapEdge); _mapNodes[node2Id].AddEdge(mapEdge); _mapEdges.Add(mapEdge); return(mapEdge); }
public static bool EdgeExists(MapNode prev, MapNode curr) { MapEdge testEdge = new MapEdge(prev, curr); foreach (MapEdge me in edges) { //Since these are added in tier order, you only need to check up until you reach the current tier //me.from is the MapEdge's first node if (me.from.tier > GameState.currentTier) { return(false); } if (me.isSame(testEdge)) { return(true); } } //If we are on the last node, and somehow an edge doesnt exist... //should be unreachable return(false); }
public void LoadMap(MapBlob blob) { _blob = blob; // Temp foreach (KeyValuePair <string, MapNodeData> kvp in blob.MapNodes) { MapNode mapNode = CreateMapNode(kvp.Key); mapNode.InitializeFromData(kvp.Value, MapNodeTappedCallback); } for (int i = 0, count = blob.MapEdges.Count; i < count; i++) { MapEdge mapEdge = CreateMapEdge(blob.MapEdges[i].P0, blob.MapEdges[i].P1); mapEdge.Initialize(blob.MapEdges[i]); } _currentNode = _mapNodes[blob.CurrentNode]; _currentNode.ToggleEdgeVisibility(true); }
public void ActivateNode(string node) { if (edgeObjectMap.ContainsKey(node)) { List <GameObject> edges = edgeObjectMap[node]; foreach (GameObject edge in edges) { MapEdge mapEdgeComponent = edge.GetComponent(typeof(MapEdge)) as MapEdge; mapEdgeComponent.activate(); } } if (edgeNodeMap.ContainsKey(node)) { List <GameObject> nodes = edgeNodeMap[node]; foreach (GameObject nodeObject in nodes) { Node nodeComponent = nodeObject.GetComponent(typeof(Node)) as Node; nodeComponent.Reveal(); } } }
public static void DrawRandomBorder <T>(T border, DataGrid <T> grid, Vector2Int borderThickness, int z, MapEdge edges, bool overwrite = false) { if (edges.HasFlag(MapEdge.North)) { int thickness = Random.Int(borderThickness); for (int x = grid.Bounds.xMin; x <= grid.Bounds.xMax; x++) { for (int y = grid.Bounds.yMax - thickness; y <= grid.Bounds.yMax; y++) { grid.Add(new Vector3Int(x, y, z), border, overwrite); } thickness = ChangeThickness(thickness, borderThickness); } } if (edges.HasFlag(MapEdge.South)) { int thickness = Random.Int(borderThickness); for (int x = grid.Bounds.xMin; x <= grid.Bounds.xMax; x++) { for (int y = grid.Bounds.yMin + thickness; y >= grid.Bounds.yMin; y--) { grid.Add(new Vector3Int(x, y, 0), border, overwrite); } thickness = ChangeThickness(thickness, borderThickness); } } if (edges.HasFlag(MapEdge.East)) { int thickness = Random.Int(borderThickness); for (int y = grid.Bounds.yMin; y <= grid.Bounds.yMax; y++) { for (int x = grid.Bounds.xMax - thickness; x <= grid.Bounds.xMax; x++) { grid.Add(new Vector3Int(x, y, 0), border, overwrite); } thickness = ChangeThickness(thickness, borderThickness); } } if (edges.HasFlag(MapEdge.West)) { int thickness = Random.Int(borderThickness); for (int y = grid.Bounds.yMin; y <= grid.Bounds.yMax; y++) { for (int x = grid.Bounds.xMin + thickness; x >= grid.Bounds.xMin; x--) { grid.Add(new Vector3Int(x, y, 0), border, overwrite); } thickness = ChangeThickness(thickness, borderThickness); } } }
public override List<Atom> Produce(CityGenerator generator) { List<Atom> production = new List<Atom>(); // Create a new map node Rule rule = generator.RuleAtCoordinates(Node.position); MapNode spawn = new MapNode(Node.position + forward * rule.CalculateRoadLength(this, generator)); spawn.ruleType = ruleType; // Fetch the spawned node's neighbours List<MapNode> neighbours = generator.GetNeighbours(spawn, generator.neighboursSearchRadius); // Check if the node is close to one of its neighbours so that they can be merged into one node bool merged = false; Vector2 spawnPosition = spawn.PositionAsVector2; foreach (MapNode neighbour in neighbours) { // Convert coords to 2D, we don't want elevation messing around with our merging algorithm Vector2 neighbourPosition = neighbour.PositionAsVector2; // Check for proximity if (Vector2.Distance(spawnPosition, neighbourPosition) <= generator.nodeMergingMaximumDistance) { // The neighbour merges spawn = neighbour; // Stop iterating merged = true; break; } } // Create a map edge between the current map node and the spawn MapEdge spawnedEdge = new MapEdge(Node, spawn); if (!merged) { // Perform the intersection of the spawned node's edge against the neighbours' edges bool intersected = Intersect(spawn, spawnedEdge, neighbours); // Raycast to check for water RaycastHit hit; if (Physics.Raycast(spawn.position + Vector3.up * 1000f, Vector3.down, out hit)) { if (hit.collider.gameObject.tag == "Water") { // Spawned over water, remove the edge from the starting node Node.edges.Remove(spawnedEdge); // Skip this node return production; } // Set the Y coordinate of the spawned node to match the height where the raycast hit spawn.position.y = hit.point.y + 0.1f; } // Add the newly created map node to the environment generator.AddMapNode(spawn); // Continue producing only if there were no intersections if (!intersected) { // Summon a branch atom Atom branch = new BranchAtom(this); branch.Node = spawn; // Add the branch atom to the list of results and we're done production.Add(branch); } } return production; }
private bool Intersect(MapNode spawn, MapEdge spawnedEdge, List<MapNode> neighbours) { // We'll need a set of all intersections we found for the given edge - in the general case there might be // several intersections so we must find the one closest to the starting node (this.Node) HashSet<MapNode> intersectionNodes = null; // Iterate through all neighbours foreach (MapNode neighbour in neighbours) { foreach (MapEdge neighboursEdge in neighbour.edges) { if (spawnedEdge.FromNode != neighboursEdge.FromNode && spawnedEdge.FromNode != neighboursEdge.ToNode && spawnedEdge.ToNode != neighboursEdge.FromNode && spawnedEdge.ToNode != neighboursEdge.ToNode) { // Try to find an intersection MapNode intersection = spawnedEdge.Intersection(neighboursEdge); if (intersection != null) { // Found - add the edge which generated the intersection to its edge list. Technically this is // invalid behavior (since the intersection lies somewhere *on* that edge), but it's only // temporarily there until we reconnect the nodes and edges properly in the next part of the // algorithm. intersection.edges.Add(neighboursEdge); // Add it to the set if (intersectionNodes == null) intersectionNodes = new HashSet<MapNode>(); intersectionNodes.Add(intersection); } } } } if (intersectionNodes != null) { // Go through all intersections and find the one closest to this.Node MapNode chosenIntersection = null; float minimumDistance = float.MaxValue; foreach (MapNode intersection in intersectionNodes) { float distance = Node.Distance(intersection); if (distance < minimumDistance) { chosenIntersection = intersection; minimumDistance = distance; } } // Move the spawn's position to be the same as chosen intersection's spawn.position = chosenIntersection.position; // Get the edge that generated this intersection MapEdge neighboursEdge = chosenIntersection.edges[0]; // Fix the "invalid behavior" mentioned above chosenIntersection.edges.Clear(); // Split the edge in two at the intersection MapNode neighboursFromNode = neighboursEdge.FromNode; MapNode neighboursToNode = neighboursEdge.ToNode; neighboursFromNode.edges.Remove(neighboursEdge); new MapEdge(neighboursFromNode, spawn); neighboursToNode.edges.Remove(neighboursEdge); new MapEdge(spawn, neighboursToNode); // Done intersectionNodes.Clear(); return true; } return false; }
public void AddEdge(MapEdge edge) { _edges.Add(edge); }
public void DelEdge(MapEdge _mapEdge) { edges.Remove(_mapEdge); }
/// <summary> /// Finds the intersection between two map edges. If there is an intersection, a new MapNode instance is created and /// returned at the intersection's coordinates. The original edges and their nodes are left unchanged. If there's no /// intersection, <c>null</c> is returned. /// </summary> /// <param name='other'> /// The edge to intersect with. /// </param> /// <returns> /// A newly spawned MapNode if there was an intersection, or <c>null</c> otherwise. /// </returns> public MapNode Intersection(MapEdge other) { // Implementation of the intersection algorithm found at: // http://britneyspeerpink.wordpress.com/2011/08/06/line-intersection/ Vector2 p = this.FromNode.PositionAsVector2; Vector2 r = this.ToNode.PositionAsVector2 - p; Vector2 q = other.FromNode.PositionAsVector2; Vector2 s = other.ToNode.PositionAsVector2 - q; Func<Vector2, Vector2, float> CrossMag = (v1, v2) => { return v1.x * v2.y - v1.y * v2.x; }; float w = CrossMag(r, s); if (Mathf.Approximately(w, 0f)) return null; else if (Mathf.Approximately(CrossMag(q - p, r), 0f)) return null; else { float t = CrossMag(q - p, s) / w; Vector2 intersectionP = p + (t * r); // Check if the intersection lies within both line segments' bounds Func<Vector2, Vector2, Vector2, bool> BoundsCheck = (intersection, p1, p2) => { return Mathf.Min(p1.x, p2.x) <= intersection.x && Mathf.Max(p1.x, p2.x) >= intersection.x && Mathf.Min(p1.y, p2.y) <= intersection.y && Mathf.Max(p1.y, p2.y) >= intersection.y; }; if (BoundsCheck(intersectionP, this.FromNode.PositionAsVector2, this.ToNode.PositionAsVector2) && BoundsCheck(intersectionP, other.FromNode.PositionAsVector2, other.ToNode.PositionAsVector2)) { // Intersection found float y = (FromNode.position + t * (ToNode.position - FromNode.position)).y; return new MapNode(new Vector3(intersectionP.x, y, intersectionP.y)); } } return null; }
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; }