Beispiel #1
0
        public void OnExplosionFinished(int id)
        {
            var explosion = queue.Dequeue();

            Exploder2DUtils.Assert(explosion.id == id, "Explosion id mismatch!");
            ProcessQueue();
        }
Beispiel #2
0
        public void Explode(Exploder2DObject.OnExplosion callback)
        {
            var settings = new Exploder2DSettings
            {
                Position              = Exploder2DUtils.GetCentroid(_exploder2D.gameObject),
                DontUseTag            = _exploder2D.DontUseTag,
                Radius                = _exploder2D.Radius,
                ForceVector           = _exploder2D.ForceVector,
                UseForceVector        = _exploder2D.UseForceVector,
                Force                 = _exploder2D.Force,
                FrameBudget           = _exploder2D.FrameBudget,
                TargetFragments       = _exploder2D.TargetFragments,
                DeactivateOptions     = _exploder2D.DeactivateOptions,
                DeactivateTimeout     = _exploder2D.DeactivateTimeout,
                ExplodeSelf           = _exploder2D.ExplodeSelf,
                HideSelf              = _exploder2D.HideSelf,
                DestroyOriginalObject = _exploder2D.DestroyOriginalObject,
                ExplodeFragments      = _exploder2D.ExplodeFragments,
                SplitMeshIslands      = _exploder2D.SplitMeshIslands,
                FragmentOptions       = _exploder2D.FragmentOptions.Clone(),
                SfxOptions            = _exploder2D.SFXOptions.Clone(),
                Callback              = callback,
                processing            = false,
            };

            queue.Enqueue(settings);
            ProcessQueue();
        }
Beispiel #3
0
        /// <summary>
        /// create pool (array) of fragment game objects with all necessary components
        /// </summary>
        /// <param name="poolSize">number of fragments</param>
        public void Allocate(int poolSize)
        {
            Exploder2DUtils.Assert(poolSize > 0, "");

            if (pool == null || pool.Length < poolSize)
            {
                DestroyFragments();

                pool = new Fragment2D[poolSize];

                for (int i = 0; i < poolSize; i++)
                {
                    var fragment = new GameObject("fragment_" + i);
                    fragment.AddComponent <SpriteRenderer>();
                    fragment.AddComponent <PolygonCollider2D>();
                    fragment.AddComponent <Rigidbody2D>();
                    fragment.AddComponent <Exploder2DOption>();

                    var fragmentComponent = fragment.AddComponent <Fragment2D>();

                    fragment.transform.parent = gameObject.transform;

                    pool[i] = fragmentComponent;

                    Exploder2DUtils.SetActiveRecursively(fragment.gameObject, false);

                    fragmentComponent.RefreshComponentsCache();

                    fragmentComponent.Sleep();
                }
            }
        }
Beispiel #4
0
 void OnDrawGizmos()
 {
     if (enabled && !(ExplodeSelf && DisableRadiusScan))
     {
         Gizmos.color = Color.red;
         Gizmos.DrawWireSphere(Exploder2DUtils.GetCentroid(gameObject), Radius);
     }
 }
Beispiel #5
0
        /// <summary>
        /// explode cracked objects
        /// Use this method in combination with Crack()
        /// Purpose of this method is to get higher performance of explosion, Crack() will
        /// calculate the explosion and prepare all fragments. Calling ExplodeCracked() will
        /// then start the explosion (flying fragments...) immediately
        /// </summary>
        public void ExplodeCracked(OnExplosion callback)
        {
            Exploder2DUtils.Assert(crack, "You must call Crack() first!");

            if (cracked)
            {
                PostCrackExplode(callback);
                crack = false;
            }
        }
Beispiel #6
0
        private int GetLevel(float distance, float radius)
        {
            Exploder2DUtils.Assert(distance >= 0.0f, "");
            Exploder2DUtils.Assert(radius >= 0.0f, "");

            var normDistance = distance / radius * 6;
            var level        = (int)normDistance / 2 + 1;

            return(Mathf.Clamp(level, 0, 10));
        }
