Esempio n. 1
0
        // Init collapse after connection loss
        static void CollapseCluster(RayfireRigid scr)
        {
            // Collect solo shards, remove from cluster, no need to reinit
            List <RFShard> detachShards = new List <RFShard>();

            RFCluster.GetSoloShards(scr.clusterDemolition.cluster, detachShards);

            // Clear fragments in case of previous demolition
            if (scr.HasFragments == true)
            {
                scr.fragments.Clear();
            }

            // Dynamic cluster connectivity check, all clusters are equal, pick biggest to keep as original
            if (scr.simulationType == SimType.Dynamic || scr.simulationType == SimType.Sleeping)
            {
                // Check left cluster shards for connectivity and collect not connected child clusters. Should be before ClusterizeDetachShards
                RFCluster.ConnectivityCheck(scr.clusterDemolition.cluster);

                // Cluster is not connected. Set biggest child cluster shards to original cluster. Cant be 1 child cluster here
                RFCluster.ReduceChildClusters(scr.clusterDemolition.cluster);
            }

            // Kinematik/ Inactive cluster, Connectivity check if cluster has uny shards. Main cluster keeps all not activated
            else if (scr.simulationType == SimType.Kinematic || scr.simulationType == SimType.Inactive)
            {
                RFCluster.ConnectivityUnyCheck(scr.clusterDemolition.cluster);
            }

            // Init final cluster ops
            RFDemolitionCluster.PostDemolitionCluster(scr, detachShards);
        }
Esempio n. 2
0
        /// /////////////////////////////////////////////////////////
        /// Cluster Colliders
        /// /////////////////////////////////////////////////////////

        // Create mesh colliders for every input mesh TODO input cluster to control all nest roots for correct colliders
        public static bool SetClusterCollidersByShards(RayfireRigid scr)
        {
            // Check colliders list
            scr.physics.CollidersRemoveNull(scr);

            // Already clusterized
            if (scr.physics.HasClusterColliders == true)
            {
                return(true);
            }

            // Colliders list
            if (scr.physics.clusterColliders == null)
            {
                scr.physics.clusterColliders = new List <Collider>();
            }

            // Connected/Nested colliders
            if (scr.objectType == ObjectType.ConnectedCluster)
            {
                SetShardColliders(scr, scr.clusterDemolition.cluster);
            }
            else if (scr.objectType == ObjectType.NestedCluster)
            {
                SetDeepShardColliders(scr, scr.clusterDemolition.cluster);
            }

            return(true);
        }
Esempio n. 3
0
        //meshDemolition.skin.SetupSkin (this);
        //meshDemolition.skin.SeparateSkins(Vector3.up,Vector3.zero);

        public void SetupSkin(RayfireRigid rigid)
        {
            skins = rigid.GetComponentsInChildren <SkinnedMeshRenderer>().ToList();
            for (int i = 0; i < skins.Count; i++)
            {
            }
        }
Esempio n. 4
0
        /// /////////////////////////////////////////////////////////
        /// Methods
        /// /////////////////////////////////////////////////////////

        // Reinit non serialized fields in case of prefab use
        public static void InitCluster(RayfireRigid scr, RFCluster cluster)
        {
            if (cluster.initialized == false)
            {
                // Reinit connected cluster shards non serialized fields
                if (scr.objectType == ObjectType.ConnectedCluster)
                {
                    for (int s = 0; s < cluster.shards.Count; s++)
                    {
                        cluster.shards[s].cluster    = cluster;
                        cluster.shards[s].neibShards = new List <RFShard>();
                        for (int n = 0; n < cluster.shards[s].nIds.Count; n++)
                        {
                            cluster.shards[s].neibShards.Add(cluster.shards[cluster.shards[s].nIds[n]]);
                        }
                    }
                }

                // Unfold nested cluster non serialized child clusters
                if (scr.objectType == ObjectType.NestedCluster)
                {
                    UnfoldNestedCluster(scr, cluster);
                }

                cluster.initialized = true;
            }
        }
Esempio n. 5
0
        /// /////////////////////////////////////////////////////////
        /// Simulation Type
        /// /////////////////////////////////////////////////////////

        // Set simulation type properties
        public static void SetSimulationType(RayfireRigid scr)
        {
            // Dynamic
            if (scr.simulationType == SimType.Dynamic)
            {
                SetDynamic(scr);
            }

            // Sleeping
            else if (scr.simulationType == SimType.Sleeping)
            {
                SetSleeping(scr);
            }

            // Inactive
            else if (scr.simulationType == SimType.Inactive)
            {
                SetInactive(scr);
            }

            // Kinematic
            else if (scr.simulationType == SimType.Kinematic)
            {
                SetKinematic(scr);
            }
        }
