Unity3D让BoxCollider根据子物体生成自适应大小

系列文章目录

unity工具

文章目录

  • 系列文章目录
    • unity工具
  • 👉前言
  • 👉一、编辑器添加
  • 👉二、代码动态添加的方法(第一种)
  • 👉三、代码动态添加的方法(第二种)
  • 👉四、重新设置模型的中心点
  • 👉壁纸分享
  • 👉总结


👉前言

大家好,我是心疼你的一切,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
有时候我们需要用到不规则的物体,或者一大堆物体,又不想每一个物体都加上碰撞盒,所以这时候就需要把这些物体放在空物体里面,在空物体上添加根据子物体的网格生成自适应大小的碰撞盒
以下就是有编辑操作的,也可以代码生成之后操作的,具体使用看自己心情哦


提示:以下是本篇文章正文内容,下面案例可供参考

👉一、编辑器添加

1.一个空物体下面有若干个子物体,想要为空物体添加碰撞盒且碰撞盒还得要包裹所有子物体,手动拖动的话有点费时,费力,费眼,这时候有个工具是最好用的(如下图所示)
在这里插入图片描述
2.选中空物体点击(如下图所示)
在这里插入图片描述
3.点完之后的图(如下图所示)
在这里插入图片描述
点完之后就能看到一个全包围模型的碰撞盒,实现完成
实现如上效果需要一个编辑器脚本,脚本放在Editor文件夹下面
编辑器脚本如下

using UnityEngine;
using UnityEditor;
/// <summary>
/// 选择一个物体给当前物体添加自适应碰撞盒 编辑器脚本
/// </summary>
public class BoundsTool
{
    [MenuItem("Tools/添加自适应碰撞盒")]
    private static void AutoBoxCollider()
    {
        //如果未选中任何物体 返回
        GameObject gameObject = Selection.activeGameObject;
        if (gameObject == null) return;
        //计算中心点
        Vector3 center = Vector3.zero;
        var renders = gameObject.GetComponentsInChildren<Renderer>();
        for (int i = 0; i < renders.Length; i++)
        {
            center += renders[i].bounds.center;
        }
        center /= renders.Length;
        //创建边界盒
        Bounds bounds = new Bounds(center, Vector3.zero);
        foreach (var render in renders)
        {
            bounds.Encapsulate(render.bounds);
        }
        //先判断当前是否有碰撞器 进行销毁
        var currentCollider = gameObject.GetComponent<Collider>();
        if (currentCollider != null) Object.DestroyImmediate(currentCollider);
        //添加BoxCollider 设置中心点及大小
        var boxCollider = gameObject.AddComponent<BoxCollider>();
        boxCollider.center = bounds.center - gameObject.transform.position;
        boxCollider.size = bounds.size;
    }
}

👉二、代码动态添加的方法(第一种)

1.动态生成物体的时候,也是可以添加的
代码动态添加的第一种方法

/// <summary>
    /// 自动调节碰撞盒的大小
    /// </summary>
    /// <param name="obj_"></param>
    public void AutoBoxCollider(GameObject obj_)
    {
        //如果未选中任何物体 返回
        GameObject gameObject = obj_;
        if (gameObject == null) return;
        //计算中心点
        Vector3 center = Vector3.zero;
        var renders = gameObject.GetComponentsInChildren<Renderer>();
        for (int i = 0; i < renders.Length; i++)
        {
            center += renders[i].bounds.center;
        }
        center /= renders.Length;
        //创建边界盒
        Bounds bounds = new Bounds(center, Vector3.zero);
        foreach (var render in renders)
        {
            bounds.Encapsulate(render.bounds);
        }
        //先判断当前是否有碰撞器 进行销毁
        var currentCollider = gameObject.GetComponent<Collider>();
        if (currentCollider != null) UnityEngine.Object.DestroyImmediate(currentCollider);
        //添加BoxCollider 设置中心点及大小
        var boxCollider = gameObject.AddComponent<BoxCollider>();
        if (!gameObject.GetComponent<Highlighter>())
        {
            gameObject.AddComponent<Highlighter>();          
        }    
        boxCollider.center = bounds.center - gameObject.transform.position;
        boxCollider.size = bounds.size;
    }

结果就自行测试吧,我就不贴图片了

👉三、代码动态添加的方法(第二种)

调用方法如下

