public static List <GameObject> GenerateVoronoiPieces(GameObject source, int extraPoints = 0, int subshatterSteps = 0, Material mat = null) { List <GameObject> pieces = new List <GameObject>(); if (mat == null) { mat = createFragmentMaterial(source); } //get transform information Vector3 origScale = source.transform.localScale; source.transform.localScale = Vector3.one; Quaternion origRotation = source.transform.localRotation; source.transform.localRotation = Quaternion.identity; //get rigidbody information Rigidbody2D rigbody = source.GetComponent <Rigidbody2D>(); //Я добавил Vector2 origVelocity = rigbody.velocity; //get collider information PolygonCollider2D sourcePolyCollider = source.GetComponent <PolygonCollider2D>(); BoxCollider2D sourceBoxCollider = source.GetComponent <BoxCollider2D>(); List <Vector2> points = new List <Vector2>(); List <Vector2> borderPoints = new List <Vector2>(); if (sourcePolyCollider != null) { points = getPoints(sourcePolyCollider); borderPoints = getPoints(sourcePolyCollider); } else if (sourceBoxCollider != null) { points = getPoints(sourceBoxCollider); borderPoints = getPoints(sourceBoxCollider); } Rect rect = getRect(source); for (int i = 0; i < extraPoints; i++) { points.Add(new Vector2(Random.Range(rect.width / -2, rect.width / 2), Random.Range(rect.height / -2, rect.height / 2))); } Voronoi voronoi = new Delaunay.Voronoi(points, null, rect); List <List <Vector2> > clippedRegions = new List <List <Vector2> >(); foreach (List <Vector2> region in voronoi.Regions()) { clippedRegions = ClipperHelper.clip(borderPoints, region); foreach (List <Vector2> clippedRegion in clippedRegions) { pieces.Add(generateVoronoiPiece(source, clippedRegion, origVelocity, origScale, origRotation, mat, rigbody)); } } List <GameObject> morePieces = new List <GameObject>(); if (subshatterSteps > 0) { subshatterSteps--; foreach (GameObject piece in pieces) { morePieces.AddRange(SpriteExploder.GenerateVoronoiPieces(piece, extraPoints, subshatterSteps)); GameObject.DestroyImmediate(piece); } } else { morePieces = pieces; } //reset transform information source.transform.localScale = origScale; source.transform.localRotation = origRotation; Resources.UnloadUnusedAssets(); return(morePieces); }
void OnDrawGizmos() { if (v == null) { return; } Gizmos.color = Color.red; if (m_points != null) { for (int i = 0; i < m_points.Count; i++) { Gizmos.DrawSphere(m_points [i], 0.2f); } } if (DrawAllEdges) { if (m_edges != null) { Gizmos.color = Color.gray; for (int i = 0; i < m_edges.Count; i++) { Vector2 left = (Vector2)m_edges [i].p0; Vector2 right = (Vector2)m_edges [i].p1; Gizmos.DrawLine((Vector3)left, (Vector3)right); } } } if (DrawDelaunayTriangulation) { Gizmos.color = Color.magenta; if (m_delaunayTriangulation != null) { for (int i = 0; i < m_delaunayTriangulation.Count; i++) { Vector2 left = (Vector2)m_delaunayTriangulation [i].p0; Vector2 right = (Vector2)m_delaunayTriangulation [i].p1; Gizmos.DrawLine((Vector3)left, (Vector3)right); } } } if (DrawSpanningTree) { if (m_spanningTree != null) { Gizmos.color = Color.green; for (int i = 0; i < m_spanningTree.Count; i++) { LineSegment seg = m_spanningTree [i]; Vector2 left = (Vector2)seg.p0; Vector2 right = (Vector2)seg.p1; Gizmos.DrawLine((Vector3)left, (Vector3)right); } } } /** This is the correct source of Voronoi polygons: the "Regions" data from the Voronoi object. * Note that the list is points, not lines, and you usually have to manually CLOSE the final point to the first */ if (DrawVoronoiRegions) { Debug.Log("Found " + v.Regions().Count + " regions to draw"); foreach (List <Vector2> region in v.Regions()) { if (randomizeVoronoiColours) /** Note: the Edges display above (in Gray) shows unconnected edges, * but this section re-uses the actual semi-polygons created automatically by the Voronoi algorithm. To prove * this you can optionally turn on colourization of the edges, so that that shared edges will show with same colours */ { Gizmos.color = new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f)); } else { Gizmos.color = Color.white; } for (int i = 0; i + 1 < region.Count; i++) { Vector2 s = (Vector2)region [i]; Vector2 e = (Vector2)region [i + 1]; if (randomizeVoronoiColours) { /** To make them easier to see, shift the vectors SLIGHTLY towards the center point. * * REMoVED: WE CANT DO THAT WHEN USING THE REGIONS SHORTCUT, REGIONS DELETE THEIR POINTS, sadly :( * * This lets you see EXACTLY what poly / partial poly the algorithm is giving us "for free", * so that triangulating it will be easy in your own projects */ // s += (siteCoord - s) * 0.05f; // e += (siteCoord - e) * 0.05f; } Gizmos.DrawLine(s, e); } if (CloseExternalVoronoPolys) { Gizmos.DrawLine((Vector2)region [region.Count - 1], (Vector2)region [0]); } } } /** This is the INcorrect way of getting polygons out; but it has an advantage: the Voronoi class deletes * the Site at center of a Region when giving us Regions (bug: I'd like to fix that and have it return a data * structure that includes the Site!). * * In the meantime, here's how to manually generate the polys by re-using the Boundaries code from Voronoi, * much easier than trying to manually generate from raw edges. * * But ideally: use DrawVoronoiRegions instead */ if (DrawManualVoronoiPolygons) { /** Note, the SiteCoords are identical to the raw Points array you passed-in when creating the Voronoi object, * I think. So ... you could safely re-use that here instead of fetching it from the Voronoi object (maybe; could be * some filteing happening? Dupes removed, etc?) */ List <Vector2> ses = m_points; // v.SiteCoords (); foreach (Vector2 siteCoord in ses) { if (randomizeVoronoiColours) /** Note: the Edges display above (in Gray) shows unconnected edges, * but this section re-uses the actual semi-polygons created automatically by the Voronoi algorithm. To prove * this you can optionally turn on colourization of the edges, so that that shared edges will show with same colours */ { Gizmos.color = new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f)); } else { Gizmos.color = Color.white; } /** NB: this is the reason we had to change VoronoiDemo class and save the Voronoi object: the boundaries * are the Voronoi polygons, the most precious thing from the algorithm. They are saved as Regions data structure * when you run the algorithm - but that data structure throws-away the Site/Point that generates each Region. */ List <LineSegment> outlineOfSite = v.VoronoiBoundaryForSite(siteCoord); List <Vector2> pointsOnPolygonOutline = null; if (CloseExternalVoronoPolys) { pointsOnPolygonOutline = new List <Vector2> (); } foreach (LineSegment seg in outlineOfSite) { Vector2 s = (Vector2)seg.p0; Vector2 e = (Vector2)seg.p1; if (randomizeVoronoiColours) { /** To make them easier to see, shift the vectors SLIGHTLY towards the center point. * * This lets you see EXACTLY what poly / partial poly the algorithm is giving us "for free", * so that triangulating it will be easy in your own projects */ s += (siteCoord - s) * 0.05f; e += (siteCoord - e) * 0.05f; } Gizmos.DrawLine(s, e); if (CloseExternalVoronoPolys) { pointsOnPolygonOutline.Add(s); pointsOnPolygonOutline.Add(e); } } if (CloseExternalVoronoPolys) { List <Vector2> unduplicatedPoints = new List <Vector2> (); //Debug.Log( "Closing outline; "+pointsOnPolygonOutline.Count+" points on outline, with "+outlineOfSite.Count+" lines between them"); foreach (Vector2 point in pointsOnPolygonOutline) { Vector2 dupe; if ((dupe = ListContainsVectorCloseToVector(unduplicatedPoints, point)) != Vector2.zero) { //Debug.Log( " - point: "+point); unduplicatedPoints.Remove(dupe); } else { //Debug.Log( " + point: "+point); unduplicatedPoints.Add(point); } } if (unduplicatedPoints.Count == 2) { // two points that need connecting Gizmos.DrawLine(unduplicatedPoints [0], unduplicatedPoints [1]); } else if (unduplicatedPoints.Count > 1) { Debug.LogError("Should only have 0 or 2 unconnected points in a single polygon; had: " + unduplicatedPoints.Count); } } if (DrawManualVoronoiLinesToCenter) { foreach (LineSegment seg in outlineOfSite) { Gizmos.color = Color.gray; Gizmos.DrawLine((Vector2)seg.p0, siteCoord); } } } } if (DrawBounds) { Gizmos.color = Color.yellow; Gizmos.DrawLine(new Vector2(0, 0), new Vector2(0, m_mapHeight)); Gizmos.DrawLine(new Vector2(0, 0), new Vector2(m_mapWidth, 0)); Gizmos.DrawLine(new Vector2(m_mapWidth, 0), new Vector2(m_mapWidth, m_mapHeight)); Gizmos.DrawLine(new Vector2(0, m_mapHeight), new Vector2(m_mapWidth, m_mapHeight)); } }
public static List<GameObject> GenerateVoronoiPieces(GameObject source, int extraPoints = 0, int subshatterSteps = 0, Material mat = null) { List<GameObject> pieces = new List<GameObject>(); if (mat == null) { mat = createFragmentMaterial(source); } //get transform information Vector3 origScale = source.transform.localScale; source.transform.localScale = Vector3.one; Quaternion origRotation = source.transform.localRotation; source.transform.localRotation = Quaternion.identity; //get rigidbody information Vector2 origVelocity = source.GetComponent<Rigidbody2D>().velocity; //get collider information PolygonCollider2D sourcePolyCollider = source.GetComponent<PolygonCollider2D>(); BoxCollider2D sourceBoxCollider = source.GetComponent<BoxCollider2D>(); List<Vector2> points = new List<Vector2>(); List<Vector2> borderPoints = new List<Vector2>(); if (sourcePolyCollider != null) { points = getPoints(sourcePolyCollider); borderPoints = getPoints(sourcePolyCollider); } else if (sourceBoxCollider != null) { points = getPoints(sourceBoxCollider); borderPoints = getPoints(sourceBoxCollider); } Rect rect = getRect(source); for (int i = 0; i < extraPoints; i++) { points.Add(new Vector2(Random.Range( rect.width / -2 + rect.center.x, rect.width / 2 + rect.center.x), Random.Range(rect.height / -2 + rect.center.y, rect.height / 2 + rect.center.y) )); } Voronoi voronoi = new Delaunay.Voronoi(points, null, rect); List<List<Vector2>> clippedRegions = new List<List<Vector2>>(); foreach (List<Vector2> region in voronoi.Regions()) { clippedRegions = ClipperHelper.clip(borderPoints, region); foreach (List<Vector2> clippedRegion in clippedRegions) { pieces.Add(generateVoronoiPiece(source, clippedRegion, origVelocity, origScale, origRotation, mat)); } } List<GameObject> morePieces = new List<GameObject>(); if (subshatterSteps > 0) { subshatterSteps--; foreach (GameObject piece in pieces) { morePieces.AddRange(SpriteExploder.GenerateVoronoiPieces(piece, extraPoints, subshatterSteps)); GameObject.DestroyImmediate(piece); } } else { morePieces = pieces; } //reset transform information source.transform.localScale = origScale; source.transform.localRotation = origRotation; Resources.UnloadUnusedAssets(); return morePieces; }
private static List <List <Vector2> > GenerateCylindricalVoronoi(List <Vector2> centroids, float width, float height) { var nullColors = new List <uint>(); //needed to call Voronoi(), but redundant in this use case int noOfCentroids = centroids.Count; for (int i = 0; i < noOfCentroids; i++) { //We copy all of the centroids to create 2 "ghost" versions of the voronoi which we we stitch onto either side of the real one. This will help us to cylindricalise the map. Vector2 ghostCentroidRight = new Vector2(centroids[i].x + width, centroids[i].y); Vector2 ghostCentroidRightRight = new Vector2(centroids[i].x + (2f * width), centroids[i].y); centroids.Add(ghostCentroidRight); centroids.Add(ghostCentroidRightRight); //the colors list has to be the same size as the centroids list nullColors.Add(0); nullColors.Add(0); nullColors.Add(0); } Delaunay.Voronoi voronoi = new Delaunay.Voronoi(centroids, nullColors, new Rect(0, 0, 3f * width, height)); List <List <Vector2> > vorRegions = voronoi.Regions(); var centralVorRegions = new List <List <Vector2> >(); //Now run the cylindricalisation step by removing all regions that are solely in the 2 ghost diagrams for (int i = 0; i < vorRegions.Count; i++) { bool hasPointInMiddle = false; for (int j = 0; j < vorRegions[i].Count; j++) { if ((vorRegions[i][j].x >= width) && (vorRegions[i][j].x < (2f * width))) { hasPointInMiddle = true; break; } } if (hasPointInMiddle) { centralVorRegions.Add(vorRegions[i]); // this region has points within our final diagram, so keep it } } var cylindricalVorRegions = new List <List <Vector2> >(); //Also remove any overlap regions on the left hand side so that we only have one copy of each wrap-around polygon (on the right hand side) for (int i = 0; i < centralVorRegions.Count; i++) { bool hasPointOutsideLeftBoundary = false; for (int j = 0; j < centralVorRegions[i].Count; j++) { if (centralVorRegions[i][j].x < width) { hasPointOutsideLeftBoundary = true; break; } } if (!hasPointOutsideLeftBoundary) { // this region does not spill over the left side, so keep it, and shift all its points to the left by a mesh width for (int p = 0; p < centralVorRegions[i].Count; p++) { centralVorRegions[i][p] = new Vector2(centralVorRegions[i][p].x - width, centralVorRegions[i][p].y); } cylindricalVorRegions.Add(centralVorRegions[i]); } } return(cylindricalVorRegions); }