Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Need help to achieve more realistic physics with destruction system

Discussion in 'Scripting' started by Sigillimus, Jan 3, 2016.

  1. Sigillimus

    Sigillimus

    Joined:
    Jul 24, 2012
    Posts:
    9
    Right now I've got a destruction system that uses a wall, broken into smaller pieces inside of 3ds Max, which remains held together in the game until a Rigidbody is attached to any of the pieces - at which point they will be affected by gravity.

    You can see an example of this here.

    You can probably see the issue, too. Right now, only the objects which are struck by a Rigidbody with a certain Tag will be affected. What I'm trying to achieve is a sense of 'support', such that when a block doesn't have any blocks below or above it, it will become a Rigidbody and fall to the ground as well. I'm just not sure how to approach this, though. I'm still relatively new to the whole Unity scripting thing, so I'd appreciate any help.
     
  2. kietus

    kietus

    Joined:
    Jun 4, 2013
    Posts:
    54
    Hello,

    It already look nice.
    I suppose they are many ways to achieve a "support" mode for your destruction system, and different levels of complexity. The topic is interesting, I wrote a small example of how I would have tried to achieve it. That's not compiled code, just to give you a possible approach.

    Code (csharp):
    1.  
    2.   public class DestructibleObject : MonoBehaviour
    3.   {
    4.      public List<DestructibleBlock> Blocks { get; set; }
    5.  
    6.      private void Awake()
    7.      {
    8.         // - All that part should settle in a 'Setup' script, value serialized/saved.
    9.         Blocks = new List<DestructibleBlock>();
    10.  
    11.         // setup blocks inside your object, and keep a ref of them
    12.         foreach (Transform child in transform)
    13.         {
    14.               MeshCollider collider = child.gameObject.AddComponent<MeshCollider>();
    15.               collider.convex = true;
    16.               Rigidbody rbody = child.gameObject.AddComponent<Rigidbody>();
    17.               rbody.isKinematic = true;
    18.  
    19.               Blocks.Add(child.gameObject.AddComponent<DestructibleBlock>());
    20.         }
    21.         // parse the block list and detect neighbors block + setup value like Height, Size etc..
    22.         foreach (DestructibleBlock block in Blocks)
    23.        {
    24.               // - get neighbors collider in reasonable range (mostly depend part size)
    25.               Collider[] hitColliders  = Physics.OverlapSphere(block.transform.position, 3);
    26.               DestructibleBlock neighborBlock;
    27.               foreach (Collider collider in hitColliders)
    28.               {
    29.                     neighborBlock = collider.GetComponent<DestructibleBlock>();
    30.                    if (neighborBlock!=null)
    31.                     {
    32.                           if (block.GetComponent<MeshCollider>().bounds.Intersects(collider.bounds))
    33.                           block.Neighbors.Add(neighborBlock);
    34.                     }
    35.               }
    36.               // - save local height of the part
    37.               block.Height = block.transform.localPosition.y;
    38.               // - register to the block destroyed event
    39.               block.BlockDestroyed += BlockDestroyed;
    40.        }
    41.   }
    42.  
    43.      // - fired when a block is destroyed
    44.      public void BlockDestroyed (object sender,System.EventArgs e)
    45.      {
    46.         DestructibleBlock block = (sender as DestructibleBlock);
    47.  
    48.         // - manage neighbors block
    49.         foreach (DestructibleBlock neighborBlock in block.Neighbors)
    50.         {
    51.             // - remove ref of that destroyed block in his neighbors block
    52.             neighborBlock.Neighbors.Remove(block);
    53.  
    54.            // here you need to proceed the neighborBlock and check condition if they needs to be destroyed or not.
    55.            // minimum :
    56.            if (neighborBlock.Neighbors.Count == 0)
    57.                  neighborBlock.DestroyBlock(); // --> if a block meet all conditions, destroy it.
    58.            // more : you need to check all Neighbors left and see if they match condition to be destroyed, where    block.Height can help.
    59.         }
    60.  
    61.         // - remove the block from main list
    62.         Blocks.Remove(block);
    63.      }
    64.   }
    65.  
    66.   public class DestructibleBlock:MonoBehaviour
    67.   {
    68.      public event System.EventHandler BlockDestroyed;
    69.      public List<DestructibleBlock> Neighbors;
    70.      public float Height { get; set; }
    71.  
    72.      public void DestroyBlock() // Called by the trigger, or the DestructibleObject.BlockDestroyed function
    73.      {
    74.         OnPartDestroyed();
    75.         GetComponent<Rigidbody>().isKinematic = false;
    76.      }
    77.  
    78.      protected virtual void OnPartDestroyed()
    79.      {
    80.         if (BlockDestroyed != null)
    81.         {
    82.            BlockDestroyed(this, System.EventArgs.Empty);
    83.         }
    84.      }
    85.   }
    86.  
    87.