【推荐100个unity插件之17】具有可破坏/砍倒unity地形树木能力的破坏系统,实现unity砍树效果 —— DestroyIt - Destruction System

简介: 【推荐100个unity插件之17】具有可破坏/砍倒unity地形树木能力的破坏系统,实现unity砍树效果 —— DestroyIt - Destruction System

前言

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:这里破坏树的预制体和原树的预制体之间碰撞器配置不太好,如果碰撞器的位置一致且不会在地下,那么效果肯定会更好,实现真正意义上的无缝衔接

image.png

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

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

其实就是在人物身上挂载个攻击区域检测脚本

点击攻击时调用里面的方法(当然还包括修复的方法),下面是我加了中文注释的脚本,方便大家理解

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插件的砍树功能,他的功能肯定远不止于此,其他功能你可以通过他们提供的实例去查看,当然如果后续我用到其他功能我会再来补充(我相信一定会有机会的,敬请期待)。

目录
相关文章
|
2天前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
11 2
|
2天前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
7 0
|
2天前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
5 0
|
2天前
|
图形学
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
5 0
|
2天前
|
存储 JSON 图形学
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
6 0
|
2天前
|
存储 图形学
【unity小技巧】unity事件系统创建通用的对象交互的功能
【unity小技巧】unity事件系统创建通用的对象交互的功能
6 0
|
2天前
|
数据可视化 大数据 API
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
5 0
|
2天前
|
自然语言处理 搜索推荐 API
【推荐100个unity插件之21】unity实现多语言切换功能——Localization插件的使用
【推荐100个unity插件之21】unity实现多语言切换功能——Localization插件的使用
6 0
|
2天前
|
JSON 开发框架 API
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
6 0
|
2天前
|
图形学
【推荐100个unity插件之19】武器拖尾特效插件——Pocket RPG Weapon Trails(2d 3d通用)
【推荐100个unity插件之19】武器拖尾特效插件——Pocket RPG Weapon Trails(2d 3d通用)
7 0