最终效果

在这里插入图片描述

前言

unity破坏系统插件之前其实已经推荐过了几个,但是他们不具备砍树树的能力(其实是不适合)。
【推荐100个unity插件之13】推荐一款开源的Unity网格破碎插件,实现在Unity中展示可破坏的墙壁的——unity-fracture
【推荐100个unity插件之4】OpenFracture插件实现unity3d物体破裂和切割
【推荐100个unity插件之3】切割unity3d物体插件——Ezy-Slice的使用

你是否一直有个疑问?unity地形刷的树要如何砍伐破坏呢?

今天推荐的这个插件DestroyIt - Destruction System,现在版本 1.10 具有创建可破坏地形树木的能力了!使用 Unity 的地形系统来放置树木,然后再用 DestroyIt 来让它们变得完全可破坏。

DestroyIt 是一款高度优化的破坏系统,它为你的游戏提供了伤害处理、修复和破坏对象等选项。

利用标准着色器和可自定义的伤害纹理,对象可以显示可见的渐进伤害(甚至可以修复)。你也可以以任何伤害阶段下播放伤害特效,举个例子,一个引擎会在半血量状态下开始熏烟,而在四分之一血的状况下会着火。

从播放粒子特效到用预制件替换对象,破坏可以是简单的或逼真的。你甚至可以将这两个方法结合在一起来获得更奢侈的效果。

DestroyIt 是设计来高效地处理大规模毁灭的。该框架提供了用于限制粒子特效和碎片的工具,因为许多对象会一次性被摧毁,或者会离镜头更远。对象池化也用了来优化内存分配。

下载

https://assetstore.unity.com/packages/tools/physics/destroyit-destruction-system-18811#description
在这里插入图片描述

可破坏的地形树

新建地形

关闭树碰撞器
在这里插入图片描述

破坏的树预制体

随便导入一个树模型
在这里插入图片描述

只留下树干添加碰撞体,最好是使用胶囊体的碰撞体,因为底下是圆的,这样能让树很好的倒下
调节树的碰撞体不要深入地下,不然树可能会被弹飞
在这里插入图片描述
树添加刚体配置,冻结刚体Y轴,防止他倒地后在地面滚动
在这里插入图片描述
制成破坏预制件
在这里插入图片描述

制作可破坏树的原始版本

重新拖入一个新的树模型
给树添加Destructible组件,生命值设置为200
在这里插入图片描述

绑定被破坏的预制体,就是我们前面的配置好的
在这里插入图片描述
可以在树干上添加命中效果,添加Hit Effects脚本,选择命中特效WoodBulletHit
在这里插入图片描述
保存为预制件,为了做区分可以改个名字
在这里插入图片描述

在地形上添加树

在这里插入图片描述
在这里插入图片描述

快速添加第一人称控制器

在这里插入图片描述

设置-可破坏的树

在这里插入图片描述
会弹出提示
在这里插入图片描述
翻译一下就是:

关于可破坏树的说明

注意:为了使用可破坏的树木,你需要在地形上取消启用树碰撞器

一旦你将树添加到地形中,点击TreeManager上的“Update
Trees”按钮,DestroyIt将创建带有碰撞器的游戏对象,并将它们放置在地形树实例上,这样它们就可以被摧毁了。

取消地形启用树碰撞器我们已经设置好了,接下来需要在DestroyIt找到TreeManager组件点击Update Trees按钮
在这里插入图片描述

运行效果

ps:这里破坏树的预制体和原树的预制体之间碰撞器配置不太好,如果碰撞器的位置一致且不会在地下,那么效果肯定会更好,实现真正意义上的无缝衔接
在这里插入图片描述

攻击具体是如何实现的呢(补充)

如果你想自己创建人物控制器,可能就需要用到,当然通常我们不会用它自带的人物控制脚本

其实就是在人物身上挂载个攻击区域检测脚本
在这里插入图片描述
点击攻击时调用里面的方法(当然还包括修复的方法),下面是我加了中文注释的脚本,方便大家理解

using System.Collections.Generic;
using UnityEngine;

namespace DestroyIt
{
    public class MeleeArea : MonoBehaviour
    {
        public int damageAmount = 30; // 伤害值
        public int repairAmount = 20; // 修复值
        public float meleeRadius = 1.3f; // 攻击半径
        public float additionalForceAmount = 150f; // 额外的力量大小
        public float additionalForceRadius = 2f; // 额外的力量作用范围半径
        public ParticleSystem repairEffect; // 修复特效

