public static List <Body> GeneratePolygons(List <VoronoiCell> cells, out List <VertexPositionTexture> verticeList, bool setSolid = true) { verticeList = new List <VertexPositionTexture>(); var bodies = new List <Body>(); List <Vector2> tempVertices = new List <Vector2>(); List <Vector2> bodyPoints = new List <Vector2>(); for (int n = cells.Count - 1; n >= 0; n--) { VoronoiCell cell = cells[n]; bodyPoints.Clear(); tempVertices.Clear(); foreach (GraphEdge ge in cell.edges) { if (Math.Abs(Vector2.Distance(ge.point1, ge.point2)) < 0.1f) { continue; } if (!tempVertices.Contains(ge.point1)) { tempVertices.Add(ge.point1); } if (!tempVertices.Contains(ge.point2)) { tempVertices.Add(ge.point2); } VoronoiCell adjacentCell = ge.AdjacentCell(cell); //if (adjacentCell!=null && cells.Contains(adjacentCell)) continue; if (setSolid) { ge.isSolid = (adjacentCell == null || !cells.Contains(adjacentCell)); } if (!bodyPoints.Contains(ge.point1)) { bodyPoints.Add(ge.point1); } if (!bodyPoints.Contains(ge.point2)) { bodyPoints.Add(ge.point2); } } if (tempVertices.Count < 3 || bodyPoints.Count < 2) { cells.RemoveAt(n); continue; } var triangles = MathUtils.TriangulateConvexHull(tempVertices, cell.Center); for (int i = 0; i < triangles.Count; i++) { foreach (Vector2 vertex in triangles[i]) { //shift the coordinates around a bit to make the texture repetition less obvious Vector2 uvCoords = new Vector2( vertex.X / 2000.0f + (float)Math.Sin(vertex.X / 500.0f) * 0.15f, vertex.Y / 2000.0f + (float)Math.Sin(vertex.Y / 700.0f) * 0.15f); verticeList.Add(new VertexPositionTexture(new Vector3(vertex, 1.0f), uvCoords)); } } if (bodyPoints.Count < 2) { continue; } if (bodyPoints.Count < 3) { foreach (Vector2 vertex in tempVertices) { if (bodyPoints.Contains(vertex)) { continue; } bodyPoints.Add(vertex); break; } } for (int i = 0; i < bodyPoints.Count; i++) { cell.bodyVertices.Add(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); } if (cell.CellType == CellType.Empty) { continue; } triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); Body cellBody = new Body(GameMain.World); for (int i = 0; i < triangles.Count; i++) { //don't create a triangle if any of the vertices are too close to each other //(apparently Farseer doesn't like polygons with a very small area, see Shape.ComputeProperties) if (Vector2.Distance(triangles[i][0], triangles[i][1]) < 0.05f || Vector2.Distance(triangles[i][0], triangles[i][2]) < 0.05f || Vector2.Distance(triangles[i][1], triangles[i][2]) < 0.05f) { continue; } Vertices bodyVertices = new Vertices(triangles[i]); FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); } cellBody.UserData = cell; cellBody.SleepingAllowed = false; cellBody.BodyType = BodyType.Kinematic; cellBody.CollisionCategories = Physics.CollisionLevel; cell.body = cellBody; bodies.Add(cellBody); } return(bodies); }
public static Body GeneratePolygons(List<VoronoiCell> cells, Level level, out List<Vector2[]> renderTriangles) { renderTriangles = new List<Vector2[]>(); List<Vector2> tempVertices = new List<Vector2>(); List<Vector2> bodyPoints = new List<Vector2>(); Body cellBody = new Body(GameMain.World) { SleepingAllowed = false, BodyType = BodyType.Static, CollisionCategories = Physics.CollisionLevel }; for (int n = cells.Count - 1; n >= 0; n-- ) { VoronoiCell cell = cells[n]; bodyPoints.Clear(); tempVertices.Clear(); foreach (GraphEdge ge in cell.Edges) { if (Vector2.DistanceSquared(ge.Point1, ge.Point2) < 0.01f) continue; if (!tempVertices.Any(v => Vector2.DistanceSquared(ge.Point1, v) < 1.0f)) { tempVertices.Add(ge.Point1); bodyPoints.Add(ge.Point1); } if (!tempVertices.Any(v => Vector2.DistanceSquared(ge.Point2, v) < 1.0f)) { tempVertices.Add(ge.Point2); bodyPoints.Add(ge.Point2); } } if (tempVertices.Count < 3 || bodyPoints.Count < 2) { cells.RemoveAt(n); continue; } renderTriangles.AddRange(MathUtils.TriangulateConvexHull(tempVertices, cell.Center)); if (bodyPoints.Count < 2) continue; if (bodyPoints.Count < 3) { foreach (Vector2 vertex in tempVertices) { if (bodyPoints.Contains(vertex)) continue; bodyPoints.Add(vertex); break; } } for (int i = 0; i < bodyPoints.Count; i++) { cell.BodyVertices.Add(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); } if (cell.CellType == CellType.Empty) continue; cellBody.UserData = cell; var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); for (int i = 0; i < triangles.Count; i++) { //don't create a triangle if the area of the triangle is too small //(apparently Farseer doesn't like polygons with a very small area, see Shape.ComputeProperties) Vector2 a = triangles[i][0]; Vector2 b = triangles[i][1]; Vector2 c = triangles[i][2]; float area = Math.Abs(a.X * (b.Y - c.Y) + b.X * (c.Y - a.Y) + c.X * (a.Y - b.Y)) / 2.0f; if (area < 1.0f) continue; Vertices bodyVertices = new Vertices(triangles[i]); var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); newFixture.UserData = cell; if (newFixture.Shape.MassData.Area < FarseerPhysics.Settings.Epsilon) { DebugConsole.ThrowError("Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + ")"); GameAnalyticsManager.AddErrorEventOnce( "CaveGenerator.GeneratePolygons:InvalidTriangle", GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + "). Seed: " + level.Seed); } } cell.Body = cellBody; } return cellBody; }
public static List <Body> GeneratePolygons(List <VoronoiCell> cells, Level level, out List <Vector2[]> renderTriangles, bool setSolid = true) { renderTriangles = new List <Vector2[]>(); var bodies = new List <Body>(); List <Vector2> tempVertices = new List <Vector2>(); List <Vector2> bodyPoints = new List <Vector2>(); Body cellBody = new Body(GameMain.World) { SleepingAllowed = false, BodyType = BodyType.Static, CollisionCategories = Physics.CollisionLevel }; bodies.Add(cellBody); for (int n = cells.Count - 1; n >= 0; n--) { VoronoiCell cell = cells[n]; bodyPoints.Clear(); tempVertices.Clear(); foreach (GraphEdge ge in cell.edges) { if (Math.Abs(Vector2.Distance(ge.point1, ge.point2)) < 0.1f) { continue; } if (!tempVertices.Contains(ge.point1)) { tempVertices.Add(ge.point1); } if (!tempVertices.Contains(ge.point2)) { tempVertices.Add(ge.point2); } VoronoiCell adjacentCell = ge.AdjacentCell(cell); //if (adjacentCell!=null && cells.Contains(adjacentCell)) continue; if (setSolid) { ge.isSolid = (adjacentCell == null || !cells.Contains(adjacentCell)); } if (!bodyPoints.Contains(ge.point1)) { bodyPoints.Add(ge.point1); } if (!bodyPoints.Contains(ge.point2)) { bodyPoints.Add(ge.point2); } } if (tempVertices.Count < 3 || bodyPoints.Count < 2) { cells.RemoveAt(n); continue; } renderTriangles.AddRange(MathUtils.TriangulateConvexHull(tempVertices, cell.Center)); if (bodyPoints.Count < 2) { continue; } if (bodyPoints.Count < 3) { foreach (Vector2 vertex in tempVertices) { if (bodyPoints.Contains(vertex)) { continue; } bodyPoints.Add(vertex); break; } } for (int i = 0; i < bodyPoints.Count; i++) { cell.bodyVertices.Add(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); } if (cell.CellType == CellType.Empty) { continue; } cellBody.UserData = cell; var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); for (int i = 0; i < triangles.Count; i++) { //don't create a triangle if any of the vertices are too close to each other //(apparently Farseer doesn't like polygons with a very small area, see Shape.ComputeProperties) if (Vector2.DistanceSquared(triangles[i][0], triangles[i][1]) < 0.006f || Vector2.DistanceSquared(triangles[i][0], triangles[i][2]) < 0.006f || Vector2.DistanceSquared(triangles[i][1], triangles[i][2]) < 0.006f) { continue; } Vertices bodyVertices = new Vertices(triangles[i]); var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); newFixture.UserData = cell; if (newFixture.Shape.MassData.Area < FarseerPhysics.Settings.Epsilon) { DebugConsole.ThrowError("Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + ")"); GameAnalyticsManager.AddErrorEventOnce( "CaveGenerator.GeneratePolygons:InvalidTriangle", GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + "). Seed: " + level.Seed); } } cell.body = cellBody; } return(bodies); }