using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Random = UnityEngine.Random; namespace RayFire { [SelectionBase] [DisallowMultipleComponent] [AddComponentMenu ("RayFire/Rayfire Rigid")] [HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-rigid-component/")] public class RayfireRigid : MonoBehaviour { public enum InitType { ByMethod = 0, AtStart = 1 } // UI public InitType initialization = InitType.ByMethod; public SimType simulationType = SimType.Dynamic; public ObjectType objectType = ObjectType.Mesh; public DemolitionType demolitionType = DemolitionType.None; public RFPhysic physics = new RFPhysic(); public RFActivation activation = new RFActivation(); public RFLimitations limitations = new RFLimitations(); public RFDemolitionMesh meshDemolition = new RFDemolitionMesh(); public RFDemolitionCluster clusterDemolition = new RFDemolitionCluster(); public RFReferenceDemolition referenceDemolition = new RFReferenceDemolition(); public RFSurface materials = new RFSurface(); public RFDamage damage = new RFDamage(); public RFFade fading = new RFFade(); public RFReset reset = new RFReset(); // Hidden public bool initialized; public RFMesh[] rfMeshes; public List fragments; public Quaternion cacheRotation; // NOTE. Should be public, otherwise rotation error on demolition. public Transform transForm; public Transform rootChild; public Transform rootParent; public MeshFilter meshFilter; public MeshRenderer meshRenderer; public SkinnedMeshRenderer skr; [FormerlySerializedAs ("restriction")] public RayfireRestriction rest; public RayfireSound sound; // Non Serialized [NonSerialized] public bool corState; [NonSerialized] public List particleList; [NonSerialized] public List debrisList; [NonSerialized] public List dustList; [NonSerialized] public RFDictionary[] subIds; [NonSerialized] public Vector3[] pivots; [NonSerialized] public Mesh[] meshes; [NonSerialized] public RayfireRigid meshRoot; [NonSerialized] public RayfireRigidRoot rigidRoot; [NonSerialized] public int debrisState = 1; [NonSerialized] public int dustState = 1; // Events public RFDemolitionEvent demolitionEvent = new RFDemolitionEvent(); public RFActivationEvent activationEvent = new RFActivationEvent(); public RFRestrictionEvent restrictionEvent = new RFRestrictionEvent(); /// ///////////////////////////////////////////////////////// /// Common /// ///////////////////////////////////////////////////////// // Awake void Awake() { // Awake Mesh input MeshInput(); // Initialize at start if (initialization == InitType.AtStart) Initialize(); } // Initialize public void Initialize() { // Deactivated if (gameObject.activeSelf == false) return; // Not initialized if (initialized == false) { // Init Awake methods AwakeMethods(); // Init sound RFSound.InitializationSound(sound, limitations.bboxSize); } // TODO add reinit for already initialized objects in case of property change } // Awake ops void AwakeMethods() { // Create RayFire manager if not created RayfireMan.RayFireManInit(); // Set components for mesh / skinned mesh / clusters SetComponentsBasic(); // Set particles RFParticles.SetParticleComponents(this); // Init mesh root. if (SetupMeshRoot() == true) return; // Check for user mistakes RFLimitations.Checks(this); // Set components for mesh / skinned mesh / clusters SetComponentsPhysics(); // Initialization Mesh input if (meshDemolition.inp == RFDemolitionMesh.MeshInputType.AtInitialization) MeshInput(); // Precache meshes at awake RFDemolitionMesh.Awake(this); // Skinned mesh SetSkinnedMesh(); // Excluded from simulation if (physics.exclude == true) return; // Set Start variables SetObjectType(); // Runtime ops if (Application.isPlaying == true) { // Start all coroutines StartAllCoroutines(); // Object initialized initialized = true; } } // Set skinned mesh void SetSkinnedMesh() { // Skinned mesh FIXME if (objectType == ObjectType.SkinnedMesh) { // Reset rigid data Default(); // Check for demolition state every frame if (demolitionType != DemolitionType.None) StartCoroutine (limitations.DemolishableCor(this)); // Reset rigid data Default(); // Set physics properties physics.destructible = physics.Destructible; if (Application.isPlaying == true) initialized = true; } } /// ///////////////////////////////////////////////////////// /// Enable/Disable /// ///////////////////////////////////////////////////////// // Disable void OnDisable() { // Set coroutines states corState = false; limitations.dmlCorState = false; physics.physicsDataCorState = false; activation.inactiveCorState = false; activation.velocityCorState = false; activation.offsetCorState = false; fading.offsetCorState = false; } // Activation void OnEnable() { // Start cors // TODO add support for fragment caching and the rest cors:skinned if (gameObject.activeSelf == true && initialized == true && corState == false) { StartAllCoroutines(); } } /// ///////////////////////////////////////////////////////// /// Setup /// ///////////////////////////////////////////////////////// // Editor Setup public void EditorSetup() { // Deactivated if (gameObject.activeSelf == false) return; // Setup mesh root if (objectType == ObjectType.MeshRoot) EditorSetupMeshRoot(); // Setup clusters if (objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster) RFDemolitionCluster.ClusterizeEditor (this); } // Editor Reset public void ResetSetup() { // Deactivated if (gameObject.activeSelf == false) return; // Reset setup for mesh root if (objectType == ObjectType.MeshRoot) ResetMeshRootSetup(); // Reset Setup for clusters if (objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster) RFDemolitionCluster.ResetClusterize (this); } /// ///////////////////////////////////////////////////////// /// Awake ops /// ///////////////////////////////////////////////////////// // Define basic components public void SetComponentsBasic() { // Set shatter component meshDemolition.sht = meshDemolition.use == true ? GetComponent() : null; // Tm transForm = GetComponent(); // Mesh/Renderer components if (objectType == ObjectType.Mesh) { meshFilter = GetComponent(); meshRenderer = GetComponent(); } else if (objectType == ObjectType.SkinnedMesh) skr = GetComponent(); rest = GetComponent(); // Add missing mesh renderer if (meshFilter != null && meshRenderer == null) meshRenderer = gameObject.AddComponent(); // Init reset lists if (reset.action == RFReset.PostDemolitionType.DeactivateToReset) limitations.desc = new List(); } // Define components public void SetComponentsPhysics() { // Excluded from simulation if (physics.exclude == true) return; // Physics components physics.rigidBody = GetComponent(); physics.meshCollider = GetComponent(); // Mesh Set collider if (objectType == ObjectType.Mesh) RFPhysic.SetRigidCollider (this); // Cluster check if (objectType == ObjectType.NestedCluster || objectType == ObjectType.ConnectedCluster) RFDemolitionCluster.Clusterize (this); // Rigid body if (Application.isPlaying == true) if (simulationType != SimType.Static) if (physics.rigidBody == null) physics.rigidBody = gameObject.AddComponent(); } /// ///////////////////////////////////////////////////////// /// MeshRoot /// ///////////////////////////////////////////////////////// // Setup mesh root editor ops void EditorSetupMeshRoot() { // Check if manager should be destroyed after setup bool destroyMan = RayfireMan.inst == null; // Create RayFire manager if not created RayfireMan.RayFireManInit(); // Reset ResetMeshRootSetup(); // Setup SetupMeshRoot(); // Destroy manager if (destroyMan == true) DestroyImmediate (RayfireMan.inst.transform.gameObject); } // Init mesh root. Copy Rigid component for children with mesh bool SetupMeshRoot() { if (objectType == ObjectType.MeshRoot) { // Get transform for Editor setup //if (transForm == null) // transForm = GetComponent(); // Stop if already initiated if (limitations.demolished == true || physics.exclude == true) return true; // Save tm physics.SaveInitTransform (transform); // MeshRoot Integrity check if (Application.isPlaying == true) RFLimitations.MeshRootCheck(this); // Add Rigid to mesh Root children if (HasFragments == false) AddMeshRootRigid(transform); // Init in runtime. DO not if editor setup if (Application.isPlaying == true) for (int i = 0; i < fragments.Count; i++) { fragments[i].Initialize(); fragments[i].meshRoot = this; } // Editor only ops if (Application.isPlaying == false) { for (int i = 0; i < fragments.Count; i++) { // Set basic fragments components for collider apply fragments[i].SetComponentsBasic(); // Set bound and size for connection size by bounding box RFLimitations.SetBound (fragments[i]); } // Add colliders to speedup. Editor only. Frags get collider at runtime in Initialize() RFPhysic.SetupMeshRootColliders (this); } // Ignore neib collisions RFPhysic.SetIgnoreColliders (physics, fragments); // Runtime only ops if (Application.isPlaying == true) { // Copy components. RayfireShatter.CopyRootMeshShatter (this, fragments); RFParticles.CopyRootMeshParticles (this, fragments); RFSound.CopySound (sound, fragments); } // Set unyielding RayfireUnyielding.MeshRootSetup (this); // Initialize connectivity InitConnectivity(); // Turn off demolition and physics if (Application.isPlaying == true) { demolitionType = DemolitionType.None; physics.exclude = true; initialized = true; } return true; } return false; } // Add Rigid to mesh Root children void AddMeshRootRigid(Transform tm) { // Get children List children = new List(tm.childCount); for (int i = 0; i < tm.childCount; i++) children.Add (tm.GetChild (i)); // Add Rigid to child with mesh fragments = new List(); for (int i = 0; i < children.Count; i++) { MeshFilter mf = children[i].GetComponent(); if (mf != null) { // Get rigid RayfireRigid childRigid = children[i].gameObject.GetComponent(); // Mark Rigid as custom Rigid component to keep it at Mesh Root Reset if (childRigid != null) childRigid.rootParent = tm; // Add new and copy props from parent if (childRigid == null) { childRigid = children[i].gameObject.AddComponent(); CopyPropertiesTo (childRigid); } // Set meshfilter childRigid.meshFilter = mf; // Collect fragments.Add (childRigid); // Set parent meshRoot. IMPORTANT needed in case of custom Rigid childRigid.meshRoot = this; } } } // Init connectivity if has void InitConnectivity() { activation.cnt = GetComponent(); if (activation.cnt != null && activation.cnt.rigidRootHost == null) { activation.cnt.meshRootHost = this; activation.cnt.Initialize();; } // Warnings if (activation.con == true && activation.cnt == null) Debug.Log ("RayFireRigid: " + name + " object has enabled Connectivity activation but has no Connectivity component.", gameObject); } // Reset MeshRoot Setup void ResetMeshRootSetup() { // Reset Connectivity if (activation.cnt != null) activation.cnt.ResetSetup(); activation.cnt = null; // ReSet unyielding RayfireUnyielding.ResetMeshRootSetup (this); // Destroy new Rigid and clear custom Rigid components if (HasFragments == true) { if (physics.clusterColliders != null) { // Clean fragments for (int i = fragments.Count - 1; i >= 0; i--) if (fragments[i] == null) fragments.RemoveAt (i); // Destroy colliders added by setup HashSet collidersHash = new HashSet (physics.clusterColliders); for (int i = 0; i < fragments.Count; i++) if (fragments[i].physics.meshCollider != null) if (collidersHash.Contains (fragments[i].physics.meshCollider) == false) DestroyImmediate (fragments[i].physics.meshCollider); physics.clusterColliders = null; // Destroy Rigids added by setup for (int i = 0; i < fragments.Count; i++) if (fragments[i].rootParent == null) DestroyImmediate (fragments[i]); else { fragments[i].rootParent = null; fragments[i].meshFilter = null; fragments[i].meshRenderer = null; fragments[i].physics.meshCollider = null; fragments[i].meshRoot = null; } } } // Reset common transForm = null; physics.ignoreList = null; fragments = null; } /// ///////////////////////////////////////////////////////// /// Start ops /// ///////////////////////////////////////////////////////// // Set Start variables public void SetObjectType () { if (objectType == ObjectType.Mesh || objectType == ObjectType.NestedCluster || objectType == ObjectType.ConnectedCluster) // Reset rigid data Default(); // Set physics properties SetPhysics(); } // Reset rigid data public void Default() { // Reset limitations.LocalReset(); meshDemolition.LocalReset(); clusterDemolition.LocalReset(); limitations.birthTime = Time.time + Random.Range (0f, 0.05f); // Birth position for activation check physics.SaveInitTransform (transForm); // Set bound and size RFLimitations.SetBound(this); // Backup original layer RFActivation.BackupActivationLayer (this); // meshDemolition.properties.layerBack = gameObject.layer; // gameObject.tag; } // Set physics properties void SetPhysics() { // Excluded from sim if (physics.exclude == true) return; // MeshCollider physic material preset. Set new or take from parent RFPhysic.SetColliderMaterial (this); // Set debris collider material if (HasDebris == true) RFPhysic.SetParticleColliderMaterial (debrisList); // Ops with rigidbody applied if (physics.rigidBody != null) { // Set physical simulation type. Important. Should after collider material define if (Application.isPlaying == true) RFPhysic.SetSimulationType (physics.rigidBody, simulationType, objectType, physics.gr, physics.si, physics.st); // Do not set convex, mass, drag for static if (simulationType == SimType.Static) return; // Convex collider meshCollider. After SetSimulation Type to turn off convex for kinematic RFPhysic.SetColliderConvex (this); // Set density. After collider defined RFPhysic.SetDensity (this); // Set drag properties RFPhysic.SetDrag (this); } // Set material solidity and destructible physics.solidity = physics.Solidity; physics.destructible = physics.Destructible; } /// ///////////////////////////////////////////////////////// /// Coroutines /// ///////////////////////////////////////////////////////// // Start all coroutines public void StartAllCoroutines() { // Stop if static if (simulationType == SimType.Static) return; // Inactive if (gameObject.activeSelf == false) return; // Prevent physics cors if (physics.exclude == true) return; // Check for demolition state every frame if (demolitionType != DemolitionType.None) StartCoroutine (limitations.DemolishableCor(this)); // Offset fade if (fading.byOffset > 0) { fading.offsetEnum = RFFade.FadeOffsetCor (this); StartCoroutine (fading.offsetEnum); } // Start inactive coroutines InactiveCors(); // Cache physics data for fragments physics.physicsEnum = physics.PhysicsDataCor (this); StartCoroutine (physics.physicsEnum); // All coroutines are running corState = true; } // Start inactive coroutines public void InactiveCors() { // Activation by velocity\offset coroutines if (simulationType == SimType.Inactive || simulationType == SimType.Kinematic) { if (activation.vel > 0) { activation.velocityEnum = activation.ActivationVelocityCor (this); StartCoroutine (activation.velocityEnum); } if (activation.off > 0) { activation.offsetEnum = activation.ActivationOffsetCor (this); StartCoroutine (activation.offsetEnum); } } // Init inactive every frame update coroutine if (simulationType == SimType.Inactive) //RayfireMan.inst.AddInactive (this); StartCoroutine (activation.InactiveCor(this)); } /// ///////////////////////////////////////////////////////// /// Demolition types /// ///////////////////////////////////////////////////////// // Awake Mesh input // TODO add checks in case has input mesh but mesh input is off public void MeshInput() { if (objectType == ObjectType.Mesh && demolitionType == DemolitionType.Runtime && meshDemolition.inp == RFDemolitionMesh.MeshInputType.AtStart) { // Set components for mesh / skinned mesh / clusters SetComponentsBasic(); // Input RFFragment.InputMesh (this); } } /// ///////////////////////////////////////////////////////// /// Collision /// ///////////////////////////////////////////////////////// // Collision check protected virtual void OnCollisionEnter (Collision collision) { // No demolition allowed if (demolitionType == DemolitionType.None) return; // Check if collision data needed if (limitations.CollisionCheck(this) == false) return; // Demolish object check if (DemolitionState() == false) return; // Tag check. IMPORTANT keep length check for compatibility with older builds if (limitations.tag.Length > 0 && limitations.tag != "Untagged" && collision.collider.CompareTag (limitations.tag) == false) return; // Check if collision demolition passed if (CollisionDemolition (collision) == true) limitations.demolitionShould = true; } // Check if collision demolition passed protected virtual bool CollisionDemolition (Collision collision) { // Final object solidity float finalSolidity = physics.solidity * limitations.sol * RayfireMan.inst.globalSolidity; // Demolition by collision if (limitations.col == true) { // Collision with kinematic object. Uses collision.impulse if (limitations.KinematicCollisionCheck(collision, finalSolidity) == true) return true; // Collision force checks. Uses relativeVelocity if (limitations.ContactPointsCheck(collision, finalSolidity) == true) return true; } // Demolition by accumulated damage collision if (damage.en == true && damage.col == true) if (limitations.DamagePointsCheck(collision, this) == true) return true; return false; } /// ///////////////////////////////////////////////////////// /// Demolition /// ///////////////////////////////////////////////////////// // Demolition available state public bool State () { // Object already demolished if (limitations.demolished == true) return false; // Object already passed demolition state and demolishing is in progress if (meshDemolition.ch.inProgress == true) return false; // Bad mesh check if (meshDemolition.badMesh > RayfireMan.inst.advancedDemolitionProperties.badMeshTry) return false; // Max amount check if (RayfireMan.MaxAmountCheck == false) return false; // Depth level check if (limitations.depth > 0 && limitations.currentDepth >= limitations.depth) return false; // Min Size check. Min Size should be considered and size is less than if (limitations.bboxSize < limitations.size) return false; // Safe frame if (Time.time - limitations.birthTime < limitations.time) return false; // Static type objects can not be demolished if (simulationType == SimType.Static) return false; // Static objects can not be demolished if (gameObject.isStatic == true) return false; // Fading if (fading.state == 2) return false; return true; } // Check if object should be demolished public virtual bool DemolitionState () { // No demolition allowed if (demolitionType == DemolitionType.None) return false; // Non destructible material if (physics.destructible == false) return false; // Visibility check if (Visible == false) return false; // Demolition available check if (State() == false) return false; // Per frame time check if (RayfireMan.inst.timeQuota > 0 && RayfireMan.inst.maxTimeThisFrame > RayfireMan.inst.timeQuota) return false; return true; } // Demolish object public void Demolish() { // Initialize if not if (initialized == false) Initialize(); // Timestamp float t1 = Time.realtimeSinceStartup; // Demolish mesh or cluster to reference if (RFReferenceDemolition.DemolishReference(this) == false) return; // Demolish mesh and create fragments. Stop if runtime caching or no meshes/fragments were created if (RFDemolitionMesh.DemolishMesh (this) == true) { // Check for inactive/kinematic fragments with unyielding RayfireUnyielding.SetUnyieldingFragments (this); // Set children with mesh as additional fragments RFDemolitionMesh.ChildrenToFragments(this); // Clusterize runtime fragments RFDemolitionMesh.ClusterizeFragments (this); } else return; // Demolish cluster to children nodes if (RFDemolitionCluster.DemolishCluster (this) == true) return; // Check fragments and proceed TODO separate flow for connected cls demolition if (limitations.demolished == false) { limitations.demolitionShould = false; demolitionType = DemolitionType.None; return; } // Connectivity check activation.CheckConnectivity(); // Fragments initialisation InitMeshFragments(); // Sum total demolition time RayfireMan.inst.maxTimeThisFrame += Time.realtimeSinceStartup - t1; // Init particles RFParticles.InitDemolitionParticles(this); // Init sound RFSound.DemolitionSound(sound, limitations.bboxSize); // Event RFDemolitionEvent.RigidDemolitionEvent (this); // Destroy demolished object RayfireMan.DestroyFragment (this, rootParent); } /// ///////////////////////////////////////////////////////// /// Fragments /// ///////////////////////////////////////////////////////// // Copy rigid properties from parent to fragments public void CopyPropertiesTo (RayfireRigid toScr) { // Set local meshRoot if (objectType == ObjectType.MeshRoot) toScr.meshRoot = this; else if (meshRoot != null) toScr.meshRoot = meshRoot; // Object type toScr.objectType = objectType; if (objectType == ObjectType.MeshRoot || objectType == ObjectType.SkinnedMesh) toScr.objectType = ObjectType.Mesh; // Sim type toScr.simulationType = simulationType; if (objectType != ObjectType.MeshRoot) if (simulationType == SimType.Kinematic || simulationType == SimType.Static || simulationType == SimType.Sleeping) toScr.simulationType = SimType.Dynamic; // Demolition type toScr.demolitionType = demolitionType; if (objectType != ObjectType.MeshRoot) if (demolitionType != DemolitionType.None) toScr.demolitionType = DemolitionType.Runtime; // Copy physics toScr.physics.CopyFrom (physics); toScr.activation.CopyFrom (activation); toScr.limitations.CopyFrom (limitations); toScr.meshDemolition.CopyFrom (meshDemolition); toScr.clusterDemolition.CopyFrom (clusterDemolition); // Copy reference demolition props if (objectType == ObjectType.MeshRoot) toScr.referenceDemolition.CopyFrom (referenceDemolition); toScr.materials.CopyFrom (materials); toScr.damage.CopyFrom (damage); toScr.fading.CopyFrom (fading); toScr.reset.CopyFrom (reset, objectType); } // Fragments initialisation public void InitMeshFragments() { // No fragments if (HasFragments == false) return; // Set velocity RFPhysic.SetFragmentsVelocity (this); // Sum total new fragments amount RayfireMan.inst.advancedDemolitionProperties.ChangeCurrentAmount (fragments.Count); // Set ancestor and descendants RFLimitations.SetAncestor (this); RFLimitations.SetDescendants (this); // Fading. move to fragment if (fading.onDemolition == true) fading.DemolitionFade (fragments); } /// ///////////////////////////////////////////////////////// /// Manual methods /// ///////////////////////////////////////////////////////// // Clear cache info public void DeleteCache() { meshes = null; pivots = null; rfMeshes = null; subIds = null; } // Delete fragments public void DeleteFragments() { // Destroy root if (rootChild != null) { if (Application.isPlaying == true) Destroy (rootChild.gameObject); else DestroyImmediate (rootChild.gameObject); // Clear ref rootChild = null; } // Clear array fragments = null; } /// ///////////////////////////////////////////////////////// /// Blade /// ///////////////////////////////////////////////////////// // Add new slice plane public void AddSlicePlane (Vector3[] slicePlane) { // Not even amount of slice data if (slicePlane.Length % 2 == 1) return; // Add slice plane data if (limitations.slicePlanes == null) limitations.slicePlanes = new List(); limitations.slicePlanes.AddRange (slicePlane); } // Slice object public void Slice() { // Check for slices if (HasSlices == false) { Debug.Log ("RayFire Rigid: " + name + " has no defined slicing planes.", gameObject); return; } // Slice if (IsMesh == true) { // Slice. Stop if failed if (RFDemolitionMesh.SliceMesh (this) == false) return; // Set children with mesh as additional fragments RFDemolitionMesh.ChildrenToFragments(this); } else if (objectType == ObjectType.ConnectedCluster) RFDemolitionCluster.SliceConnectedCluster (this); // Particles RFParticles.InitDemolitionParticles(this); // Sound RFSound.DemolitionSound(sound, limitations.bboxSize); // Event RFDemolitionEvent.RigidDemolitionEvent (this); // Destroy original if (IsMesh == true) RayfireMan.DestroyFragment (this, rootParent); } /// ///////////////////////////////////////////////////////// /// Caching /// ///////////////////////////////////////////////////////// // Caching into meshes over several frames public void CacheFrames() { StartCoroutine (meshDemolition.ch.RuntimeCachingCor(this)); } /// ///////////////////////////////////////////////////////// /// Public methods /// ///////////////////////////////////////////////////////// // Save init transform. Birth tm for activation check and reset [ContextMenu("SaveInitTransform")] public void SaveInitTransform () { // Rigid save tm if (objectType == ObjectType.Mesh) physics.SaveInitTransform (transForm); // Mesh Root save tm else if (objectType == ObjectType.MeshRoot) { if (HasFragments == true) { // Save for Rigids for (int i = 0; i < fragments.Count; i++) if (fragments[i] != null) fragments[i].physics.SaveInitTransform (fragments[i].transForm); // Save is connectivity backup cluster if (activation.cnt != null && reset.connectivity == true ) if (activation.cnt.backup != null) RFBackupCluster.SaveTmRecursive (activation.cnt.backup.cluster); } } } // Apply damage public bool ApplyDamage (float damageValue, Vector3 damagePoint, float damageRadius = 0f, Collider coll = null) { return RFDamage.ApplyDamage (this, damageValue, damagePoint, damageRadius, coll); } // Activate inactive object public void Activate(bool connCheck = true) { if (objectType != ObjectType.MeshRoot) RFActivation.ActivateRigid (this, connCheck); else for (int i = 0; i < fragments.Count; i++) RFActivation.ActivateRigid (fragments[i], connCheck); } // Fade this object public void Fade() { if (objectType != ObjectType.MeshRoot) RFFade.FadeRigid (this); else for (int i = 0; i < fragments.Count; i++) RFFade.FadeRigid (fragments[i]); } // Reset object public void ResetRigid() { RFReset.ResetRigid (this); } /// ///////////////////////////////////////////////////////// /// Other /// ///////////////////////////////////////////////////////// // Destroy public void DestroyObject(GameObject go) { Destroy (go); } public void DestroyRigid(RayfireRigid rigid) { Destroy (rigid); } /// ///////////////////////////////////////////////////////// /// Getters /// ///////////////////////////////////////////////////////// // Fragments/Meshes check public bool HasFragments { get { return fragments != null && fragments.Count > 0; } } public bool HasMeshes { get { return meshes != null && meshes.Length > 0; } } public bool HasRfMeshes { get { return rfMeshes != null && rfMeshes.Length > 0; } } public bool HasDebris { get { return debrisList != null && debrisList.Count > 0; } } public bool HasDust { get { return dustList != null && dustList.Count > 0; } } bool HasSlices { get { return limitations.slicePlanes != null && limitations.slicePlanes.Count > 0; } } public bool IsCluster { get { return objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster; } } bool IsMesh { get { return objectType == ObjectType.Mesh || objectType == ObjectType.SkinnedMesh; } } // Check if object visible // TODO add cluster visibility support public bool Visible { get { if (objectType == ObjectType.Mesh && meshRenderer != null) return meshRenderer.isVisible; if (objectType == ObjectType.SkinnedMesh && skr != null) return skr.isVisible; return true; }} // CLuster Integrity public float AmountIntegrity { get { if (objectType == ObjectType.ConnectedCluster) return (float)clusterDemolition.cluster.shards.Count / (float)clusterDemolition.am * 100f; return 0f; } } } }