        // 当进行近战伤害时调用
        public void OnMeleeDamage()
        {
            Collider[] objectsInRange = Physics.OverlapSphere(transform.position, meleeRadius);
            List<Destructible> damagedObjects = new List<Destructible>(); // 记录已经受到伤害的物体,以免对每个碰撞体重复造成伤害
            bool hasPlayedHitEffect = false; // 是否已经播放过攻击特效

            foreach (Collider col in objectsInRange)
            {
                // 忽略地形碰撞体
                if (col is TerrainCollider) continue;

                // 忽略触发器碰撞体
                if (col.isTrigger) continue;

                // 忽略玩家的角色控制器(即避免攻击到自己)
                if (col is CharacterController && col.tag == "Player") continue;

                if (!hasPlayedHitEffect) // 每次近战攻击只播放一次攻击特效
                {
                    // 播放攻击特效
                    HitEffects hitEffects = col.gameObject.GetComponentInParent<HitEffects>();
                    if (hitEffects != null && hitEffects.effects.Count > 0)
                        hitEffects.PlayEffect(HitBy.Axe, transform.position, transform.forward * -1);

                    hasPlayedHitEffect = true;
                }

                // 对受到伤害的刚体施加冲击力
                Rigidbody rbody = col.attachedRigidbody;
                if (rbody != null)
                    rbody.AddForceAtPosition(transform.forward * 3f, transform.position, ForceMode.Impulse);

                // 如果碰撞到的物体是可摧毁的,则造成伤害
                // 只对激活且启用的父对象中的 Destructible 脚本进行操作
                // 特别说明:默认情况下,地形树上的 Destructible 脚本是关闭的(以节省资源),所以我们将对其进行特殊处理,并仍然处理碰撞
                Destructible[] destObjs = col.gameObject.GetComponentsInParent<Destructible>(false);
                foreach (Destructible destObj in destObjs)
                {
                    if (damagedObjects.Contains(destObj)) continue;
                    if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;

                    damagedObjects.Add(destObj);
                    ImpactDamage meleeImpact = new ImpactDamage()
                    {
                        DamageAmount = damageAmount,
                        AdditionalForce = additionalForceAmount,
                        AdditionalForcePosition = transform.position,
                        AdditionalForceRadius = additionalForceRadius
                    };
                    destObj.ApplyDamage(meleeImpact);
                }
            }
        }

        // 当进行近战修复时调用
        private void OnMeleeRepair()
        {
            Collider[] objectsInRange = Physics.OverlapSphere(transform.position, meleeRadius);
            List<Destructible> repairedObjects = new List<Destructible>(); // 记录已经修复过的物体,以免重复修复
            bool hasPlayedRepairEffect = false; // 是否已经播放过修复特效

            // 在范围内修复物体
            foreach (Collider col in objectsInRange)
            {
                // 忽略地形碰撞体
                if (col is TerrainCollider) continue;

                // 忽略触发器碰撞体
                if (col.isTrigger) continue;

                // 忽略玩家的角色控制器(即避免修复自己)
                if (col is CharacterController && col.tag == "Player") continue;

                // 如果是可摧毁的物体,则进行修复
                Destructible destObj = col.gameObject.GetComponentInParent<Destructible>();
                if (destObj != null &&
                    !repairedObjects.Contains(destObj) &&
                    destObj.CurrentHitPoints < destObj.TotalHitPoints &&
                    destObj.canBeRepaired)
                {
                    repairedObjects.Add(destObj);
                    destObj.RepairDamage(repairAmount);
                    // 播放修复粒子特效
                    if (repairEffect != null && !hasPlayedRepairEffect)
                    {
                        repairEffect.GetComponent<ParticleSystem>().Clear(true);
                        repairEffect.Play(true);
                        hasPlayedRepairEffect = true;
                    }
                }
            }
        }

        // 在编辑器中绘制可视化调试辅助线
        private void OnDrawGizmos()
        {
            Gizmos.DrawWireSphere(transform.position, meleeRadius);
        }
    }
}

一些其他问题

这里收集了一些其他人的问题,和作者的回答

问题1

在这里插入图片描述
回答:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题2

它是否只在平坦的地形上工作,并且是否使用音频源来表示声距。
在这里插入图片描述
回答
在这里插入图片描述

待续

这里我只研究了DestroyIt插件的砍树功能,他的功能肯定远不止于此,其他功能你可以通过他们提供的实例去查看,当然如果后续我用到其他功能我会再来补充(我相信一定会有机会的,敬请期待)。

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