Esempio n. 6
0
        // Check if fragment is the last child in root and delete root as well
        static void DestroyOp(RayfireRigid scr, Transform tm, float time = 0f)
        {
            // Set delay
            if (time == 0)
            {
                time = scr.reset.destroyDelay;
            }

            // Object is going to be destroyed. Timer is on
            scr.reset.toBeDestroyed = true;

            // Destroy object
            if (time <= 0f)
            {
                Destroy(scr.gameObject);
            }
            else
            {
                Destroy(scr.gameObject, time);
            }

            // Destroy root
            if (tm != null && tm.childCount == 0)
            {
                Destroy(tm.gameObject);
            }
        }
Esempio n. 7
0
        // Set uny state
        public void SetUnyByColliders(Collider[] colliders)
        {
            // Get rigids
            if (rigidList == null)
            {
                rigidList = new List <RayfireRigid>();
            }
            else
            {
                rigidList.Clear();
            }

            // Collect TODO get shard's cluster rigid
            for (int i = 0; i < colliders.Length; i++)
            {
                RayfireRigid rigid = colliders[i].GetComponent <RayfireRigid>();
                if (rigid != null)
                {
                    if (rigidList.Contains(rigid) == false)
                    {
                        rigidList.Add(rigid);
                    }
                }
            }

            // Set this uny state
            SetUnyRigids(rigidList);
        }
Esempio n. 8
0
        // Check for positive amount
        public static bool AmountCheck(RayfireRigid source, int pType)
        {
            // Check debris burst amount
            if (pType == 0)
            {
                for (int i = 0; i < source.debrisList.Count; i++)
                {
                    if (source.debrisList[i].emission.burstType == BurstType.None && source.debrisList[i].emission.distanceRate == 0)
                    {
                        Debug.Log(source.name + " has debris enabled but has no amount");
                        return(false);
                    }
                }
            }

            // Check dust burst amount
            if (pType == 1)
            {
                for (int i = 0; i < source.dustList.Count; i++)
                {
                    if (source.dustList[i].emission.burstType == BurstType.None && source.dustList[i].emission.distanceRate == 0)
                    {
                        Debug.Log(source.name + " has dust enabled but has no amount");
                        return(false);
                    }
                }
            }

            return(true);
        }
Esempio n. 9
0
        /// /////////////////////////////////////////////////////////
        /// Activation
        /// /////////////////////////////////////////////////////////

        // Init particles on activation
        public static void InitActivationParticles(RayfireRigid source)
        {
            // Create debris particles
            if (source.HasDebris == true)
            {
                for (int i = 0; i < source.debrisList.Count; i++)
                {
                    if (source.debrisList[i].onActivation == true)
                    {
                        CreateDebrisRigid(source.debrisList[i]);
                    }
                }
            }

            // Create dust particles
            if (source.HasDust == true)
            {
                for (int i = 0; i < source.dustList.Count; i++)
                {
                    if (source.dustList[i].onActivation == true)
                    {
                        CreateDustRigid(source.dustList[i]);
                    }
                }
            }
        }
Esempio n. 10
0
 // Local
 public void InvokeLocalEvent(RayfireRigid rigid)
 {
     if (LocalEvent != null)
     {
         LocalEvent.Invoke(rigid);
     }
 }
Esempio n. 11
0
 // Restriction event
 public static void InvokeGlobalEvent(RayfireRigid rigid)
 {
     if (GlobalEvent != null)
     {
         GlobalEvent.Invoke(rigid);
     }
 }
Esempio n. 12
0
        /// /////////////////////////////////////////////////////////
        /// Damage
        /// /////////////////////////////////////////////////////////

        // Apply damage. Return new rigid
        RayfireRigid ImpactDamage(RayfireRigid scrRigid, RaycastHit hit, Vector3 shootPos, Vector3 shootVector, Vector3 impactPoint)
        {
            // No damage or damage disabled
            if (damage == 0 || scrRigid.damage.enable == false)
            {
                return(scrRigid);
            }

            // Check for demolition TODO input collision collider if radius is 0
            bool damageDemolition = scrRigid.ApplyDamage(damage, impactPoint, radius);

            // object was not demolished
            if (damageDemolition == false)
            {
                return(scrRigid);
            }

            // Target was demolished
            if (scrRigid.HasFragments == true)
            {
                // Get new fragment target
                bool dmlHitState = Physics.Raycast(shootPos, shootVector, out hit, maxDistance, mask, QueryTriggerInteraction.Ignore);

                // Get new hit rigid
                if (dmlHitState == true)
                {
                    return(hit.collider.attachedRigidbody.transform.GetComponent <RayfireRigid>());
                }
            }

            return(null);
        }