MeshTool.SpawnCollider(parents); //传一个父物体即可

代码如下

using UnityEngine;

public class MeshTool
{

    public static Bounds SpawnCollider(Transform target)
    {
        Vector3 pMax = Vector3.zero;
        Vector3 pMin = Vector3.zero;
        Vector3 center = Vector3.zero;

        Vector3 oldPos = target.transform.position;
        Quaternion oldQua = target.transform.rotation;
        Vector3 oldScale = target.transform.localScale;

        target.transform.position = Vector3.zero;
        target.transform.rotation = Quaternion.identity;
        target.transform.localScale = Vector3.one;

        Bounds bounds = CalcBounds(target, ref pMax, ref pMin, ref center);

        BoxCollider collider = target.GetComponent<BoxCollider>();
        if (collider == null)
        {
            collider = target.gameObject.AddComponent<BoxCollider>();
        }
        collider.center = bounds.center;
        collider.size = bounds.size;

        target.transform.position = oldPos;
        target.transform.rotation = oldQua;
        target.transform.localScale = oldScale;

        return bounds;
    }

    private static Bounds CalcBounds(Transform obj, ref Vector3 pMax, ref Vector3 pMin, ref Vector3 center)
    {
        Renderer meshRenderer = obj.GetComponent<Renderer>();

        if (meshRenderer != null)
        {
            Bounds b = meshRenderer.bounds;
            pMax = b.max;
            pMin = b.min;
            center = b.center;
        }

        RecursivelyCalcBounds(obj.transform, ref pMax, ref pMin);

        CalculateCenter(pMax, pMin, out center, ref pMax, ref pMin);

        Vector3 size = new Vector3(pMax.x - pMin.x, pMax.y - pMin.y, pMax.z - pMin.z);
        Bounds bound = new Bounds(center, size);

        return bound;
    }

    private static void CalculateCenter(Vector3 max, Vector3 min, out Vector3 center, ref Vector3 pMax, ref Vector3 pMin)
    {
        float xc = (pMax.x + pMin.x) / 2f;
        float yc = (pMax.y + pMin.y) / 2f;
        float zc = (pMax.z + pMin.z) / 2f;

        center = new Vector3(xc, yc, zc);
    }

    private static void RecursivelyCalcBounds(Transform obj, ref Vector3 pMax, ref Vector3 pMin)
    {
        if (obj.transform.childCount <= 0)
        {
            return;
        }

        foreach (Transform item in obj)
        {
            Renderer m = item.GetComponent<Renderer>();

            if (m != null)
            {
                Bounds b = m.bounds;
                if (pMax.Equals(Vector3.zero) && pMin.Equals(Vector3.zero))
                {
                    pMax = b.max;
                    pMin = b.min;
                }

                if (b.max.x > pMax.x)
                {
                    pMax.x = b.max.x;
                }

                if (b.max.y > pMax.y)
                {
                    pMax.y = b.max.y;
                }
                if (b.max.z > pMax.z)
                {
                    pMax.z = b.max.z;
                }
                if (b.min.x < pMin.x)
                {
                    pMin.x = b.min.x;
                }

                if (b.min.y < pMin.y)
                {
                    pMin.y = b.min.y;
                }
                if (b.min.z < pMin.z)
                {
                    pMin.z = b.min.z;
                }
            }
            RecursivelyCalcBounds(item, ref pMax, ref pMin);
        }
    }

}

👉四、重新设置模型的中心点

有时候模型的轴向不准确,就需要重新设置模型的轴向了,
有时候有多个子物体的时候,想要把轴向设置到模型的中心点,这个时候就可以用了,反正只要能代码添加的,绝对不会手动添加的
能懒就懒,能不动就不动,哈哈哈…

代码方法如下

List<GameObject> ObjZ = new List<GameObject>();
    Vector3 posZ = Vector3.zero;
    /// <summary>
    /// 设置模型的中心点,方便做模型的移动
    /// </summary>
    /// <param name="_trans"></param>
    public void SetModelPos(Transform _trans)
    {
        yield return new WaitForSeconds(0.2f);
        posZ = Vector3.zero;
        ObjZ.Clear();
        for (int i = 0; i < _trans.childCount; i++)
        {
            posZ += (_trans.GetChild(i).GetComponent<MeshCollider>().bounds.center);
            ObjZ.Add(_trans.GetChild(i).gameObject);
        }
        posZ /= _trans.childCount;
        for (int i = 0; i < ObjZ.Count; i++)
        {
            ObjZ[i].transform.parent = null;
        }
        _trans.position = posZ;
        for (int i = 0; i < ObjZ.Count; i++)
        {
            ObjZ[i].transform.parent = _trans;
        }     
    }

