4
\$\begingroup\$

I have a Car, who needs a Box Collider. If the car would be 1 single mesh, i would only need to call:

        boxCol = gameObject.AddComponent<BoxCollider>();

and it would create a boxCollider, which fits perfectly my car, based on my car's mesh.

Now I have a car which exists of many different parts in the hierarchy. (for example: Body of the car is the parent of the 4 doors. Every door is 1 seperate gameobject, and has a doorknob child etc. )

now i need a script which changes the boxCollider so, that it has the box surrounding the whole car.

i found: http://answers.unity3d.com/questions/22019/auto-sizing-primitive-collider-based-on-child-mesh.html

but it just doesnt get me the right collider.

Edit: I just tried again - and the Boxcollider stays the same.

using UnityEngine;
using UnityEditor;
using System.Collections;

public class ColliderToFit : MonoBehaviour
{

    [MenuItem("My Tools/Collider/Fit to Children")]
    static void FitToChildren()
    {
        foreach (GameObject rootGameObject in Selection.gameObjects)
        {
            if (!(rootGameObject.GetComponent<Collider>()  is BoxCollider))
                continue;

            bool hasBounds = false;
            Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);

            for (int i = 0; i < rootGameObject.transform.childCount; ++i)
            {
                Renderer childRenderer = rootGameObject.transform.GetChild(i).GetComponent<Renderer>();
                if (childRenderer != null)
                {
                    if (hasBounds)
                    {
                        bounds.Encapsulate(childRenderer.bounds);
                    }
                    else
                    {
                        bounds = childRenderer.bounds;
                        hasBounds = true;
                    }
                }
            }

            BoxCollider collider = (BoxCollider)rootGameObject.GetComponent<Collider>();
            collider.center = bounds.center - rootGameObject.transform.position;
            collider.size = bounds.size;
        }
    }

}
\$\endgroup\$
3
  • 4
    \$\begingroup\$ "but it just doesnt get me the right collider" - Every time you say "this solution did not work" it's important to include in what way it didn't work. ie. how did its result differ from what you wanted? Without this information, it's very difficult for someone to discern what kind of help you need. \$\endgroup\$
    – DMGregory
    Aug 29 '16 at 13:26
  • 1
    \$\begingroup\$ there is no recursion, so it will only walk through first level children you can do GetComponentsInChildren and extend your target box based on child size \$\endgroup\$
    – Yevhen
    Aug 29 '16 at 18:46
  • \$\begingroup\$ well - i know. The Boxcollider doesnt even change for its children though \$\endgroup\$
    – OC_RaizW
    Aug 30 '16 at 7:40
3
\$\begingroup\$

I found out that the Boxcollider I get from the solution above was only expanding the bounds of all the children while leaving out the gameObject itself aswell as all other descendants, and it only delivered the right solution for position and rotation 0, and scale 1, which confused me at first.

here is the code that will surround the gameobject and every descendant: (keep in mind that you need to set the position and the rotation to 0 and the localScale to 1 and to get the right Collider. Just store the old transform variables somewhere and then set them to 0 (and scale to 1) , then change the collider (call this script), then set the transform variables back again) . Have fun!

public void addBoundsToAllChildren()
{
    if (boxCol == null)
    {
        boxCol = gameObject.GetComponent(typeof(BoxCollider)) as BoxCollider;
        if (boxCol == null)
        {
            boxCol = gameObject.AddComponent<BoxCollider>();
        }
    }
    Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);
    Renderer thisRenderer = transform.GetComponent<Renderer>();
    bounds.Encapsulate(thisRenderer.bounds);
    boxCol.offset = bounds.center - transform.position;
    boxCol.size = bounds.size;

    allDescendants = gameObject.GetComponentsInChildren<Transform>();
    foreach (Transform desc in allDescendants)
    {
        Renderer childRenderer = desc.GetComponent<Renderer>();
        if (childRenderer != null)
        {
           bounds.Encapsulate(childRenderer.bounds);
        }
        boxCol.offset = bounds.center - transform.position;
        boxCol.size = bounds.size;
    }
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ It seems that now there's no BoxCollider.offset in Unity. \$\endgroup\$ Aug 31 '18 at 2:30
  • 1
    \$\begingroup\$ @user1566515 Instead of offset you can use BoxCollider.center I suppose \$\endgroup\$ Jun 27 '19 at 19:40
  • \$\begingroup\$ This approach does assume the root object has a Renderer, which may not be true. It's pretty common to have an empty root to contain the meshes, so everything from thisRenderer outside the loop should be inside code like if (transform.TryGetComponent<Renderer>(out var thisRenderer)){ } \$\endgroup\$
    – jhocking
    Jun 3 '20 at 13:41
  • \$\begingroup\$ I've been using this for a while and just had to modify it to fix a bug, here's the code now (along with links in the comments explaining the problem) gist.github.com/jhocking/e64a5abdcae9b294f02cec56e26fb14b \$\endgroup\$
    – jhocking
    Feb 10 at 16:00
2
\$\begingroup\$

A modified version of @OC_RaizW answer for BoxCollider2D (only children taken into account, not self):

public void addBoundsToAllChildren()
{

    var boxCol = gameObject.GetComponent<BoxCollider2D>();
    if (boxCol == null)
    {
        boxCol = gameObject.AddComponent<BoxCollider2D>();
    }

    Bounds bounds = new Bounds(transform.position, Vector3.zero);

    var allDescendants = gameObject.GetComponentsInChildren<Transform>();
    foreach (Transform desc in allDescendants)
    {
        Renderer childRenderer = desc.GetComponent<Renderer>();
        if (childRenderer != null)
        {
            bounds.Encapsulate(childRenderer.bounds);
        }
        boxCol.offset = bounds.center - transform.position;
        boxCol.size = bounds.size;
    }
}
\$\endgroup\$
-2
\$\begingroup\$

Maybe I'm misunderstanding the question, but why don't you just go into Unity and create the Box Collider and make it the right size you want? As opposed to trying to create it in code. As long as all the other components are a part of the car, it will surround them too.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This sounds more like a comment than an actual answer. In fact, your not addressing the actual question at all, other then suggesting a complete alternative. \$\endgroup\$
    – Gnemlock
    Aug 31 '16 at 3:40
  • \$\begingroup\$ Because I can't do that for custom meshes. \$\endgroup\$
    – OC_RaizW
    Aug 31 '16 at 8:03
  • \$\begingroup\$ @OC_RaizW I apologize, I didn't realize that. \$\endgroup\$ Aug 31 '16 at 12:10
  • \$\begingroup\$ If all you want is a box collider that surrounds your car, then Ethan's answer is correct, you can just do that in the inspector, no code required. \$\endgroup\$ Sep 2 '16 at 16:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.