Ejemplo n.º 1
0
        void Update()
        {
            long cuttingTime = 0;

            switch (state)
            {
            case State.None:
                break;

            case State.Preprocess:
            {
                timer.Reset();
                timer.Start();
#if DBG
                var watch = new Stopwatch();
                watch.Start();
#endif

                // get mesh data from game object in radius
                var readyToCut = Preprocess();

#if DBG
                watch.Stop();
                preProcessingTime = watch.ElapsedMilliseconds;
                processingFrames  = 0;
#endif

                // nothing to explode
                if (!readyToCut)
                {
#if DBG
                    Exploder2DUtils.Log("Nothing to explode " + mainCentroid);
#endif
                    OnExplosionFinished(false);
                }
                else
                {
                    // continue to cutter, don't wait to another frame
                    state = State.ProcessCutter;
                    goto case State.ProcessCutter;
                }
            }
            break;

            case State.ProcessCutter:
            {
#if DBG
                processingFrames++;
                var watch = new Stopwatch();
                watch.Start();
#endif

                // process main cutter
                var cuttingFinished = false;

                switch (CuttingStrategy)
                {
                case CutStrategy.Randomized:
                    cuttingFinished = ProcessCutterRandomized(out cuttingTime);
                    break;

//                            case CutStrategy.Grid:
//                                cuttingFinished = ProcessCutterGrid(out cuttingTime);
//                                break;

                default: Exploder2DUtils.Assert(false, "Invalid cutting strategy");
                    break;
                }

#if DBG
                watch.Stop();
                processingTime += watch.ElapsedMilliseconds;
#endif

                if (cuttingFinished)
                {
                    poolIdx  = 0;
                    postList = new List <CutMesh>(meshSet);

                    // continue to next state if the cutter is finished
                    if (splitMeshIslands)
                    {
#if DBG
                        isolatingIslandsFrames = 0;
                        isolatingIslandsTime   = 0.0f;
#endif
                        islands = new List <CutMesh>(meshSet.Count);

                        state = State.IsolateMeshIslands;
                        goto case State.IsolateMeshIslands;
                    }

                    state = State.PostprocessInit;
                    goto case State.PostprocessInit;
                }
            }
            break;

            case State.IsolateMeshIslands:
            {
#if DBG
                var watchPost = new Stopwatch();
                watchPost.Start();
#endif

                var isolatingFinished = IsolateMeshIslands(ref cuttingTime);

#if DBG
                watchPost.Stop();
                isolatingIslandsFrames++;
                isolatingIslandsTime += watchPost.ElapsedMilliseconds;
#endif

                if (isolatingFinished)
                {
                    // goto next state
                    state = State.PostprocessInit;
                    goto case State.PostprocessInit;
                }
            }
            break;

            case State.PostprocessInit:
            {
                InitPostprocess();

                state = State.Postprocess;
                goto case State.Postprocess;
            }

            case State.Postprocess:
            {
#if DBG
                var watchPost = new Stopwatch();
                watchPost.Start();
#endif
                if (Postprocess(cuttingTime))
                {
                    timer.Stop();
                }
#if DBG
                watchPost.Stop();
                postProcessingTime += watchPost.ElapsedMilliseconds;
#endif
            }
            break;
            }
        }
