public void OnDetach(object o) { FracturedChunk chunk = o as FracturedChunk; var destructibleObject = MapObjectUtility.GetMapObjectOfFracturedChunk(chunk); if (destructibleObject == null) { var evt = ChunkSyncEvent.Allocate(); evt.EType = TriggerObjectSyncEventType.DetachChunk; evt.ChunkId = chunk.ChunkId; MapObjectUtility.StoreTriggerObjectEvent(chunk.FracturedObjectSource.gameObject, evt); } if (destructibleObject != null) { var data = destructibleObject.destructibleData; var chunkId = chunk.ChunkId; if (data.IsInDestructionState(chunkId)) { return; } data.SetDestruction(chunk.ChunkId); //synchronization delay for vehicle-collidable destructible object if (chunk.FracturedObjectSource.EnableVehicleCollision) { data.SyncDelay = SYNC_DELAY_TIME; } //notify server to destory destructible object SendDetachChunkEventToServer(destructibleObject, chunk.ChunkId); } }
public CollisionInfo(FracturedChunk chunk, Collision collisionInfo, bool bIsMain) { this.chunk = chunk; this.collisionInfo = collisionInfo; this.bIsMain = bIsMain; bCancelCollisionEvent = false; }
public CollisionInfo(FracturedChunk chunk, Vector3 collisionPoint, bool bIsMain) { this.chunk = chunk; this.collisionPoint = collisionPoint; this.bIsMain = bIsMain; bCancelCollisionEvent = false; }
public void DisconnectFrom(FracturedChunk chunk) { if (chunk) { if (chunk.IsConnectedTo(this)) { for (int i = 0; i < ListAdjacentChunks.Count; i++) { if (ListAdjacentChunks[i].chunk == chunk) { ListAdjacentChunks.RemoveAt(i); break; } } for (int i = 0; i < chunk.ListAdjacentChunks.Count; i++) { if (chunk.ListAdjacentChunks[i].chunk == this) { chunk.ListAdjacentChunks.RemoveAt(i); break; } } } } }
public void NotifyChunkDetach(FracturedChunk chunk) { if (m_bDetached == false) { // Disable all triggerse in them so that free chunks will collide also with static non-free chunks foreach (FracturedChunk chunkInstance in ListFracturedChunks) { if (chunkInstance != null) { Collider colliderComponent = chunkInstance.GetComponent <Collider>(); if (colliderComponent != null) { colliderComponent.isTrigger = false; } } } } m_bDetached = true; SetSingleMeshVisibility(false); if (EventDetachedAnyCallMethod.Length > 0 && EventDetachedAnyCallGameObject != null) { EventDetachedAnyCallGameObject.SendMessage(EventDetachedAnyCallMethod); } }
private static void ComputeRandomConnectionBreaksRecursive(FracturedChunk chunk, List <FracturedChunk> listBreaksOut, int nLevel) { if (chunk.Visited == true) { return; } chunk.Visited = true; foreach (FracturedChunk.AdjacencyInfo adjacency in chunk.ListAdjacentChunks) { if (adjacency.chunk) { if (chunk.FracturedObjectSource != null && adjacency.chunk.Visited == false && adjacency.chunk.IsDestructibleChunk()) { bool bConnected = adjacency.fArea > chunk.FracturedObjectSource.ChunkConnectionMinArea; if (bConnected) { float fRandom = UnityEngine.Random.value; if (fRandom > (chunk.FracturedObjectSource.ChunkConnectionStrength * nLevel)) { ComputeRandomConnectionBreaksRecursive(adjacency.chunk, listBreaksOut, nLevel + 1); listBreaksOut.Add(adjacency.chunk); } } } } } }
void OnFreeChunkCollision(FracturedChunk.CollisionInfo info) { // We can cancel the collision processing here info.bCancelCollisionEvent = false; // Simply increase a counter for each collision nChunkCollisions++; }
void OnChunkDetach(FracturedChunk.CollisionInfo info) { // We can cancel the collision processing here info.bCancelCollisionEvent = false; // Simply increase a counter for each chunk detached nChunksDetached++; }
public void NotifyChunkDetach(FracturedChunk chunk) { m_bDetached = true; SetSingleMeshVisibility(false); if (EventDetachedAnyCallMethod.Length > 0 && EventDetachedAnyCallGameObject != null) { EventDetachedAnyCallGameObject.SendMessage(EventDetachedAnyCallMethod); } }
public void OnDetach(object o) { FracturedChunk chunk = o as FracturedChunk; var destructibleObject = MapObjectUtility.GetMapObjectOfFracturedChunk(chunk); if (destructibleObject != null) { var data = destructibleObject.destructibleData; data.SetDestruction(chunk.ChunkId); data.LastSyncDestructionState = data.DestructionState; destructibleObject.flagImmutability.LastModifyServerTime = _currentTime.CurrentTime; } }
public void ConnectTo(FracturedChunk chunk, float fArea) { if (chunk) { if (chunk.IsConnectedTo(this)) { return; } ListAdjacentChunks.Add(new AdjacencyInfo(chunk, fArea)); chunk.ListAdjacentChunks.Add(new AdjacencyInfo(this, fArea)); } }
public void ConnectTo(FracturedChunk chunk, float fArea) { if(chunk) { if(chunk.IsConnectedTo(this)) { return; } ListAdjacentChunks.Add(new AdjacencyInfo(chunk, fArea)); chunk.ListAdjacentChunks.Add(new AdjacencyInfo(this, fArea)); } }
public override IEnumerator Behavior() { Collider[] cols = Physics.OverlapSphere(transform.position, radious); foreach (Collider col in cols) { FracturedChunk chunk = col.GetComponent <FracturedChunk>(); if (chunk == null) { continue; } chunk.Impact(transform.position, force, radious, true); chunk.FracturedObjectSource.SetSingleMeshVisibility(false); } yield break; }
public bool IsConnectedTo(FracturedChunk chunk) { foreach (AdjacencyInfo info in ListAdjacentChunks) { bool bHasMinArea = true; if (info.chunk.FracturedObjectSource) { bHasMinArea = info.fArea > info.chunk.FracturedObjectSource.ChunkConnectionMinArea; } if (info.chunk == chunk) { return(bHasMinArea); } } return(false); }
public void OnSceneGUI() { FracturedChunk fracturedChunk = target as FracturedChunk; if (fracturedChunk == null) { return; } FracturedObject fracturedObject = fracturedChunk.FracturedObjectSource; // Chunk connections bool bDrawLines = true; if (fracturedObject != null) { bDrawLines = fracturedObject.ShowChunkConnectionLines; } if (bDrawLines) { Color handlesColor = Handles.color; Handles.color = new Color32(155, 89, 182, 255); if (fracturedChunk.ListAdjacentChunks.Count > 0) { Handles.DotHandleCap(0, fracturedChunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(fracturedChunk.transform.position) * 0.03f, Event.current.type); } foreach (FracturedChunk.AdjacencyInfo chunkAdjacency in fracturedChunk.ListAdjacentChunks) { if (chunkAdjacency.chunk) { Handles.DotHandleCap(0, chunkAdjacency.chunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(chunkAdjacency.chunk.transform.position) * 0.03f, Event.current.type); Handles.DrawLine(fracturedChunk.transform.position, chunkAdjacency.chunk.transform.position); } } Handles.color = handlesColor; } }
public static FracturedChunk ChunkRaycast(Vector3 v3Pos, Vector3 v3Forward, out RaycastHit hitInfo) { FracturedChunk chunk = null; if (Physics.Raycast(v3Pos, v3Forward, out hitInfo)) { // Intersection found, try to check if it has a FracturedChunk component chunk = hitInfo.collider.GetComponent <FracturedChunk>(); if (chunk == null && hitInfo.collider.transform.parent != null) { // Not found, but concave collider creates child nodes, we have to take this into account as well. // In this case the FracturedChunk should be in its parent chunk = hitInfo.collider.transform.parent.GetComponent <FracturedChunk>(); } } return(chunk); }
void FireWeapon() { bool holdingDownFire = Input.GetKey(KeyCode.Mouse0); if (holdingDownFire) { _shootingTime += Time.deltaTime; _fireTimer += Time.deltaTime; if (_fireTimer > _fireInterval) { _fireTimer = 0.0f; RaycastHit hitInfo; FracturedChunk chunkRaycast = FracturedChunk.ChunkRaycast(_cameraTransform.position, _cameraTransform.forward, out hitInfo); if (chunkRaycast) { chunkRaycast.FromCenterImpact(hitInfo.point, _fromCenterForce, _fromCenterRadius, true); } GameAudio.PlayOneShot("GunShot"); } } if (!holdingDownFire && _previouslyShooting) { //if the previous shot was true and current is false //the player just stopped shooting GameAudio.PlayOneShot("ShellDrop", new Dictionary <string, float>() { { "Shots", _shootingTime } }); _shootingTime = 0.0f; } _previouslyShooting = holdingDownFire; }
private static bool AreSupportedChunksRecursive(FracturedChunk chunk, List <FracturedChunk> listChunksVisited, List <FracturedChunk> listChunksSupport) { if (chunk.Visited) { return(false); } chunk.Visited = true; listChunksVisited.Add(chunk); if (chunk.IsSupportChunk) { listChunksSupport.Add(chunk); } bool bAnyConnectedIsSupport = false; foreach (FracturedChunk.AdjacencyInfo adjacencyInfo in chunk.ListAdjacentChunks) { if (adjacencyInfo.chunk) { if (adjacencyInfo.chunk.FracturedObjectSource) { if (adjacencyInfo.fArea >= adjacencyInfo.chunk.FracturedObjectSource.ChunkConnectionMinArea) { if (AreSupportedChunksRecursive(adjacencyInfo.chunk, listChunksVisited, listChunksSupport)) { bAnyConnectedIsSupport = true; } } } } } return(chunk.IsSupportChunk || bAnyConnectedIsSupport); }
public void NotifyDetachChunkCollision(FracturedChunk.CollisionInfo collisionInfo) { // This one will be called internally from FracturedChunk from within a collision if(EventDetachCollisionCallGameObject != null && EventDetachCollisionCallMethod.Length > 0) { EventDetachCollisionCallGameObject.SendMessage(EventDetachCollisionCallMethod, collisionInfo); } if(collisionInfo.bCancelCollisionEvent == false) { NotifyDetachChunkCollision(collisionInfo.collisionInfo.contacts[0].point, collisionInfo.bIsMain); } }
public AdjacencyInfo(FracturedChunk chunk, float fArea) { this.chunk = chunk; this.fArea = fArea; }
public void NotifyFreeChunkCollision(FracturedChunk.CollisionInfo collisionInfo) { if(EventDetachedCollisionCallGameObject != null && EventDetachedCollisionCallMethod.Length > 0) { EventDetachedCollisionCallGameObject.SendMessage(EventDetachedCollisionCallMethod, collisionInfo); } if(collisionInfo.bCancelCollisionEvent == false) { if(EventDetachedSoundArray.Length > 0) { int nFreeSound = -1; for(int nSound = 0; nSound < m_afFreeChunkSoundTimers.Length; nSound++) { if(m_afFreeChunkSoundTimers[nSound] <= 0.0f) { nFreeSound = nSound; break; } } if(nFreeSound != -1) { AudioClip clip = EventDetachedSoundArray[UnityEngine.Random.Range(0, EventDetachedSoundArray.Length)]; if(clip != null) { AudioSource.PlayClipAtPoint(clip, collisionInfo.collisionInfo.contacts[0].point); } m_afFreeChunkSoundTimers[nFreeSound] = clip.length; } } if(EventDetachedPrefabsArray.Length > 0) { FracturedObject.PrefabInfo prefab = EventDetachedPrefabsArray[UnityEngine.Random.Range(0, EventDetachedPrefabsArray.Length)]; if(prefab != null) { int nFreePrefab = -1; for(int nPrefab = 0; nPrefab < m_afFreeChunkPrefabTimers.Length; nPrefab++) { if(m_afFreeChunkPrefabTimers[nPrefab] <= 0.0f) { nFreePrefab = nPrefab; break; } } if(nFreePrefab != -1) { GameObject newGameObject = Instantiate(prefab.GameObject, collisionInfo.collisionInfo.contacts[0].point, prefab.GameObject.transform.rotation) as GameObject; if(Mathf.Approximately(prefab.MinLifeTime, 0.0f) == false || Mathf.Approximately(prefab.MaxLifeTime, 0.0f) == false) { DieTimer timer = newGameObject.AddComponent<DieTimer>(); timer.SecondsToDie = UnityEngine.Random.Range(prefab.MinLifeTime, prefab.MaxLifeTime); m_afFreeChunkPrefabTimers[nFreePrefab] = timer.SecondsToDie; } else { m_afFreeChunkPrefabTimers[nFreePrefab] = float.MaxValue; } } } } } }
void Update() { if (ShootMode == Mode.FromCenter) { // Raycast if (Weapon) { Weapon.GetComponent <Renderer> ().enabled = true; } bool bShot = ShouldShoot(); if (bShot) { _shootingTime += Time.deltaTime; } bool holdingDownFire = Input.GetKey(KeyCode.Space); if (!holdingDownFire && _previousShot) { //if the previous shot was true and current is false //the player just stopped shooting GameAudio.PlayOneShot("ShellDrop", new Dictionary <string, float>() { { "Shots", _shootingTime } }); _shootingTime = 0.0f; } if (bShot) { m_fRecoilTimer = RecoilDuration; if (AudioWeaponShot) { AudioSource.PlayClipAtPoint(AudioWeaponShot, transform.position, WeaponShotVolume); } } m_bRaycastFound = false; RaycastHit hitInfo; FracturedChunk chunkRaycast = FracturedChunk.ChunkRaycast(transform.position, transform.forward, out hitInfo); if (chunkRaycast) { m_bRaycastFound = true; if (bShot) { // Hit it! chunkRaycast.FromCenterImpact(hitInfo.point, FromCenterForce, FromCenterRadius, true); } } _previousShot = holdingDownFire; } // Mouse-aim if (Input.GetMouseButton(0) && Input.GetMouseButtonDown(0) == false) { this.transform.Rotate(-(Input.mousePosition.y - m_v3MousePosition.y) * MouseSpeed, 0.0f, 0.0f); this.transform.RotateAround(this.transform.position, Vector3.up, (Input.mousePosition.x - m_v3MousePosition.x) * MouseSpeed); } m_v3MousePosition = Input.mousePosition; }
void OnCollisionEnter(Collision collision) { if (FracturedObjectSource == null || collision == null) { return; } if (collision.contacts == null) { return; } if (collision.contacts.Length == 0) { return; } if (collision.gameObject) { FracturedChunk otherChunk = collision.gameObject.GetComponent <FracturedChunk>(); if (otherChunk) { if (otherChunk.rigidbody.isKinematic && IsDetachedChunk == false) { // Just intersecting with other chunk in kinematic state return; } } } float fMass = Mathf.Infinity; // If there is no rigidbody we consider it static if (collision.rigidbody) { fMass = collision.rigidbody.mass; } if (IsDetachedChunk == false) { // Chunk still attached. // We are going to check if the collision is against a free chunk of the same object. This way we prevent chunks pushing each other out, we want to control // this only through the FractureObject.InterconnectionStrength variable bool bOtherIsFreeChunkFromSameObject = false; FracturedChunk otherChunk = collision.gameObject.GetComponent <FracturedChunk>(); if (otherChunk != null) { if (otherChunk.IsDetachedChunk == true && otherChunk.FracturedObjectSource == FracturedObjectSource) { bOtherIsFreeChunkFromSameObject = true; } } if (bOtherIsFreeChunkFromSameObject == false && collision.relativeVelocity.magnitude > FracturedObjectSource.EventDetachMinVelocity && fMass > FracturedObjectSource.EventDetachMinMass && rigidbody != null && IsDestructibleChunk()) { CollisionInfo collisionInfo = new CollisionInfo(this, collision, true); FracturedObjectSource.NotifyDetachChunkCollision(collisionInfo); if (collisionInfo.bCancelCollisionEvent == false) { List <FracturedChunk> listBreaks = new List <FracturedChunk>(); // Impact enough to make it detach. Compute random list of connected chunks that are detaching as well (we'll use the ConnectionStrength parameter). listBreaks = ComputeRandomConnectionBreaks(); listBreaks.Add(this); DetachFromObject(); foreach (FracturedChunk chunk in listBreaks) { collisionInfo.chunk = chunk; collisionInfo.bIsMain = false; collisionInfo.bCancelCollisionEvent = false; if (chunk != this) { FracturedObjectSource.NotifyDetachChunkCollision(collisionInfo); } if (collisionInfo.bCancelCollisionEvent == false) { chunk.DetachFromObject(); chunk.rigidbody.AddExplosionForce(collision.relativeVelocity.magnitude * FracturedObjectSource.EventDetachExitForce, collision.contacts[0].point, 0.0f, FracturedObjectSource.EventDetachUpwardsModifier); } } } } } else { // Free chunk if (collision.relativeVelocity.magnitude > FracturedObjectSource.EventDetachedMinVelocity && fMass > FracturedObjectSource.EventDetachedMinMass) { FracturedObjectSource.NotifyFreeChunkCollision(new CollisionInfo(this, collision, true)); } } }
public void NotifyChunkDetach(FracturedChunk chunk) { if(m_bDetached == false) { // Disable all triggerse in them so that free chunks will collide also with static non-free chunks foreach(FracturedChunk chunkInstance in ListFracturedChunks) { if(chunkInstance != null) { Collider colliderComponent = chunkInstance.GetComponent<Collider>(); if(colliderComponent != null) { colliderComponent.isTrigger = false; } } } } m_bDetached = true; SetSingleMeshVisibility(false); if(EventDetachedAnyCallMethod.Length > 0 && EventDetachedAnyCallGameObject != null) { EventDetachedAnyCallGameObject.SendMessage(EventDetachedAnyCallMethod); } }
public override void OnInspectorGUI() { bool bCheckDetachNonSupportedChunks = false; bool bMarkNonSupportedChunks = false; Color colorGUI = GUI.color; // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. serializedObject.Update(); FracturedChunk fracturedChunk = serializedObject.targetObject as FracturedChunk; PropDontDeleteAfterBroken.boolValue = EditorGUILayout.Toggle(new GUIContent("Don't Delete If Broken", "Will prevent this chunk to be deleted (due to lifetime parameters configured on the FracturedObject panel) after being broken off from the object."), PropDontDeleteAfterBroken.boolValue); EditorGUI.BeginChangeCheck(); PropIsSupportChunk.boolValue = EditorGUILayout.Toggle(new GUIContent("Is Support Chunk", "Chunks that are tagged as support can't be destroyed and will hold the object together. A chunk needs to be connected to a support chunk (directly or through other chunks) or otherwise it will fall. This prevents chunks from staying static in the air and enables realistic collapsing behavior."), PropIsSupportChunk.boolValue); if (EditorGUI.EndChangeCheck()) { if (fracturedChunk.FracturedObjectSource) { if (Application.isPlaying) { bCheckDetachNonSupportedChunks = true; } bMarkNonSupportedChunks = true; } } // Apply changes to the serializedProperty. serializedObject.ApplyModifiedProperties(); if (bCheckDetachNonSupportedChunks) { fracturedChunk.FracturedObjectSource.CheckDetachNonSupportedChunks(); } if (bMarkNonSupportedChunks) { fracturedChunk.FracturedObjectSource.MarkNonSupportedChunks(); } if (bCheckDetachNonSupportedChunks || bMarkNonSupportedChunks) { SceneView.RepaintAll(); } bCheckDetachNonSupportedChunks = false; bMarkNonSupportedChunks = false; EditorGUILayout.Space(); if (serializedObject.targetObjects.Length == 1) { EditorGUILayout.LabelField(new GUIContent("Chunk Attached To Object: " + (fracturedChunk.IsDetachedChunk ? "No" : "Yes"), "Is the chunk attached to the object or has it been detached?")); EditorGUILayout.LabelField(new GUIContent("Chunk Connected To Support: " + (fracturedChunk.IsNonSupportedChunk ? "No" : "Yes"), "Is the chunk directly or indirectly connected to a support chunk?")); EditorGUILayout.LabelField(new GUIContent("Chunk Volume: " + string.Format("{0} ({1:0.##}% of total)", fracturedChunk.Volume, fracturedChunk.RelativeVolume * 100.0f), "The chunk volume and % of volume with respect to the object")); EditorGUILayout.LabelField(new GUIContent("Concave Collider Generated: " + (fracturedChunk.HasConcaveCollider ? "Yes" : "No"), "Does this chunk have one or more colliders generated by the Concave Collider utility?")); } else { GUI.color = new Color(0.5f, 1.0f, 0.0f, 1.0f); EditorGUILayout.LabelField("Multiselection mode"); GUI.color = colorGUI; } EditorGUILayout.Space(); EditorGUILayout.Space(); Vector4 v4GUIColor = GUI.color; EditorGUILayout.BeginHorizontal(); SelectedManuallyAddChunk = EditorGUILayout.ObjectField(new GUIContent("Manually Add Connection"), SelectedManuallyAddChunk, typeof(FracturedChunk), true) as FracturedChunk; if (GUILayout.Button(new GUIContent("Connect", "Connects this chunk to the selected one."), GUILayout.Width(80))) { if (SelectedManuallyAddChunk) { if (serializedObject.targetObjects.Length == 1) { if (fracturedChunk.FracturedObjectSource != SelectedManuallyAddChunk.FracturedObjectSource) { EditorUtility.DisplayDialog("Chunks not of the same object", "The two chunks belong to different fractured objects.", "OK"); } else if (fracturedChunk.IsConnectedTo(SelectedManuallyAddChunk)) { EditorUtility.DisplayDialog("Chunks already connected", "The two chunks are already connected.", "OK"); } else { fracturedChunk.ConnectTo(SelectedManuallyAddChunk, Mathf.Min(Mathf.Sqrt(fracturedChunk.Volume), Mathf.Sqrt(SelectedManuallyAddChunk.Volume))); bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } } else { // Multi-edit foreach (Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; chunkMultiSelected.ConnectTo(SelectedManuallyAddChunk, Mathf.Min(Mathf.Sqrt(chunkMultiSelected.Volume), Mathf.Sqrt(SelectedManuallyAddChunk.Volume))); bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); if (serializedObject.targetObjects.Length == 1) { GUILayout.Label("Connections to other chunks:"); } else { GUILayout.Label("Common connections to other chunks:"); } FracturedChunk chunkToDisconnectFrom = null; // Compute common connections in multi-edit mode List <FracturedChunk> listConnectedChunks = new List <FracturedChunk>(); List <float> listAreas = new List <float>(); for (int nConnectedChunk = 0; nConnectedChunk < fracturedChunk.ListAdjacentChunks.Count; nConnectedChunk++) { FracturedChunk.AdjacencyInfo info = fracturedChunk.ListAdjacentChunks[nConnectedChunk]; if (info.chunk) { listConnectedChunks.Add(info.chunk); listAreas.Add(info.fArea); } } if (serializedObject.targetObjects.Length > 1) { // Multi-edit, only finish with those that are shared among all selected chunks foreach (Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; List <FracturedChunk> listCommonChunks = new List <FracturedChunk>(); foreach (FracturedChunk.AdjacencyInfo info in chunkMultiSelected.ListAdjacentChunks) { if (listConnectedChunks.Contains(info.chunk)) { listCommonChunks.Add(info.chunk); } } listConnectedChunks = listCommonChunks; } } for (int nConnectedChunk = 0; nConnectedChunk < listConnectedChunks.Count; nConnectedChunk++) { FracturedChunk chunk = listConnectedChunks[nConnectedChunk]; float fArea = listAreas[nConnectedChunk]; if (chunk) { EditorGUILayout.BeginHorizontal(); if (chunk.IsSupportChunk) { GUI.color = new Color(0.6f, 0.6f, 1.0f, 1.0f); } GUILayout.Label(string.Format("{0} (Surface {1})", chunk.name, serializedObject.targetObjects.Length == 1 ? fArea.ToString("F3") : "")); GUI.color = v4GUIColor; GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("Disconnect", "Disconnects the currently selected chunk from this one"), GUILayout.Width(80))) { if (fracturedChunk.FracturedObjectSource != null) { chunkToDisconnectFrom = chunk; } } if (GUILayout.Button(new GUIContent("Select", "Changes the active selection to this chunk"), GUILayout.Width(80))) { if (fracturedChunk.FracturedObjectSource != null) { UnityEditor.Selection.activeGameObject = chunk.gameObject; } } EditorGUILayout.EndHorizontal(); } } if (chunkToDisconnectFrom != null) { foreach (Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; chunkMultiSelected.DisconnectFrom(chunkToDisconnectFrom); } bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } if (bCheckDetachNonSupportedChunks) { fracturedChunk.FracturedObjectSource.CheckDetachNonSupportedChunks(); } if (bMarkNonSupportedChunks) { fracturedChunk.FracturedObjectSource.MarkNonSupportedChunks(); } EditorGUILayout.Space(); EditorGUILayout.Space(); int nButtonWidth = 200; GUI.enabled = serializedObject.targetObjects.Length == 1; EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if (GUILayout.Button(new GUIContent("Go To Fractured Object", "Selects the FracturedObject this chunk comes from"), GUILayout.Width(nButtonWidth))) { if (fracturedChunk.FracturedObjectSource != null) { UnityEditor.Selection.activeGameObject = fracturedChunk.FracturedObjectSource.gameObject; } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if (GUILayout.Button(new GUIContent("Show Non-Connected Chunks", "Enables the MeshRenderer of all the chunks that are not directly connected to this chunk."), GUILayout.Width(nButtonWidth))) { if (fracturedChunk.FracturedObjectSource != null) { foreach (FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if (chunk) { if (fracturedChunk.IsConnectedTo(chunk) == false) { chunk.GetComponent <Renderer>().enabled = true; } } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if (GUILayout.Button(new GUIContent("Hide Non-Connected Chunks", "Disables the MeshRenderer of all the chunks that are not directly connected to this chunk."), GUILayout.Width(nButtonWidth))) { if (fracturedChunk.FracturedObjectSource != null) { foreach (FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if (chunk) { if (fracturedChunk.IsConnectedTo(chunk) == false && fracturedChunk != chunk) { chunk.GetComponent <Renderer>().enabled = false; } } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if (GUILayout.Button(new GUIContent("Show All Other Chunks", "Enables the MeshRenderer of all the other chunks in the object."), GUILayout.Width(nButtonWidth))) { if (fracturedChunk.FracturedObjectSource != null) { foreach (FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if (chunk && fracturedChunk != chunk) { chunk.GetComponent <Renderer>().enabled = true; } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if (GUILayout.Button(new GUIContent("Hide All Other Chunks", "Disables the MeshRenderer of all the other chunks in the object."), GUILayout.Width(nButtonWidth))) { if (fracturedChunk.FracturedObjectSource != null) { foreach (FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if (chunk && fracturedChunk != chunk) { chunk.GetComponent <Renderer>().enabled = false; } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); GUI.enabled = true; if (bCheckDetachNonSupportedChunks || bMarkNonSupportedChunks) { SceneView.RepaintAll(); } }
public void Explode(Vector3 v3ExplosionPosition, float fExplosionForce) { // Explodes all chunks if (m_bExploded == true) { return; } // Play sound if (EventExplosionSound) { AudioSource.PlayClipAtPoint(EventExplosionSound, v3ExplosionPosition); } // Instance prefabs on random positions if (EventExplosionPrefabsArray.Length > 0 && EventExplosionPrefabsInstanceCount > 0 && ListFracturedChunks.Count > 0) { for (int i = 0; i < EventExplosionPrefabsInstanceCount; i++) { FracturedObject.PrefabInfo prefab = EventExplosionPrefabsArray[UnityEngine.Random.Range(0, EventExplosionPrefabsArray.Length)]; if (prefab != null) { FracturedChunk chunkRandom = null; while (chunkRandom == null) { chunkRandom = ListFracturedChunks[UnityEngine.Random.Range(0, ListFracturedChunks.Count)]; } GameObject newGameObject = Instantiate(prefab.GameObject, chunkRandom.transform.position, prefab.GameObject.transform.rotation) as GameObject; if (Mathf.Approximately(prefab.MinLifeTime, 0.0f) == false || Mathf.Approximately(prefab.MaxLifeTime, 0.0f) == false) { DieTimer timer = newGameObject.AddComponent <DieTimer>(); timer.SecondsToDie = UnityEngine.Random.Range(prefab.MinLifeTime, prefab.MaxLifeTime); } } } } // Explode chunks foreach (FracturedChunk chunk in ListFracturedChunks) { if (chunk) { chunk.ListAdjacentChunks.Clear(); if (chunk.IsDestructibleChunk() && chunk.IsDetachedChunk == false) { chunk.DetachFromObject(false); chunk.GetComponent <Rigidbody>().AddExplosionForce(fExplosionForce, v3ExplosionPosition, 0.0f, 0.0f); } } } m_bExploded = true; }
public static MapObjectEntity GetMapObjectOfFracturedChunk(FracturedChunk chunk) { var mapObject = GetMapObjectOfFracturedChunk <FracturedChunk, FracturedObject>(chunk); return(mapObject != null && mapObject.hasDestructibleData ? mapObject : null); }
public bool IsConnectedTo(FracturedChunk chunk) { foreach(AdjacencyInfo info in ListAdjacentChunks) { bool bHasMinArea = true; if(info.chunk.FracturedObjectSource) { bHasMinArea = info.fArea > info.chunk.FracturedObjectSource.ChunkConnectionMinArea; } if(info.chunk == chunk) { return bHasMinArea; } } return false; }
private static void ComputeRandomConnectionBreaksRecursive(FracturedChunk chunk, List<FracturedChunk> listBreaksOut, int nLevel) { if(chunk.Visited == true) { return; } chunk.Visited = true; foreach(FracturedChunk.AdjacencyInfo adjacency in chunk.ListAdjacentChunks) { if(adjacency.chunk) { if(chunk.FracturedObjectSource != null && adjacency.chunk.Visited == false && adjacency.chunk.IsDestructibleChunk()) { bool bConnected = adjacency.fArea > chunk.FracturedObjectSource.ChunkConnectionMinArea; if(bConnected) { float fRandom = UnityEngine.Random.value; if(fRandom > (chunk.FracturedObjectSource.ChunkConnectionStrength * nLevel)) { ComputeRandomConnectionBreaksRecursive(adjacency.chunk, listBreaksOut, nLevel + 1); listBreaksOut.Add(adjacency.chunk); } } } } } }
public void DisconnectFrom(FracturedChunk chunk) { if(chunk) { if(chunk.IsConnectedTo(this)) { for(int i = 0; i < ListAdjacentChunks.Count; i++) { if(ListAdjacentChunks[i].chunk == chunk) { ListAdjacentChunks.RemoveAt(i); break; } } for(int i = 0; i < chunk.ListAdjacentChunks.Count; i++) { if(chunk.ListAdjacentChunks[i].chunk == this) { chunk.ListAdjacentChunks.RemoveAt(i); break; } } } } }
void Update() { if (Input.GetKeyDown(KeyCode.W)) { ShootMode = ShootMode == Mode.ExplodeRaycast ? Mode.ShootObjects : Mode.ExplodeRaycast; } if (ObjectToShoot != null && ShootMode == Mode.ShootObjects) { // Shoot objects if (Weapon) { Weapon.GetComponent <Renderer>().enabled = false; } if (Input.GetKeyDown(KeyCode.Space)) { GameObject newObject = GameObject.Instantiate(ObjectToShoot) as GameObject; newObject.transform.position = this.transform.position; newObject.transform.localScale = new Vector3(ObjectScale, ObjectScale, ObjectScale); newObject.GetComponent <Rigidbody>().mass = ObjectMass; newObject.GetComponent <Rigidbody>().solverIterations = 255; newObject.GetComponent <Rigidbody>().AddForce(this.transform.forward * InitialObjectSpeed, ForceMode.VelocityChange); //DieTimer dieTimer = newObject.AddComponent<DieTimer>() as DieTimer; //dieTimer.SecondsToDie = ObjectLife; } } if (ShootMode == Mode.ExplodeRaycast) { // Raycast if (Weapon) { Weapon.GetComponent <Renderer>().enabled = true; } bool bShot = Input.GetKeyDown(KeyCode.Space); if (bShot) { m_fRecoilTimer = RecoilDuration; if (AudioWeaponShot) { AudioSource.PlayClipAtPoint(AudioWeaponShot, transform.position, WeaponShotVolume); } } m_bRaycastFound = false; RaycastHit hitInfo; FracturedChunk chunkRaycast = FracturedChunk.ChunkRaycast(transform.position, transform.forward, out hitInfo); if (chunkRaycast) { m_bRaycastFound = true; if (bShot) { // Hit it! chunkRaycast.Impact(hitInfo.point, ExplosionForce, ExplosionRadius, true); } } } // Update recoil if (m_fRecoilTimer > 0.0f) { if (Weapon) { // Some rudimentary recoil animation here Weapon.transform.localPosition = m_v3InitialWeaponPos + new Vector3(0.0f, 0.0f, (-m_fRecoilTimer / RecoilDuration) * RecoilIntensity); Weapon.transform.localRotation = m_qInitialWeaponRot * Quaternion.Euler(new Vector3((m_fRecoilTimer / RecoilDuration) * 360.0f * RecoilIntensity * 0.1f, 0.0f, 0.0f)); } m_fRecoilTimer -= Time.deltaTime; } else { if (Weapon) { Weapon.transform.localPosition = m_v3InitialWeaponPos; Weapon.transform.localRotation = m_qInitialWeaponRot; } } // Mouse-aim if (Input.GetMouseButton(0) && Input.GetMouseButtonDown(0) == false) { this.transform.Rotate(-(Input.mousePosition.y - m_v3MousePosition.y) * MouseSpeed, 0.0f, 0.0f); this.transform.RotateAround(this.transform.position, Vector3.up, (Input.mousePosition.x - m_v3MousePosition.x) * MouseSpeed); } m_v3MousePosition = Input.mousePosition; }
public void NotifyChunkDetach(FracturedChunk chunk) { m_bDetached = true; SetSingleMeshVisibility(false); if(EventDetachedAnyCallMethod.Length > 0 && EventDetachedAnyCallGameObject != null) { EventDetachedAnyCallGameObject.SendMessage(EventDetachedAnyCallMethod); } }
public override void OnInspectorGUI() { bool bCheckDetachNonSupportedChunks = false; bool bMarkNonSupportedChunks = false; Color colorGUI = GUI.color; // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. serializedObject.Update(); FracturedChunk fracturedChunk = serializedObject.targetObject as FracturedChunk; PropDontDeleteAfterBroken.boolValue = EditorGUILayout.Toggle(new GUIContent("Don't Delete If Broken", "Will prevent this chunk to be deleted (due to lifetime parameters configured on the FracturedObject panel) after being broken off from the object."), PropDontDeleteAfterBroken.boolValue); EditorGUI.BeginChangeCheck(); PropIsSupportChunk.boolValue = EditorGUILayout.Toggle(new GUIContent("Is Support Chunk", "Chunks that are tagged as support can't be destroyed and will hold the object together. A chunk needs to be connected to a support chunk (directly or through other chunks) or otherwise it will fall. This prevents chunks from staying static in the air and enables realistic collapsing behavior."), PropIsSupportChunk.boolValue); if(EditorGUI.EndChangeCheck()) { if(fracturedChunk.FracturedObjectSource) { if(Application.isPlaying) { bCheckDetachNonSupportedChunks = true; } bMarkNonSupportedChunks = true; } } // Apply changes to the serializedProperty. serializedObject.ApplyModifiedProperties(); if(bCheckDetachNonSupportedChunks) { fracturedChunk.FracturedObjectSource.CheckDetachNonSupportedChunks(); } if(bMarkNonSupportedChunks) { fracturedChunk.FracturedObjectSource.MarkNonSupportedChunks(); } if(bCheckDetachNonSupportedChunks || bMarkNonSupportedChunks) { SceneView.RepaintAll(); } bCheckDetachNonSupportedChunks = false; bMarkNonSupportedChunks = false; EditorGUILayout.Space(); if(serializedObject.targetObjects.Length == 1) { EditorGUILayout.LabelField(new GUIContent("Chunk Attached To Object: " + (fracturedChunk.IsDetachedChunk ? "No" : "Yes"), "Is the chunk attached to the object or has it been detached?")); EditorGUILayout.LabelField(new GUIContent("Chunk Connected To Support: " + (fracturedChunk.IsNonSupportedChunk ? "No" : "Yes"), "Is the chunk directly or indirectly connected to a support chunk?")); EditorGUILayout.LabelField(new GUIContent("Chunk Volume: " + string.Format("{0} ({1:0.##}% of total)", fracturedChunk.Volume, fracturedChunk.RelativeVolume * 100.0f), "The chunk volume and % of volume with respect to the object")); EditorGUILayout.LabelField(new GUIContent("Concave Collider Generated: " + (fracturedChunk.HasConcaveCollider ? "Yes" : "No"), "Does this chunk have one or more colliders generated by the Concave Collider utility?")); } else { GUI.color = new Color(0.5f, 1.0f, 0.0f, 1.0f); EditorGUILayout.LabelField("Multiselection mode"); GUI.color = colorGUI; } EditorGUILayout.Space(); EditorGUILayout.Space(); Vector4 v4GUIColor = GUI.color; EditorGUILayout.BeginHorizontal(); SelectedManuallyAddChunk = EditorGUILayout.ObjectField(new GUIContent("Manually Add Connection"), SelectedManuallyAddChunk, typeof(FracturedChunk), true) as FracturedChunk; if(GUILayout.Button(new GUIContent("Connect", "Connects this chunk to the selected one."), GUILayout.Width(80))) { if(SelectedManuallyAddChunk) { if(serializedObject.targetObjects.Length == 1) { if(fracturedChunk.FracturedObjectSource != SelectedManuallyAddChunk.FracturedObjectSource) { EditorUtility.DisplayDialog("Chunks not of the same object", "The two chunks belong to different fractured objects.", "OK"); } else if(fracturedChunk.IsConnectedTo(SelectedManuallyAddChunk)) { EditorUtility.DisplayDialog("Chunks already connected", "The two chunks are already connected.", "OK"); } else { fracturedChunk.ConnectTo(SelectedManuallyAddChunk, Mathf.Min(Mathf.Sqrt(fracturedChunk.Volume), Mathf.Sqrt(SelectedManuallyAddChunk.Volume))); bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } } else { // Multi-edit foreach(Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; chunkMultiSelected.ConnectTo(SelectedManuallyAddChunk, Mathf.Min(Mathf.Sqrt(chunkMultiSelected.Volume), Mathf.Sqrt(SelectedManuallyAddChunk.Volume))); bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); if(serializedObject.targetObjects.Length == 1) { GUILayout.Label("Connections to other chunks:"); } else { GUILayout.Label("Common connections to other chunks:"); } FracturedChunk chunkToDisconnectFrom = null; // Compute common connections in multi-edit mode List<FracturedChunk> listConnectedChunks = new List<FracturedChunk>(); List<float> listAreas = new List<float>(); for(int nConnectedChunk = 0; nConnectedChunk < fracturedChunk.ListAdjacentChunks.Count; nConnectedChunk++) { FracturedChunk.AdjacencyInfo info = fracturedChunk.ListAdjacentChunks[nConnectedChunk]; if(info.chunk) { listConnectedChunks.Add(info.chunk); listAreas.Add(info.fArea); } } if(serializedObject.targetObjects.Length > 1) { // Multi-edit, only finish with those that are shared among all selected chunks foreach(Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; List<FracturedChunk> listCommonChunks = new List<FracturedChunk>(); foreach(FracturedChunk.AdjacencyInfo info in chunkMultiSelected.ListAdjacentChunks) { if(listConnectedChunks.Contains(info.chunk)) { listCommonChunks.Add(info.chunk); } } listConnectedChunks = listCommonChunks; } } for(int nConnectedChunk = 0; nConnectedChunk < listConnectedChunks.Count; nConnectedChunk++) { FracturedChunk chunk = listConnectedChunks[nConnectedChunk]; float fArea = listAreas[nConnectedChunk]; if(chunk) { EditorGUILayout.BeginHorizontal(); if(chunk.IsSupportChunk) { GUI.color = new Color(0.6f, 0.6f, 1.0f, 1.0f); } GUILayout.Label(string.Format("{0} (Surface {1})", chunk.name, serializedObject.targetObjects.Length == 1 ? fArea.ToString("F3") : "")); GUI.color = v4GUIColor; GUILayout.FlexibleSpace(); if(GUILayout.Button(new GUIContent("Disconnect", "Disconnects the currently selected chunk from this one"), GUILayout.Width(80))) { if(fracturedChunk.FracturedObjectSource != null) { chunkToDisconnectFrom = chunk; } } if(GUILayout.Button(new GUIContent("Select", "Changes the active selection to this chunk"), GUILayout.Width(80))) { if(fracturedChunk.FracturedObjectSource != null) { UnityEditor.Selection.activeGameObject = chunk.gameObject; } } EditorGUILayout.EndHorizontal(); } } if(chunkToDisconnectFrom != null) { foreach(Object objectMultiselection in serializedObject.targetObjects) { FracturedChunk chunkMultiSelected = objectMultiselection as FracturedChunk; chunkMultiSelected.DisconnectFrom(chunkToDisconnectFrom); } bCheckDetachNonSupportedChunks = true; bMarkNonSupportedChunks = true; } if(bCheckDetachNonSupportedChunks) { fracturedChunk.FracturedObjectSource.CheckDetachNonSupportedChunks(); } if(bMarkNonSupportedChunks) { fracturedChunk.FracturedObjectSource.MarkNonSupportedChunks(); } EditorGUILayout.Space(); EditorGUILayout.Space(); int nButtonWidth = 200; GUI.enabled = serializedObject.targetObjects.Length == 1; EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if(GUILayout.Button(new GUIContent("Go To Fractured Object", "Selects the FracturedObject this chunk comes from"), GUILayout.Width(nButtonWidth))) { if(fracturedChunk.FracturedObjectSource != null) { UnityEditor.Selection.activeGameObject = fracturedChunk.FracturedObjectSource.gameObject; } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if(GUILayout.Button(new GUIContent("Show Non-Connected Chunks", "Enables the MeshRenderer of all the chunks that are not directly connected to this chunk."), GUILayout.Width(nButtonWidth))) { if(fracturedChunk.FracturedObjectSource != null) { foreach(FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if(chunk) { if(fracturedChunk.IsConnectedTo(chunk) == false) { chunk.GetComponent<Renderer>().enabled = true; } } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if(GUILayout.Button(new GUIContent("Hide Non-Connected Chunks", "Disables the MeshRenderer of all the chunks that are not directly connected to this chunk."), GUILayout.Width(nButtonWidth))) { if(fracturedChunk.FracturedObjectSource != null) { foreach(FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if(chunk) { if(fracturedChunk.IsConnectedTo(chunk) == false && fracturedChunk != chunk) { chunk.GetComponent<Renderer>().enabled = false; } } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if(GUILayout.Button(new GUIContent("Show All Other Chunks", "Enables the MeshRenderer of all the other chunks in the object."), GUILayout.Width(nButtonWidth))) { if(fracturedChunk.FracturedObjectSource != null) { foreach(FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if(chunk && fracturedChunk != chunk) { chunk.GetComponent<Renderer>().enabled = true; } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" "); if(GUILayout.Button(new GUIContent("Hide All Other Chunks", "Disables the MeshRenderer of all the other chunks in the object."), GUILayout.Width(nButtonWidth))) { if(fracturedChunk.FracturedObjectSource != null) { foreach(FracturedChunk chunk in fracturedChunk.FracturedObjectSource.ListFracturedChunks) { if(chunk && fracturedChunk != chunk) { chunk.GetComponent<Renderer>().enabled = false; } } } } GUILayout.Label(" "); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); GUI.enabled = true; if(bCheckDetachNonSupportedChunks || bMarkNonSupportedChunks) { SceneView.RepaintAll(); } }
void Start() { vio = gameObject.GetComponent <VRTK_InteractableObject> (); cScript = gameObject.GetComponent <FracturedChunk>(); vio.isGrabbable = false; }
private static bool AreSupportedChunksRecursive(FracturedChunk chunk, List<FracturedChunk> listChunksVisited, List<FracturedChunk> listChunksSupport) { if(chunk.Visited) { return false; } chunk.Visited = true; listChunksVisited.Add(chunk); if(chunk.IsSupportChunk) { listChunksSupport.Add(chunk); } bool bAnyConnectedIsSupport = false; foreach(FracturedChunk.AdjacencyInfo adjacencyInfo in chunk.ListAdjacentChunks) { if(adjacencyInfo.chunk) { if(adjacencyInfo.chunk.FracturedObjectSource) { if(adjacencyInfo.fArea >= adjacencyInfo.chunk.FracturedObjectSource.ChunkConnectionMinArea) { if(AreSupportedChunksRecursive(adjacencyInfo.chunk, listChunksVisited, listChunksSupport)) { bAnyConnectedIsSupport = true; } } } } } return chunk.IsSupportChunk || bAnyConnectedIsSupport; }
public Vector3 collisionPoint; // The collision point #endregion Fields #region Constructors public CollisionInfo(FracturedChunk chunk, Vector3 collisionPoint, bool bIsMain) { this.chunk = chunk; this.collisionPoint = collisionPoint; this.bIsMain = bIsMain; bCancelCollisionEvent = false; }
void HandleCollision(Collider other, Vector3 v3CollisionPos, float relativeSpeed) { if (FracturedObjectSource == null || other == null) { return; } if (other.gameObject) { FracturedChunk otherChunk = other.gameObject.GetComponent <FracturedChunk>(); if (otherChunk && (other.attachedRigidbody != null)) { if (other.attachedRigidbody.isKinematic && IsDetachedChunk == false) { // Just intersecting with other chunk in kinematic state return; } } } float fMass = Mathf.Infinity; // If there is no rigidbody we consider it static Rigidbody otherRigidbody = other.attachedRigidbody; if (otherRigidbody != null) { fMass = otherRigidbody.mass; } if (IsDetachedChunk == false) { // Chunk still attached. // We are going to check if the collision is against a free chunk of the same object. This way we prevent chunks pushing each other out, we want to control // this only through the FractureObject.InterconnectionStrength variable bool bOtherIsFreeChunkFromSameObject = false; FracturedChunk otherChunk = other.gameObject.GetComponent <FracturedChunk>(); if (otherChunk != null) { if (otherChunk.IsDetachedChunk == true && otherChunk.FracturedObjectSource == FracturedObjectSource) { bOtherIsFreeChunkFromSameObject = true; } } if (bOtherIsFreeChunkFromSameObject == false && relativeSpeed > FracturedObjectSource.EventDetachMinVelocity && fMass > FracturedObjectSource.EventDetachMinMass && (GetComponent <Collider>() != null && GetComponent <Collider>().attachedRigidbody) && IsDestructibleChunk()) { CollisionInfo collisionInfo = new CollisionInfo(this, v3CollisionPos, true); FracturedObjectSource.NotifyDetachChunkCollision(collisionInfo); if (collisionInfo.bCancelCollisionEvent == false) { List <FracturedChunk> listBreaks = new List <FracturedChunk>(); // Impact enough to make it detach. Compute random list of connected chunks that are detaching as well (we'll use the ConnectionStrength parameter). listBreaks = ComputeRandomConnectionBreaks(); listBreaks.Add(this); DetachFromObject(); foreach (FracturedChunk chunk in listBreaks) { collisionInfo.chunk = chunk; collisionInfo.bIsMain = false; collisionInfo.bCancelCollisionEvent = false; if (chunk != this) { FracturedObjectSource.NotifyDetachChunkCollision(collisionInfo); } if (collisionInfo.bCancelCollisionEvent == false) { chunk.DetachFromObject(); chunk.GetComponent <Collider>().attachedRigidbody.AddExplosionForce(relativeSpeed * FracturedObjectSource.EventDetachExitForce, otherRigidbody.transform.position, 0.0f, FracturedObjectSource.EventDetachUpwardsModifier); } } } } } else { // Free chunk Rigidbody myRigidbody = GetComponent <Collider>().attachedRigidbody; Vector3 otherVelocity = otherRigidbody != null ? otherRigidbody.velocity : Vector3.zero; float relativeSpeedFree = (otherVelocity - myRigidbody.velocity).magnitude; if (relativeSpeedFree > FracturedObjectSource.EventDetachedMinVelocity && fMass > FracturedObjectSource.EventDetachedMinMass) { FracturedObjectSource.NotifyFreeChunkCollision(new CollisionInfo(this, v3CollisionPos, true)); } } }