Beispiel #7
0
        /// <summary>
        /// crack will calculate fragments and prepare object for explosion
        /// Use this method in combination with ExplodeCracked()
        /// Purpose of this method is to get higher performance of explosion, Crack() will
        /// calculate the explosion and prepare all fragments. Calling ExplodeCracked() will
        /// then start the explosion (flying fragments...) immediately
        /// </summary>
        public void Crack(OnCracked callback)
        {
            Exploder2DUtils.Assert(!crack, "Another crack in progress!");

            if (!crack)
            {
                CrackedCallback = callback;
                crack           = true;
                cracked         = false;
                Explode(null);
            }
        }
Beispiel #8
0
        /// <summary>
        /// deactivate this fragment piece
        /// </summary>
        public void Deactivate()
        {
            Exploder2DUtils.SetActive(gameObject, false);
            visible   = false;
            activeObj = false;

            // turn off particles
            if (particleSystems != null)
            {
                foreach (var psystem in particleSystems)
                {
                    psystem.Clear();
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// this is called from exploder class to start the explosion
        /// </summary>
        public void Explode()
        {
            activeObj = true;
            Exploder2DUtils.SetActiveRecursively(gameObject, true);
            visibilityCheckTimer = 0.1f;
            visible         = true;
            deactivateTimer = deactivateTimeout;
            originalScale   = transform.localScale;

            if (explodable)
            {
                tag = Exploder2DObject.Tag;
            }

            Emit(true);
        }
Beispiel #10
0
        /// <summary>
        /// callback from queue, do not call this unles you know what you are doing!
        /// </summary>
        public void StartExplosionFromQueue(Vector2 pos, int id, OnExplosion callback)
        {
            Exploder2DUtils.Assert(state == State.None, "Wrong state: " + state);

            mainCentroid      = pos;
            explosionID       = id;
            state             = State.Preprocess;
            ExplosionCallback = callback;

#if DBG
            processingTime        = 0.0f;
            preProcessingTime     = 0.0f;
            postProcessingTime    = 0.0f;
            postProcessingTimeEnd = 0.0f;
            isolatingIslandsTime  = 0.0f;
            cuts = 0;
#endif
        }
Beispiel #11
0
        /// <summary>
        /// returns list of currently active (visible) fragments
        /// </summary>
        /// <returns></returns>
        public List <Fragment2D> GetActiveFragments()
        {
            if (pool != null)
            {
                var list = new List <Fragment2D>(pool.Length);

                foreach (var fragment in pool)
                {
                    if (Exploder2DUtils.IsActive(fragment.gameObject))
                    {
                        list.Add(fragment);
                    }
                }

                return(list);
            }

            return(null);
        }
Beispiel #12
0
        void Update()
        {
            if (activeObj)
            {
                //
                // clamp velocity
                //
                if (rigidBody)
                {
                    if (rigidBody.velocity.sqrMagnitude > maxVelocity * maxVelocity)
                    {
                        var vel = rigidBody.velocity.normalized;
                        rigidBody.velocity = vel * maxVelocity;
                    }
                }
                else if (rigid2D)
                {
                    if (rigid2D.velocity.sqrMagnitude > maxVelocity * maxVelocity)
                    {
                        var vel = rigid2D.velocity.normalized;
                        rigid2D.velocity = vel * maxVelocity;
                    }
                }

                if (deactivateOptions == DeactivateOptions.Timeout)
                {
                    deactivateTimer -= Time.deltaTime;

                    if (deactivateTimer < 0.0f)
                    {
                        Sleep();
                        activeObj = false;
                        Exploder2DUtils.SetActiveRecursively(gameObject, false);

                        // return fragment to previous fadout state
                        switch (fadeoutOptions)
                        {
                        case FadeoutOptions.FadeoutAlpha:
                            break;
                        }
                    }
                    else
                    {
                        var t = deactivateTimer / deactivateTimeout;

                        switch (fadeoutOptions)
                        {
                        case FadeoutOptions.FadeoutAlpha:
                            var color = spriteRenderer.color;
                            color.a = t;
                            spriteRenderer.color = color;
                            break;

                        case FadeoutOptions.ScaleDown:
                            gameObject.transform.localScale = originalScale * t;
                            break;
                        }
                    }
                }

                visibilityCheckTimer -= Time.deltaTime;

                if (visibilityCheckTimer < 0.0f && UnityEngine.Camera.main)
                {
                    var viewportPoint = UnityEngine.Camera.main.WorldToViewportPoint(transform.position);

                    if (viewportPoint.z < 0 || viewportPoint.x < 0 || viewportPoint.y < 0 ||
                        viewportPoint.x > 1 || viewportPoint.y > 1)
                    {
                        if (deactivateOptions == DeactivateOptions.OutsideOfCamera)
                        {
                            Sleep();
                            activeObj = false;
                            Exploder2DUtils.SetActiveRecursively(gameObject, false);
                        }

                        visible = false;
                    }
                    else
                    {
                        visible = true;
                    }

                    visibilityCheckTimer = Random.Range(0.1f, 0.3f);

                    if (explodable)
                    {
                        var size = GetComponent <Collider>().bounds.size;

                        if (Mathf.Max(size.x, size.y, size.z) < minSizeToExplode)
                        {
                            tag = string.Empty;
                        }
                    }
                }
            }
        }
Beispiel #13
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;
            }
        }
Beispiel #14
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);
        }