Esempio n. 13
0
        // Shoot over axis
        public void Shoot(Vector3 shootPos, Vector3 shootVector)
        {
            // Event
            shotEvent.InvokeLocalEvent(this);
            RFShotEvent.InvokeGlobalEvent(this);

            // Get intersection collider
            RaycastHit hit;
            bool       hitState = Physics.Raycast(shootPos, shootVector, out hit, maxDistance, mask, QueryTriggerInteraction.Ignore);

            // No hits
            if (hitState == false)
            {
                return;
            }

            // Check for tag
            if (tagFilter != untagged && CompareTag(hit.transform.tag) == false)
            {
                return;
            }

            // Pos and normal info
            Vector3 impactPoint  = hit.point;
            Vector3 impactNormal = hit.normal;

            // If mesh collider
            // int triId = hit.triangleIndex;
            // Vector3 bar = hit.barycentricCoordinate;

            // Create impact flash
            ImpactFlash(impactPoint, impactNormal);

            // Get rigid from collider or rigid body
            RayfireRigid rigid = hit.collider.attachedRigidbody == null
                ? hit.collider.GetComponent <RayfireRigid>()
                : hit.collider.attachedRigidbody.transform.GetComponent <RayfireRigid>();

            // Collider has Rigid
            if (rigid != null)
            {
                // Impact Debris and dust
                ImpactDebris(rigid, impactPoint, impactNormal);

                // Impact Dust
                ImpactDust(rigid, impactPoint, impactNormal);

                // Apply damage and return new demolished rigid fragment
                rigid = ImpactDamage(rigid, hit, shootPos, shootVector, impactPoint);
            }

            // No Rigid script. TODO impact with object without rigid. get Rigid bodies around impact radius
            if (rigid == null)
            {
                return;
            }

            // Impact hit to rigid bodies. Activated inactive, detach clusters
            ImpactHit(rigid, hit, impactPoint, shootVector);
        }
Esempio n. 14
0
        // Start collapse coroutine
        IEnumerator CollapseCor(RayfireRigid scr)
        {
            // Wait time
            WaitForSeconds wait = new WaitForSeconds(duration / steps);

            // Iterate collapse
            inProgress = true;
            float step = (end - start) / (float)steps;

            for (int i = 0; i < steps; i++)
            {
                float percentage = start + step * i;
                if (type == RFCollapseType.ByArea)
                {
                    AreaCollapse(scr, (int)percentage);
                }
                else if (type == RFCollapseType.BySize)
                {
                    SizeCollapse(scr, (int)percentage);
                }
                else if (type == RFCollapseType.Random)
                {
                    RandomCollapse(scr, (int)percentage, scr.clusterDemolition.seed);
                }
                yield return(wait);
            }
            inProgress = false;
        }
Esempio n. 15
0
        // Restore rigid properties
        static void Reset(RayfireRigid scr)
        {
            // Reset caching if it is on
            scr.meshDemolition.StopRuntimeCaching();

            // Reset limitations
            scr.activation.Reset();

            if (scr.restriction != null)
            {
                scr.restriction.Reset();
            }

            scr.limitations.Reset();
            scr.meshDemolition.Reset();
            scr.clusterDemolition.Reset();
            scr.fading.Reset();

            // Reset damage
            if (scr.reset.damage == true)
            {
                scr.damage.Reset();
            }

            // Set physical simulation type. Important. Should after collider material define
            RFPhysic.SetSimulationType(scr);
        }
