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));
        }
Esempio n. 2
0
 public void SetPolygroup(PolygroupModifier polygroup)
 {
     this.polygroup = polygroup;
 }
Esempio n. 3
0
        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);
        }