Ejemplo n.º 2
0
        private List <CutMesh> GetMeshList()
        {
            GameObject[] objects = null;

            if (DontUseTag)
            {
                var objs    = FindObjectsOfType(typeof(Explodable2D));
                var objList = new List <GameObject>(objs.Length);

                foreach (var o in objs)
                {
                    var ex = (Explodable2D)o;

                    if (ex)
                    {
                        objList.Add(ex.gameObject);
                    }
                }

                objects = objList.ToArray();
            }
            else
            {
                objects = GameObject.FindGameObjectsWithTag(Tag);
            }

            var list = new List <CutMesh>(objects.Length);

            foreach (var o in objects)
            {
                // don't destroy the destroyer :)
                if (!ExplodeSelf && o == gameObject)
                {
                    continue;
                }

                // stop scanning for object is case of ExplodeSelf
                if (o != gameObject && ExplodeSelf && DisableRadiusScan)
                {
                    continue;
                }

//                UnityEngine.Debug.DrawLine(mainCentroid, mainCentroid + Vector2.up*100, Color.green, 100);

                var distance2 = (Exploder2DUtils.GetCentroid(o) - mainCentroid).sqrMagnitude;

                if (distance2 < Radius * Radius)
                {
                    var meshData    = GetMeshData(o);
                    var meshDataLen = meshData.Count;

                    for (var i = 0; i < meshDataLen; i++)
                    {
                        var centroid = meshData[i].centroid;
                        var distance = (centroid - mainCentroid).magnitude;

//                    UnityEngine.Debug.Log("Distance: " + distance + " " + meshData[i].gameObject.name);

                        var layer = FragmentOptions.InheritSortingLayer
                            ? meshData[i].spriteRenderer.sortingLayerName
                            : FragmentOptions.SortingLayer;
                        var order = FragmentOptions.InheritOrderInLayer
                            ? meshData[i].spriteRenderer.sortingOrder
                            : FragmentOptions.OrderInLayer;
                        var color = FragmentOptions.InheritSpriteRendererColor
                            ? meshData[i].spriteRenderer.color
                            : FragmentOptions.SpriteRendererColor;

                        list.Add(new CutMesh
                        {
                            spriteMesh    = meshData[i].spriteMesh,
                            centroidLocal = meshData[i].gameObject.transform.InverseTransformPoint(centroid),
                            transform     = meshData[i].gameObject.transform,

                            sprite     = meshData[i].sprite,
                            parent     = meshData[i].gameObject.transform.parent,
                            position   = meshData[i].gameObject.transform.position,
                            rotation   = meshData[i].gameObject.transform.rotation,
                            localScale = meshData[i].gameObject.transform.localScale,

                            distance = distance,
                            level    = GetLevel(distance, Radius),
                            original = meshData[i].parentObject,

                            sortingLayer = layer,
                            orderInLayer = order,
                            color        = color,

                            option = o.GetComponent <Exploder2DOption>(),
                        });
                    }
                }
            }

            if (list.Count == 0)
            {
#if DBG
                Exploder2DUtils.Log("No explodable objects found!");
#endif
                return(list);
            }

            list.Sort(delegate(CutMesh m0, CutMesh m1)
            {
                return((m0.level).CompareTo(m1.level));
            });

            // for the case when the count of objects is higher then target fragments
            if (list.Count > TargetFragments)
            {
                list.RemoveRange(TargetFragments - 1, list.Count - TargetFragments);
            }

            var levelMax          = list[list.Count - 1].level;
            var fragmentsPerLevel = GetLevelFragments(levelMax, TargetFragments);

            int maxCount  = 0;
            var listCount = list.Count;

            var levelCount = new int[levelMax + 1];
            foreach (var cutMesh in list)
            {
                levelCount[cutMesh.level]++;
            }

            for (int i = 0; i < listCount; i++)
            {
                var cutMesh = list[i];

                var curLevelRatio = levelMax + 1 - cutMesh.level;

                var fragments = (int)((curLevelRatio * fragmentsPerLevel) / levelCount[cutMesh.level]);

                cutMesh.fragments = fragments;

                maxCount += fragments;

                list[i] = cutMesh;

                if (maxCount >= TargetFragments)
                {
                    cutMesh.fragments -= maxCount - TargetFragments;
                    maxCount          -= maxCount - TargetFragments;

                    list[i] = cutMesh;

                    break;
                }
            }

//        foreach (var cutMesh in list)
//        {
//            UnityEngine.Debug.Log(cutMesh.level + " " + cutMesh.distance + " " + cutMesh.fragments);
//        }

            return(list);
        }