Esempio n. 16
0
        /// /////////////////////////////////////////////////////////
        /// Other
        /// /////////////////////////////////////////////////////////

        // Detach child particles in case object has child particles and about to be deleted
        static void DetachParticles(RayfireRigid source)
        {
            // Detach debris particle system if fragment was already demolished/activated before
            if (source.HasDebris == true)
            {
                for (int i = 0; i < source.debrisList.Count; i++)
                {
                    if (source.debrisList[i].hostTm != null)
                    {
                        source.debrisList[i].hostTm.parent     = null;
                        source.debrisList[i].hostTm.localScale = Vector3.one;
                    }
                }
            }

            // Detach dust particle system if fragment was already demolished/activated before
            if (source.HasDust == true)
            {
                for (int i = 0; i < source.dustList.Count; i++)
                {
                    if (source.dustList[i].hostTm != null)
                    {
                        source.dustList[i].hostTm.parent     = null;
                        source.dustList[i].hostTm.localScale = Vector3.one;
                    }
                }
            }
        }
Esempio n. 17
0
        /// /////////////////////////////////////////////////////////
        /// Methods
        /// /////////////////////////////////////////////////////////

        // Check if fragment is the last child in root and delete root as well
        public static void DestroyFragment(RayfireRigid scr, Transform tm, float time = 0f)
        {
            // Decrement total amount.
            if (Application.isPlaying == true)
            {
                inst.advancedDemolitionProperties.currentAmount--;
            }

            // Deactivate
            scr.gameObject.SetActive(false);

            // Destroy mesh
            if (scr.reset.action == RFReset.PostDemolitionType.DestroyWithDelay)
            {
                DestroyOp(scr, tm, time);
            }

            // Destroy not connected child clusters in any case
            else if (scr.reset.action == RFReset.PostDemolitionType.DeactivateToReset)
            {
                if (scr.objectType == ObjectType.ConnectedCluster && scr.clusterDemolition.cluster.id > 1)
                {
                    DestroyOp(scr, tm, time);
                }
            }
        }
Esempio n. 18
0
        // Copy debris and dust
        public static void CopyParticles(RayfireRigid source, RayfireRigid target)
        {
            // Copy debris
            if (source.HasDebris == true)
            {
                for (int i = 0; i < source.debrisList.Count; i++)
                {
                    RayfireDebris targetDebris = target.gameObject.AddComponent <RayfireDebris>();
                    targetDebris.CopyFrom(source.debrisList[i]);

                    if (source.debrisList[i].children == null)
                    {
                        source.debrisList[i].children = new List <RayfireDebris>();
                    }
                    source.debrisList[i].children.Add(targetDebris);
                }
            }

            // Copy dust
            if (source.HasDust == true)
            {
                for (int i = 0; i < source.dustList.Count; i++)
                {
                    RayfireDust targetDust = target.gameObject.AddComponent <RayfireDust>();
                    targetDust.CopyFrom(source.dustList[i]);

                    if (source.dustList[i].children == null)
                    {
                        source.dustList[i].children = new List <RayfireDust>();
                    }
                    source.dustList[i].children.Add(targetDust);
                }
            }
        }
Esempio n. 19
0
        // Init broke restriction
        static void BrokeRestriction(RayfireRigid scr)
        {
            // Set state
            scr.restriction.broke = true;

            // Event
            scr.restrictionEvent.InvokeLocalEvent(scr);
            RFRestrictionEvent.InvokeGlobalEvent(scr);

            // Destroy/Deactivate
            if (scr.restriction.breakAction == RFBoundActionType.PostDemolitionAction)
            {
                RayfireMan.DestroyFragment(scr, scr.rootParent);
            }

            // Fade
            else if (scr.restriction.breakAction == RFBoundActionType.Fade)
            {
                RFFade.Fade(scr);
            }

            // Reset
            else if (scr.restriction.breakAction == RFBoundActionType.Reset)
            {
                RFReset.ResetRigid(scr);
            }
        }
Esempio n. 20
0
        // Cluster preview ui
        void ClusterPreviewUI(RayfireRigid scr)
        {
            if (rigid.objectType == ObjectType.ConnectedCluster)
            {
                GUILayout.BeginHorizontal();

                // Show nodes
                EditorGUI.BeginChangeCheck();
                scr.clusterDemolition.cn = GUILayout.Toggle(scr.clusterDemolition.cn, "Show Connections", "Button", GUILayout.Height(22));
                scr.clusterDemolition.nd = GUILayout.Toggle(scr.clusterDemolition.nd, "    Show Nodes    ", "Button", GUILayout.Height(22));
                if (EditorGUI.EndChangeCheck())
                {
                    foreach (Object targ in targets)
                    {
                        if (targ as RayfireRigid != null)
                        {
                            (targ as RayfireRigid).clusterDemolition.cn = rigid.clusterDemolition.cn;
                            (targ as RayfireRigid).clusterDemolition.nd = rigid.clusterDemolition.nd;
                            SetDirty(targ as RayfireRigid);
                        }
                    }
                    SceneView.RepaintAll();
                }

                EditorGUILayout.EndHorizontal();
            }
        }