如果有需要会继续添加好用的小工具哦,谢谢

👉壁纸分享

请添加图片描述

👉总结

以上就是讲了如何设置碰撞盒的自适应大小,如能帮助到你,就帮忙点个三连吧,谢谢
不定时更新Unity开发技巧,觉得有用记得一键三连哦。么么哒
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/654318.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式事务解决方案(最终一致性【可靠消息解决方案】)

可靠消息最终一致性解决方案 可靠消息最终一致性分布式事务解决方案指的是事务的发起方执行完本地事务之后&#xff0c;发出一条消息&#xff0c;事务的参与方&#xff0c;也就是消息的消费者一定能够接收到这条消息并且处理完成&#xff0c;这个方案强调的是只要事务发起方将消…

03 FreeRTOS 同步互斥与通信

1、同步与互斥 一句话理解同步与互斥&#xff1a;我等你用完厕所&#xff0c;我再用厕所。 什么叫同步&#xff1f;就是&#xff1a;哎哎哎&#xff0c;我正在用厕所&#xff0c;你等会。 什么叫互斥&#xff1f;就是&#xff1a;哎哎哎&#xff0c;我正在用厕所&#xff0c;你…

太阳能语音监控杆(球机LED款)有什么用

传统监控设备依赖电力支持&#xff0c;在偏远地区和没有网络地区难以发挥其作用&#xff0c;而鼎跃安全的太阳能语音监控杆&#xff08;球机LED款&#xff09;在传统监控基础上&#xff0c;进行了全面优化&#xff0c;解决了无电无网区域使用受限的问题。 太阳能语音监控杆&am…

关于已配好java环境但双击无法打开jar包的解决方案

如果你已经装好了 java 环境直接跳到最后看解决方法即可 先说一下你安装的 java 环境&#xff0c;如果完全是默认选项安装&#xff0c;则会安装 jdk 和 jre&#xff0c;并且在安装 jre 时还需要安装目录下为空&#xff0c;其实 jre 的安装是多余的&#xff0c;因为安装的 jdk 里…

无人机侦察:雷达系统概述

一、雷达基本原理 无人机侦察中的雷达系统主要基于无线电波的传播和反射原理。雷达发射机产生特定频率的电磁波&#xff0c;并通过天线以定向波束形式向空间发射。当这些电磁波遇到目标时&#xff0c;部分能量会被反射回来&#xff0c;被雷达接收机捕获。通过测量发射和接收电…

VUE3学习第一篇:启动ruoyi

1、找到ruoyi的vue3版本 然后下载代码到本地&#xff0c; 我刚开始用的nodejs14报错&#xff0c; 后面换成nodejs16&#xff0c;启动前端成功了。 页面如下图所示

记一次Chanakya靶机的渗透测试

Chanakya靶机渗透测试 首先通过主机发现发现到靶机的IP地址为:172.16.10.141 然后使用nmap工具对其进行扫描:nmap -sC -sV -sS -p- 172.16.10.141 发现目标靶机开启了80,22,21等多个端口&#xff0c; 访问80端口,发现是一个普通的页面,点击进入多个界面也没有其他有用的信息,然…

ArcgisPro3.1.5安装手册

ArcgisPro3.1.5安装手册 一、目录介绍: 二、安装教程&#xff1a; (1)安装顺序&#xff1a;最先安装运行环境&#xff08;runtime6.0.5&#xff09;,接着安装install里面的文件&#xff0c;最后复制path里面的文件替换到软件bin文件夹下即可。 (2)具体安装步骤&#xff…

图算法新书发布会圆满成功,大咖现场都讲了啥?

5月24日&#xff0c;嬴图与机工社携手举办的“《图算法&#xff1a;行业应用与实践》新书发布会”圆满成功。 现场直播在线观众达4000人/次左右&#xff0c;点赞数量超7000&#xff0c;直至发布会尾声&#xff0c;观看人数仍在持续增长。 通过观众们的反馈&#xff0c;我们也对…

