// 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); }
/// ///////////////////////////////////////////////////////// /// 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); }
//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++) { } }
/// ///////////////////////////////////////////////////////// /// 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; } }
/// ///////////////////////////////////////////////////////// /// 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); } }
// 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); } }
// 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); }
// 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); }
/// ///////////////////////////////////////////////////////// /// 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]); } } } }
// Local public void InvokeLocalEvent(RayfireRigid rigid) { if (LocalEvent != null) { LocalEvent.Invoke(rigid); } }
// Restriction event public static void InvokeGlobalEvent(RayfireRigid rigid) { if (GlobalEvent != null) { GlobalEvent.Invoke(rigid); } }
/// ///////////////////////////////////////////////////////// /// 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); }
// 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); }
// 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; }
// 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); }
/// ///////////////////////////////////////////////////////// /// 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; } } } }
/// ///////////////////////////////////////////////////////// /// 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); } } }
// 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); } } }
// 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); } }
// 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(); } }
/// ///////////////////////////////////////////////////////// /// 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); } }
// 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); } }
/// ///////////////////////////////////////////////////////// /// 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>(); }
// 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); } } } }
// 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; } } } }
// Reinit demolished mesh object static void ResetClusterDemolition(RayfireRigid scr) { if (scr.objectType == ObjectType.ConnectedCluster || scr.objectType == ObjectType.NestedCluster) { RFBackupCluster.RestoreBackup(scr); } }
/// ///////////////////////////////////////////////////////// /// 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; } } }
// 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); }
// 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); }
// 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); } }