Esempio n. 21
0
        /// /////////////////////////////////////////////////////////
        /// Static
        /// /////////////////////////////////////////////////////////

        // Cache velocity for fragments
        public IEnumerator DemolishableCor(RayfireRigid scr)
        {
            while (scr.demolitionType != DemolitionType.None)
            {
                // Max depth reached
                if (scr.limitations.depth > 0 && scr.limitations.currentDepth >= scr.limitations.depth)
                {
                    scr.demolitionType = DemolitionType.None;
                }

                // Init demolition
                if (scr.limitations.demolitionShould == true)
                {
                    scr.Demolish();
                }

                // Check for slicing planes and init slicing
                else if (scr.limitations.sliceByBlade == true && scr.limitations.slicePlanes.Count > 1)
                {
                    scr.Slice();
                }

                yield return(null);
            }
        }
Esempio n. 22
0
        // Reset if object fading/faded
        static void ResetFade(RayfireRigid scr)
        {
            // Was excluded
            if (scr.fading.fadeType == FadeType.SimExclude)
            {
                scr.physics.meshCollider.enabled = true;// TODO CHECK CLUSTER COLLIDERS
            }

            // Was moved down
            else if (scr.fading.fadeType == FadeType.MoveDown)
            {
                scr.physics.meshCollider.enabled = true;// TODO CHECK CLUSTER COLLIDERS
                scr.gameObject.SetActive(true);
            }

            // Was scaled down
            else if (scr.fading.fadeType == FadeType.ScaleDown)
            {
                scr.transForm.localScale = scr.physics.initScale;
                scr.gameObject.SetActive(true);
            }

            // Was destroyed
            else if (scr.fading.fadeType == FadeType.Destroy)
            {
                scr.gameObject.SetActive(true);
            }
        }
Esempio n. 23
0
        /// /////////////////////////////////////////////////////////
        /// Constructor
        /// /////////////////////////////////////////////////////////

        // Constructor
        public RFCluster()
        {
            id           = -1;
            tm           = null;
            depth        = 0;
            initialized  = false;
            demolishable = true;
            shards       = new List <RFShard>();
            rigid        = null;

            // Collapse
            minimumArea    = 0;
            maximumArea    = 0;
            minimumSize    = 0;
            maximumSize    = 0;
            randomCollapse = 0;

            // Non serialized
            mainCluster   = null;
            childClusters = null;

            // neibClusters = new List<RFCluster>();
            // neibArea = new List<float>();
            // neibPerc = new List<float>();
        }
Esempio n. 24
0
        // Destroy particles
        static void DestroyParticles(RayfireRigid scr)
        {
            // Destroy debris
            if (scr.HasDebris == true)
            {
                for (int d = 0; d < scr.debrisList.Count; d++)
                {
                    if (scr.debrisList[d].hostTm != null)
                    {
                        scr.debrisList[d].hostTm.gameObject.SetActive(false);
                        RayfireMan.DestroyGo(scr.debrisList[d].hostTm.gameObject);
                    }
                }
            }

            // Destroy debris
            if (scr.HasDust == true)
            {
                for (int d = 0; d < scr.dustList.Count; d++)
                {
                    if (scr.dustList[d].hostTm != null)
                    {
                        scr.dustList[d].hostTm.gameObject.SetActive(false);
                        RayfireMan.DestroyGo(scr.dustList[d].hostTm.gameObject);
                    }
                }
            }
        }
Esempio n. 25
0
        // Set velocity
        public static void SetFragmentsVelocity(RayfireRigid scr)
        {
            // TODO different for clusters, get rigid bodys center of mass

            // Current velocity
            if (scr.meshDemolition.runtimeCaching.wasUsed == true && scr.meshDemolition.runtimeCaching.skipFirstDemolition == false)
            {
                for (int i = 0; i < scr.fragments.Count; i++)
                {
                    if (scr.fragments[i] != null)
                    {
                        scr.fragments[i].physics.rigidBody.velocity = scr.physics.rigidBody.GetPointVelocity(scr.fragments[i].transForm.position) * scr.physics.dampening;
                    }
                }
            }

            // Previous frame velocity
            else
            {
                Vector3 baseVelocity = scr.physics.velocity * scr.physics.dampening;
                for (int i = 0; i < scr.fragments.Count; i++)
                {
                    if (scr.fragments[i].physics.rigidBody != null)
                    {
                        scr.fragments[i].physics.rigidBody.velocity = baseVelocity;
                    }
                }
            }
        }
