前言
unity破坏系统插件之前其实已经推荐过了几个,但是他们不具备砍树树的能力(其实是不适合)。
【推荐100个unity插件之13】推荐一款开源的Unity网格破碎插件,实现在Unity中展示可破坏的墙壁的——unity-fracture
你是否一直有个疑问?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插件的砍树功能,他的功能肯定远不止于此,其他功能你可以通过他们提供的实例去查看,当然如果后续我用到其他功能我会再来补充(我相信一定会有机会的,敬请期待)。