Ejemplo n.º 3
0
        bool Postprocess(long timeOffset)
        {
            var postTimer = new Stopwatch();

            postTimer.Start();

            var count = postList.Count;

#if DBG
            postProcessingFrames++;
#endif

            while (poolIdx < count)
            {
                var fragment = pool[poolIdx];
                var mesh     = postList[poolIdx];

                poolIdx++;

                if (!mesh.original)
                {
                    continue;
                }

                if (crack)
                {
                    Exploder2DUtils.SetActiveRecursively(fragment.gameObject, false);
                }

                fragment.CreateSprite(mesh.spriteMesh, mesh.sprite, mesh.original.transform, mesh.sortingLayer, mesh.orderInLayer, mesh.color);

                var oldParent = fragment.transform.parent;
                fragment.transform.parent     = mesh.parent;
                fragment.transform.position   = new Vector3(mesh.position.x, mesh.position.y, mesh.original.transform.position.z);
                fragment.transform.rotation   = mesh.rotation;
                fragment.transform.localScale = mesh.localScale;
                fragment.transform.parent     = null;
                fragment.transform.parent     = oldParent;

                if (!crack)
                {
                    if (mesh.original != gameObject)
                    {
                        Exploder2DUtils.SetActiveRecursively(mesh.original, false);
                    }
                    else
                    {
                        Exploder2DUtils.EnableCollider(mesh.original, false);
                        Exploder2DUtils.SetVisible(mesh.original, false);
                    }
                }

                if (!FragmentOptions.DisableColliders)
                {
                    Core.MeshUtils.GeneratePolygonCollider(fragment.polygonCollider2D, mesh.spriteMesh);
                }

                if (mesh.option)
                {
                    mesh.option.DuplicateSettings(fragment.options);
                }

                if (!crack)
                {
                    fragment.Explode();
                }

                var force = Force;
                if (mesh.option && mesh.option.UseLocalForce)
                {
                    force = mesh.option.Force;
                }

                // apply force to rigid body
                fragment.ApplyExplosion2D(mesh.transform, mesh.centroidLocal, mainCentroid, FragmentOptions, UseForceVector,
                                          ForceVector, force, mesh.original, TargetFragments);

#if SHOW_DEBUG_LINES
                UnityEngine.Debug.DrawLine(mainCentroid, forceVector * Force, Color.yellow, 3);
#endif

                if (postTimer.ElapsedMilliseconds + timeOffset > FrameBudget)
                {
                    return(false);
                }
            }

#if DBG
            var watch = new Stopwatch();
            watch.Start();
#endif

            if (!crack)
            {
                if (DestroyOriginalObject)
                {
                    foreach (var mesh in postList)
                    {
                        if (mesh.original && !mesh.original.GetComponent <Fragment2D>())
                        {
                            Object.Destroy(mesh.original);
                        }
                    }
                }

                if (ExplodeSelf)
                {
                    if (!DestroyOriginalObject)
                    {
                        Exploder2DUtils.SetActiveRecursively(gameObject, false);
                    }
                }

                if (HideSelf)
                {
                    Exploder2DUtils.SetActiveRecursively(gameObject, false);
                }

#if DBG
                Exploder2DUtils.Log("Explosion finished! " + postList.Count + postList[0].original.transform.gameObject.name);
#endif
                OnExplosionFinished(true);
            }
            else
            {
                cracked = true;

                if (CrackedCallback != null)
                {
                    CrackedCallback();
                }
            }

#if DBG
            postProcessingTimeEnd = watch.ElapsedMilliseconds;
#endif

            return(true);
        }
Ejemplo n.º 4
0
        void PostCrackExplode(OnExplosion callback)
        {
            if (callback != null)
            {
                callback(0.0f, ExplosionState.ExplosionStarted);
            }

            var count = postList.Count;

            poolIdx = 0;

            while (poolIdx < count)
            {
                var fragment = pool[poolIdx];
                var mesh     = postList[poolIdx];

                poolIdx++;

                if (mesh.original != gameObject)
                {
                    Exploder2DUtils.SetActiveRecursively(mesh.original, false);
                }
                else
                {
                    Exploder2DUtils.EnableCollider(mesh.original, false);
                    Exploder2DUtils.SetVisible(mesh.original, false);
                }

                fragment.Explode();
            }

            if (DestroyOriginalObject)
            {
                foreach (var mesh in postList)
                {
                    if (mesh.original && !mesh.original.GetComponent <Fragment2D>())
                    {
                        Object.Destroy(mesh.original);
                    }
                }
            }

            if (ExplodeSelf)
            {
                if (!DestroyOriginalObject)
                {
                    Exploder2DUtils.SetActiveRecursively(gameObject, false);
                }
            }

            if (HideSelf)
            {
                Exploder2DUtils.SetActiveRecursively(gameObject, false);
            }

#if DBG
            Exploder2DUtils.Log("Crack finished! " + postList.Count + postList[0].original.transform.gameObject.name);
#endif
            ExplosionCallback = callback;
            OnExplosionFinished(true);
        }