Esempio n. 26
0
 // Reinit demolished mesh object
 static void ResetClusterDemolition(RayfireRigid scr)
 {
     if (scr.objectType == ObjectType.ConnectedCluster || scr.objectType == ObjectType.NestedCluster)
     {
         RFBackupCluster.RestoreBackup(scr);
     }
 }
Esempio n. 27
0
        /// /////////////////////////////////////////////////////////
        /// Collider properties
        /// /////////////////////////////////////////////////////////

        // Set collider material
        public static void SetColliderMaterial(RayfireRigid scr)
        {
            // Set physics material if not defined by user
            if (scr.physics.material == null)
            {
                scr.physics.material = scr.physics.PhysMaterial;
            }

            // Set mesh collider material
            if (scr.physics.meshCollider != null)
            {
                scr.physics.meshCollider.sharedMaterial = scr.physics.material;

                // Set debris material properties
                if (scr.HasDebris == true)
                {
                    for (int i = 0; i < scr.debrisList.Count; i++)
                    {
                        scr.debrisList[i].collision.SetMaterialProps(scr.debrisList[i]);
                    }
                }

                return;
            }

            // Set cluster colliders material
            if (scr.physics.HasClusterColliders == true)
            {
                for (int i = 0; i < scr.physics.clusterColliders.Count; i++)
                {
                    scr.physics.clusterColliders[i].sharedMaterial = scr.physics.material;
                }
            }
        }
Esempio n. 28
0
        // Check fragments reuse state
        static bool FragmentReuseState(RayfireRigid scr)
        {
            // Do not reuse reference demolition
            if (scr.demolitionType == DemolitionType.ReferenceDemolition)
            {
                return(false);
            }

            // Fragments list null or empty
            if (scr.HasFragments == false)
            {
                return(false);
            }

            // One of the fragment null
            if (scr.fragments.Any(t => t == null))
            {
                return(false);
            }

            // One of the fragment going to be destroyed TODO make reusable
            if (scr.fragments.Any(t => t.reset.toBeDestroyed == true))
            {
                return(false);
            }

            // One of the fragment demolished TODO make reusable
            if (scr.fragments.Any(t => t.limitations.demolished == true))
            {
                return(false);
            }

            // Fragments can be reused
            return(true);
        }
Esempio n. 29
0
        // Create pool object
        public static RayfireRigid CreateRigidInstance()
        {
            // Create
            GameObject instance = new GameObject("Instance");

            // Turn off
            instance.SetActive(false);

            // Setup
            MeshFilter   mf            = instance.AddComponent <MeshFilter>();
            MeshRenderer mr            = instance.AddComponent <MeshRenderer>();
            RayfireRigid rigidInstance = instance.AddComponent <RayfireRigid>();

            rigidInstance.initialization = RayfireRigid.InitType.AtStart;
            Rigidbody rb = instance.AddComponent <Rigidbody>();

            rb.collisionDetectionMode = RayfireMan.inst.collisionDetection;

            // Define components
            rigidInstance.transForm         = instance.transform;
            rigidInstance.meshFilter        = mf;
            rigidInstance.meshRenderer      = mr;
            rigidInstance.physics.rigidBody = rb;

            return(rigidInstance);
        }
Esempio n. 30
0
        // Break neib connection randomly
        public static void RandomCollapse(RayfireRigid scr, int randomValue, int randomSeed)
        {
            // Not initialized
            if (scr.initialized == false)
            {
                return;
            }

            // Value lower than last
            if (randomValue < scr.clusterDemolition.cluster.randomCollapse)
            {
                return;
            }

            // Set value
            scr.clusterDemolition.cluster.randomCollapse = randomValue;
            scr.clusterDemolition.cluster.randomSeed     = randomSeed;

            // Main cluster.
            int removed = RemNeibRandom(scr.clusterDemolition.cluster, randomValue, randomSeed);

            ;
            if (removed > 0)
            {
                CollapseCluster(scr);
            }
        }