// Adds this boundary to a graph as a series of nodes and edges public void AddToGraph(BoundaryGraph graph) { List <Vector2> corners = Get2DBounds(); List <BoundaryGraphNode> nodes = new List <BoundaryGraphNode>(); int i = 0; // Convert each point into a node for (i = 0; i < corners.Count; i++) { BoundaryGraphNode node = new BoundaryGraphNode(corners[i]); nodes.Add(node); } // Link each node to the next one (note linking is reciprical so I don't have to link the reverse) for (i = 0; i < nodes.Count; i++) { int nextInd = (i + 1) % nodes.Count; nodes[i].AddNeighbor(nodes[nextInd]); } // Add the nodes to the graph foreach (BoundaryGraphNode node in nodes) { node.AddParentBoundary(this); graph.AddNode(node); } }
// Compiles the level recovering interior geometry // Output is saved as a scriptable object instance in assets public void CompileLevel() { // Build a list of boundaries and a shape graph List <Boundary> boundaries = new List <Boundary>(); BoundaryGraph graph = new BoundaryGraph(); foreach (Transform trans in transform) { Boundary temp = trans.gameObject.GetComponent <Boundary>(); if (temp != null) { boundaries.Add(temp); temp.AddToGraph(graph); } } // Unify the graph and make sure any intersections have a vertex graph.Unify(); // Remove any verticies interior to another boundary // This does not account for exterior - exterior edges that cross the shape List <BoundaryGraphNode> deleteList = new List <BoundaryGraphNode>(); foreach (BoundaryGraphNode node in graph) { foreach (Boundary bound in boundaries) { // Ignore its parent boundaries //if (node.IsParent(bound)) //continue; // If position is interior, remove this node if (bound.Interior(node.position)) { deleteList.Add(node); break; } } } // Cleanup deleted nodes foreach (BoundaryGraphNode node in deleteList) { graph.DeleteNode(node); } // Now we will delete any edges who's midpoint is interior to another boundary // These edges can remain when there's an exterior-exterior edge crossing polygons // Consider a T shape made of 2 boundaries. Right at the cross section foreach (UnorderedPair <BoundaryGraphNode, BoundaryGraphNode> edge in graph.getEdgesAsUniquePairs()) { // Find the midpoint Vector3 midpoint = new Vector3((edge.item1.position.x + edge.item2.position.x) / 2, (edge.item1.position.y + edge.item2.position.y) / 2, 0); foreach (Boundary bound in boundaries) { // Ignore its parent boundaries //if (edge.item1.IsParent(bound) || edge.item2.IsParent(bound)) //continue; // If position is interior, remove this node if (bound.Interior(midpoint)) { edge.item1.RemoveNeighbor(edge.item2); // Edge removal is reciprical break; } } } // NOTE: work still needed. Needs to handle multiple islands and error cases. // right now it only works for the trivial case // While the graph has nodes remaining while (!graph.IsEmpty()) { // Pick an extrema node. This will belong to the exterior most cycle in the graph BoundaryGraphNode extrema = graph.GetExtrema(); // Clean up any exterior - exterior edges that could connect two seperate layers // These are left over after deleting the interior nodes // To do this, we track whether we are currently in an exterior // Remove that node and all nodes connected. This will give you the loop. List <BoundaryGraphNode> loop = graph.RemoveConnectedComponent(extrema); // Convert loop into a list of vector2 List <Vector2> vertexList = new List <Vector2>(); foreach (BoundaryGraphNode node in loop) { vertexList.Add(node.position); } vertexList.RemoveAt(vertexList.Count - 1); // There is a bug causing duplicate nodes and instead of fixing it I did this... f**k me :( Polygon poly = Undo.AddComponent <Polygon>(gameObject); poly.SetVerticies(vertexList); } return; }