前言

经常碰到一些不需要精确碰撞的不规则模型,此时只需要一个BoxCollider把它和它的子物体包裹进去即可。
不规则子物体

手动加碰撞盒非常麻烦,不仅中心点不准确,大小也需要手动调整。而利用Renderer组件,可以获取模型的渲染大小及中心点,经过简单的计算就可以自动生成合适的BoxCollider。

实现

1.关键方法

  1. Selection.activeGameObject
    位于UnityEditor命名空间下,获得层级视图中选定的游戏物体。
  2. Render.bounds
    GameObject的MeshRender(或其他Render组件)的渲染边界框,即实际大小。
  3. Transform.InverseTransformPoint
    将世界坐标转换为本地坐标。

2.完整脚本

using UnityEngine;
using UnityEditor;
public class MyTools : Editor {
    [MenuItem("MyTools/AddBoxCollider")]
    static void AddBoxCollider()
    {
        if (Selection.activeGameObject == null)
        {
#if UNITY_EDITOR
            Debug.Log("<color=red>MyTools/AddBoxCollider:未选中物体</color>");
#endif
            return;
        }
        Transform target = Selection.activeGameObject.transform;
        Vector3 center = Vector3.zero;
        //注意GetComponentsInChildren获取的组件中包括父物体挂载的组件
        var renders = target.GetComponentsInChildren<Renderer>();
        for (int i = 0; i < renders.Length; i++)
        {
            //bounds.center 为渲染边界中心点的世界坐标
            center += renders[i].bounds.center;
        }
        //求平均中心点,类似于(点A+点B)/2 为两点连线的中心点。
        center /= renders.Length;
        //创建一个包围盒,中心为计算出的平均中心点。
        Bounds bounds = new Bounds(center, Vector3.zero);
        for (int i = 0; i < renders.Length; i++)
        {
            //使包围盒包裹子物体的RendererBounds(扩大)
            bounds.Encapsulate(renders[i].bounds);
        }
        BoxCollider boxCollider = target.gameObject.AddComponent<BoxCollider>();
        //bounds.center 为世界坐标,需要将其转换为父物体的本地坐标
        boxCollider.center = target.InverseTransformPoint(bounds.center);
        //父物体缩放之后,boxCollider的size 1 代表的长度也会跟着缩放,1m—>0.1m
        //而Bounds就不同了,它一直是标准的1m,所以需除以父物体缩放。
        boxCollider.size = bounds.size / target.localScale.z;
    }
}

效果

脚本放在Editor文件夹下,选中父物体Cube,在菜单栏中找到MyTools/AddBoxCollider,点击即可添加。
不规则子物体

引用资料

  1. [头图]【Unity】Unity-Japan UnityChanSD角色

我来吐槽

*

*