JavaWeb_SpringBootWeb

先通过一个小练习简单了解以下SpringBootWeb。 小练习&#xff1a; 需求&#xff1a;使用SpringBoot开发一个Web应用&#xff0c;浏览器发起请求/hello后&#xff0c;给浏览器返回字符串"Hello World~"。 步骤&#xff1a; 1.创建SpringBoot项目&#xff0c;勾选We…

切勿安装这五款流氓软件,你中招了没

流氓软件&#xff0c;又称为恶意软件&#xff0c;是一类设计用来损害用户设备、窃取信息或干扰正常使用的程序。以下是五款臭名昭著的流氓软件介绍&#xff0c;提醒切勿安装&#xff0c;只能说一个比一个毒&#xff0c;你中招了没 可以去去虚拟机试试谁的毒更强一些&#xff0…

杨若歆发布最新单曲《迷雾之谜》从啦啦女神到音乐新星的华丽转身

5月28日&#xff0c;台北——杨若歆&#xff0c;这位被粉丝封为"啦啦女神"的多才多艺艺人&#xff0c;近日推出了她的最新单曲《迷雾之谜》&#xff0c;这首歌曲以其空灵的旋律和杨若歆独特的高音&#xff0c;迅速在歌迷中引起了热烈的反响。 杨若歆&#xff0c;身高…

精酿啤酒:品质与口感在消费者选择中的权重分析

在啤酒市场中&#xff0c;消费者选择的影响因素众多&#xff0c;其中品质与口感是两个核心要素。对于Fendi club啤酒而言&#xff0c;品质与口感的权重分析在消费者选择中显得尤为重要。 品质是消费者选择啤酒的首要因素。随着消费者对啤酒认知的提高&#xff0c;他们对品质的…

上海汇正财经官网怎么样?客户好评如潮,口碑赞誉之声不绝于耳

在财经服务领域&#xff0c;客户评价是衡量一家企业信誉和服务质量的重要标准。上海汇正财经作为业内知名的财经服务平台&#xff0c;以其优质的服务赢得了广大客户的认可和好评。大量正面用户评价和成功服务的案例&#xff0c;充分证明了上海汇正财经是一个值得信赖的正规企业…

解决ssh报错,.ssh/id_rsa: No such file or directory Permission denied (publickey)

拉取依赖或者代码时说没有权限 首先我们可以看到的是这个报错但是我们的远程确实配置ssh密钥 首先我们可以看到的是这个报错 但是我们的远程确实配置ssh密钥 我们可以在我们项目路径下添加一下我们的私钥如&#xff1a; 首先确定我们ssh是正常启动的eval $(ssh-agent)我们可以…

TI_DSP_F2808学习笔记3: ePWM

共有6组ePWM&#xff0c;每一组 ePWM 模块都包含以下 7 个模块&#xff1a;时基模块 TB、计数比较模块 CC、动作模块 AQ、死区产生模块 DB、PWM 斩波模块 PC、错误联防模块 TZ、时间触发模块 ET。 时基模块 TB 确定PWM的周期和相位。 1&#xff09;PWM 时基计数器&#xff…

Spring Boot集成Picocli快速入门Demo

1.什么是Picocli&#xff1f; Picocli是一个单文件命令行解析框架&#xff0c;它允许您创建命令行应用而几乎不需要代码。使用 Option 或 Parameters 在您的应用中注释字段&#xff0c;Picocli将分别使用命令行选项和位置参数填充这些字段。使用Picocli来编写一个功能强大的命…

段位在于面对人性之恶,一笑而过

这个小哥哥不知道是哪里不对劲了&#xff0c;突然给我留言说我在骗流量&#xff0c;骗关注。公众号是我的&#xff0c;文章是我写的&#xff0c;主要分享的就是我创业的一些接单案例&#xff0c;因为之前收到很多无效的留言&#xff0c;寻求合作就几个字我不想接收无效信息&…

体验SmartEDA的高效与便捷,电子设计从未如此简单

SmartEDA&#xff1a;革新电子设计&#xff0c;让高效与便捷触手可及 在快节奏的现代生活中&#xff0c;科技日新月异&#xff0c;各行各业都在寻求更高效、更便捷的解决方案。对于电子设计行业而言&#xff0c;SmartEDA的出现&#xff0c;无疑是一场革命性的变革。它以其高效…