Ejemplo n.º 5
0
        bool IsolateMeshIslands(ref long timeOffset)
        {
            var timer = new Stopwatch();

            timer.Start();

            var count = postList.Count;

            while (poolIdx < count)
            {
                var mesh = postList[poolIdx];
                poolIdx++;

                var islandsFound = false;

                if (SplitMeshIslands || (mesh.option && mesh.option.SplitMeshIslands))
                {
                    var meshIslands = MeshUtils.IsolateMeshIslands(mesh.spriteMesh);

                    if (meshIslands != null)
                    {
                        islandsFound = true;

                        foreach (var meshIsland in meshIslands)
                        {
                            islands.Add(new CutMesh
                            {
                                spriteMesh    = meshIsland.mesh,
                                centroidLocal = meshIsland.centroidLocal,

                                sprite    = mesh.sprite,
                                vertices  = mesh.vertices,
                                transform = mesh.transform,
                                distance  = mesh.distance,
                                level     = mesh.level,
                                fragments = mesh.fragments,
                                original  = mesh.original,

                                parent     = mesh.transform.parent,
                                position   = mesh.transform.position,
                                rotation   = mesh.transform.rotation,
                                localScale = mesh.transform.localScale,

                                sortingLayer = mesh.sortingLayer,
                                orderInLayer = mesh.orderInLayer,
                                color        = mesh.color,

                                option = mesh.option,
                            });
                        }
                    }
                }

                if (!islandsFound)
                {
                    islands.Add(mesh);
                }

                if (timer.ElapsedMilliseconds + timeOffset > FrameBudget)
                {
                    return(false);
                }
            }

#if DBG
            Exploder2DUtils.Log("Replacing fragments: " + postList.Count + " by islands: " + islands.Count);
#endif

            // replace postList by island list
            postList = islands;

            return(true);
        }
Ejemplo n.º 6
0
        private bool ProcessCutterRandomized(out long cuttingTime)
        {
            Exploder2DUtils.Assert(state == State.ProcessCutter || state == State.DryRun, "Wrong state!");

            var stopWatch = new Stopwatch();

            stopWatch.Start();

            bool cutting        = true;
            bool timeBudgetStop = false;
            var  cycleCounter   = 0;

            cuttingTime = 0;

            while (cutting)
            {
                cycleCounter++;

                if (cycleCounter > TargetFragments)
                {
                    Exploder2DUtils.Log("Explode Infinite loop!");
                    break;
                }

                newFragments.Clear();
                meshToRemove.Clear();

                cutting = false;
                var fragmentsCount = meshSet.Count;

                foreach (var mesh in meshSet)
                {
                    if (levelCount[mesh.level] > 0)
                    {
                        var randomLineNormalized = Random.insideUnitCircle;

                        if (!mesh.transform)
                        {
                            continue;
                        }

                        var plane = Core.Math.Line2D.CreateNormalPoint(randomLineNormalized, mesh.centroidLocal);

#if DBG
                        cuts++;
#endif

                        if (mesh.option)
                        {
                            splitMeshIslands |= mesh.option.SplitMeshIslands;
                        }

                        List <CutterMesh> meshes = null;
                        cutter.Cut(mesh.spriteMesh, mesh.transform, plane, ref meshes);

                        cutting = true;

                        if (meshes != null)
                        {
                            foreach (var cutterMesh in meshes)
                            {
                                newFragments.Add(new CutMesh
                                {
                                    spriteMesh    = cutterMesh.mesh,
                                    centroidLocal = cutterMesh.centroidLocal,

                                    sprite    = mesh.sprite,
                                    vertices  = mesh.vertices,
                                    transform = mesh.transform,
                                    distance  = mesh.distance,
                                    level     = mesh.level,
                                    fragments = mesh.fragments,
                                    original  = mesh.original,

                                    parent     = mesh.transform.parent,
                                    position   = mesh.transform.position,
                                    rotation   = mesh.transform.rotation,
                                    localScale = mesh.transform.localScale,

                                    sortingLayer = mesh.sortingLayer,
                                    orderInLayer = mesh.orderInLayer,
                                    color        = mesh.color,

                                    option = mesh.option,
                                });
                            }

                            meshToRemove.Add(mesh);

                            levelCount[mesh.level] -= 1;

                            // stop this madness!
                            if (fragmentsCount + newFragments.Count - meshToRemove.Count >= TargetFragments)
                            {
                                cuttingTime = stopWatch.ElapsedMilliseconds;
                                meshSet.ExceptWith(meshToRemove);
                                meshSet.UnionWith(newFragments);
                                return(true);
                            }

                            // computation took more than FrameBudget ...
                            if (stopWatch.ElapsedMilliseconds > FrameBudget)
                            {
                                timeBudgetStop = true;
                                break;
                            }
                        }
                    }
                }

                meshSet.ExceptWith(meshToRemove);
                meshSet.UnionWith(newFragments);

                if (timeBudgetStop)
                {
                    break;
                }
            }

            cuttingTime = stopWatch.ElapsedMilliseconds;

            // explosion is finished
            if (!timeBudgetStop)
            {
                return(true);
            }

            return(false);
        }