Beispiel #15
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);
        }
Beispiel #16
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);
        }
Beispiel #17
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);
        }
Beispiel #18
0
        /// <summary>
        /// returns list of fragments with requested size
        /// this method pick fragments hidden from camera or sleeping rather then visible
        /// </summary>
        /// <param name="size">number of requested fragments</param>
        /// <returns>list of fragments</returns>
        public List <Fragment2D> GetAvailableFragments(int size)
        {
            if (size > pool.Length)
            {
                Debug.LogError("Requesting pool size higher than allocated! Please call Allocate first! " + size);
                return(null);
            }

            if (size == pool.Length)
            {
                return(new List <Fragment2D>(pool));
            }

            var fragments = new List <Fragment2D>();

            int counter = 0;

            // get deactivated fragments first
            foreach (var fragment in pool)
            {
                // get invisible fragments
                if (!fragment.activeObj)
                {
                    fragments.Add(fragment);
                    counter++;
                }

                if (counter == size)
                {
                    return(fragments);
                }
            }

            foreach (var fragment in pool)
            {
                // get invisible fragments
                if (!fragment.visible)
                {
                    fragments.Add(fragment);
                    counter++;
                }

                if (counter == size)
                {
                    return(fragments);
                }
            }

            // there are still live fragments ... get sleeping ones
            if (counter < size)
            {
                foreach (var fragment in pool)
                {
                    if (fragment.IsSleeping() && fragment.visible)
                    {
                        Exploder2DUtils.Assert(!fragments.Contains(fragment), "!!!");
                        fragments.Add(fragment);
                        counter++;
                    }

                    if (counter == size)
                    {
                        return(fragments);
                    }
                }
            }

            // there are still live fragments...
            if (counter < size)
            {
                foreach (var fragment in pool)
                {
                    if (!fragment.IsSleeping() && fragment.visible)
                    {
                        Exploder2DUtils.Assert(!fragments.Contains(fragment), "!!!");
                        fragments.Add(fragment);
                        counter++;
                    }

                    if (counter == size)
                    {
                        return(fragments);
                    }
                }
            }

            Exploder2DUtils.Assert(false, "ERROR!!!");
            return(null);
        }
Beispiel #19
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);
        }