public List <PolygroupModifier> AdvancedSubtractPolygroup(PolygroupModifier subjectPolygroup, List <Vector2> clippingPolygon) { // The polygons to keep from the subject polygroup, by index List <int> keptIndices = new List <int>(); // The new triangles added from the triangulated clipped polygons List <List <Vector2> > newTriangles = new List <List <Vector2> >(); foreach (int i in subjectPolygroup.keptIndices) { List <Vector2> originalPolygon = subjectPolygroup.originalPolygroup[i]; if (SubtractInternal(originalPolygon, clippingPolygon, out List <DTPolygon> subOutput)) { DTProfilerMarkers.Triangulation.Begin(); List <List <Vector2> > triangles = DTUtility.TriangulateAll(subOutput, TriangleNetTriangulator.Instance); DTProfilerMarkers.Triangulation.End(); newTriangles.AddRange(triangles); } else { keptIndices.Add(i); } } return(Polygrouper.AdvancedCreatePolygroups(subjectPolygroup.originalPolygroup, keptIndices, newTriangles)); }
public void SetPolygroup(PolygroupModifier polygroup) { this.polygroup = polygroup; }
public void ApplyPolygroupModifier(PolygroupModifier mod) { // Collider from polygon DTProfilerMarkers.ApplyCollider.Begin(); PolygonCollider2D polygonCollider = GetComponent <PolygonCollider2D>(); // If there is no existing polygroup, create one if (polygroup == null) { // Create a polygroup from the new polygons passed in polygroup = new PolygroupModifier(new DTConvexPolygroup(mod.newPolygons), Enumerable.Range(0, mod.newPolygons.Count).ToList(), null); // Add all polygons as paths polygonCollider.pathCount = mod.newPolygons.Count; for (int i = 0; i < mod.newPolygons.Count; i++) { polygonCollider.SetPath(i, mod.newPolygons[i]); } DTProfilerMarkers.ApplyCollider.End(); // Create mesh from triangulated polygon ApplyRenderMesh(polygroup.KeptPolygons.ToMesh()); return; } // Calculate the number of paths in the output. Must be at least large enough to contain the last kept // polygon. New polygons will fill gaps. If there are more gaps than new polygons, the gaps will remain. // If there are more new polygons than gaps, the number of paths will be extended accordingly. int minimumPaths = mod.keptIndices.Count == 0 ? 0 : mod.keptIndices[mod.keptIndices.Count - 1] + 1; int gaps = minimumPaths - mod.keptIndices.Count; int numPaths = minimumPaths + Mathf.Max(0, mod.newPolygons.Count - gaps); // Set number of paths in stored polygroup and in collider based on the calculations above if (polygroup.originalPolygroup.Count < numPaths) { polygroup.originalPolygroup.AddRange(Enumerable.Repeat <List <Vector2> >(null, numPaths - polygroup.originalPolygroup.Count)); } else if (polygroup.originalPolygroup.Count > numPaths) { polygroup.originalPolygroup.RemoveRange(numPaths, polygroup.originalPolygroup.Count - numPaths); } polygonCollider.pathCount = numPaths; int keptIndicesIndex = 0; int nextKeptIndex = keptIndicesIndex < polygroup.keptIndices.Count ? polygroup.keptIndices[keptIndicesIndex] : -1; int modKeptIndicesIndex = 0; int modNextKeptIndex = modKeptIndicesIndex < mod.keptIndices.Count ? mod.keptIndices[modKeptIndicesIndex] : -1; int modNewPolygonsIndex = 0; List <int> newKeptIndices = new List <int>(); for (int i = 0; i < numPaths; i++) { // If we are keeping this polygon, determine which polygon to keep next if (i == modNextKeptIndex) { keptIndicesIndex++; nextKeptIndex = keptIndicesIndex < polygroup.keptIndices.Count ? polygroup.keptIndices[keptIndicesIndex] : -1; modKeptIndicesIndex++; modNextKeptIndex = modKeptIndicesIndex < mod.keptIndices.Count ? mod.keptIndices[modKeptIndicesIndex] : -1; newKeptIndices.Add(i); } // If a new polygon should fill this spot, do so now else if (modNewPolygonsIndex < mod.newPolygons.Count) { polygroup.originalPolygroup[i] = mod.newPolygons[modNewPolygonsIndex]; polygonCollider.SetPath(i, mod.newPolygons[modNewPolygonsIndex]); modNewPolygonsIndex++; newKeptIndices.Add(i); // If the new polygon replaced an old one, determine the next polygon in the old list if (i == nextKeptIndex) { keptIndicesIndex++; nextKeptIndex = keptIndicesIndex < polygroup.keptIndices.Count ? polygroup.keptIndices[keptIndicesIndex] : -1; } } // If we are discarding this polygon and there are no new polygons to replace it, but we are keeping subsequent polygons, empty this path else if (i == nextKeptIndex) { keptIndicesIndex++; nextKeptIndex = keptIndicesIndex < polygroup.keptIndices.Count ? polygroup.keptIndices[keptIndicesIndex] : -1; polygonCollider.SetPath(i, new Vector2[0]); } } polygroup.keptIndices = newKeptIndices; if (GetComponent <Rigidbody2D>().mass < MassCutoff) { Destroy(gameObject); } DTProfilerMarkers.ApplyCollider.End(); // Create mesh from triangulated polygon ApplyRenderMesh(polygroup.KeptPolygons.ToMesh()); }
public void ExecuteExplosions(IEnumerable <Explosion> explosions, IEnumerable <DestructibleObject> dtObjects, IPolygonSubtractor subtractor) { ORourkeSubtractor oRourkeSub = (ORourkeSubtractor)subtractor; if (oRourkeSub == null) { throw new NotSupportedException("This explosion executor only supports ORourkeSubtractor"); } TriangleNetTriangulator.Instance.callCount = 0; // Store destructible objects in a new list, since we may add or remove some during processing List <DestructibleObject> dtObjectList = dtObjects.ToList(); // Add new destructible objects to this list instead of objectList until finished processing the current explosion List <DestructibleObject> pendingAdditions = new List <DestructibleObject>(); // Process all objects for all explosions foreach (var exp in explosions) { for (int i = 0; i < dtObjectList.Count; i++) { // Remove this object from the list if it has been destroyed if (dtObjectList[i] == null) { dtObjectList.RemoveAt(i--); continue; } // Cast this DO to an advanced DO var dtObj = (DO_Advanced_Triangle_Clip_Collide)dtObjectList[i]; if (dtObj == null) { throw new NotSupportedException("This explosion executor only supports DO_Advanced_Triangle_Clip_Collide"); } // Do basic AABB-circle check to see whether we can skip processing this destructible object with this explosion int bc = DTUtility.BoundsCheck(dtObj, exp); if (bc == -1) { // Object is not affected by explosion continue; } else if (bc == 1) { // Object is completely removed by explosion dtObjectList.RemoveAt(i--); UnityEngine.Object.Destroy(dtObj.gameObject); continue; } // Leave the polygroup in local coordinates and transform the explosion instead to the DO's space. // Note that this is stored in the subject DO and will be referenced by all PolygroupModifiers, // so changes to the original DO will affect all PolygroupModifiers. This shouldn't cause any // problems since we only need the indices anyway. PolygroupModifier inputPolygroup = dtObj.GetPolygroup(); List <Vector2> transformedExplosion = dtObj.InverseTransformPoints(exp.DTPolygon.Contour); // Subtract explosion polygon from destructible object polygon group DTProfilerMarkers.SubtractPolygroup.Begin(); List <PolygroupModifier> result = oRourkeSub.AdvancedSubtractPolygroup(inputPolygroup, transformedExplosion); DTProfilerMarkers.SubtractPolygroup.End(); int count = result.Count(); if (count == 0) { // If no output polygons, remove the current destrucible object dtObjectList.RemoveAt(i--); UnityEngine.Object.Destroy(dtObj.gameObject); continue; } else { // Otherwise apply the output polygons (fragments) to GameObjects (new or reused) for (int j = 0; j < result.Count; j++) { if (j < result.Count - 1) { // Duplicate the GameObject that was clipped by the explosion, so that we maintain properties such as velocity and also maintain the same collider + mesh GameObject go = UnityEngine.Object.Instantiate(dtObj.gameObject, dtObj.transform.parent); var newObj = go.GetComponent <DO_Advanced_Triangle_Clip_Collide>(); newObj.SetPolygroup(new PolygroupModifier(new DTConvexPolygroup(inputPolygroup.originalPolygroup), inputPolygroup.keptIndices, null)); // Apply the new clipped polygon list newObj.ApplyPolygroupModifier(result[j]); // Add it to the objectList, but not until after finished processing this explosion pendingAdditions.Add(newObj); continue; } else { // Reuse the existing GameObject by applying the new clipped polygon to it dtObj.ApplyPolygroupModifier(result[j]); continue; } } } } // Add pendingAdditions elements to objectList so that they are included when processing the next explosion in explosions dtObjectList.AddRange(pendingAdditions); pendingAdditions.Clear(); } Debug.Log("# Objects:" + dtObjectList.Count); Debug.Log("# Polygons:" + dtObjectList.Sum(obj => obj.GetTransformedPolygonList().Count)); Debug.Log("# Triangulation Calls:" + TriangleNetTriangulator.Instance.callCount); }