炸弹的动画需要从引爆一段时间之后切换到另外一个动画即爆炸,那么首先需要一个最基本的参数anim用于控制Animator组件
private Animator anim;关于时间,需要记录炸弹引爆的开始时间,使用游戏时钟,还需要记录引爆的时长,也就是等待爆炸的时间。他们都是float型的变量,开始时间+等待时间就是爆炸动画效果播放的时间。
private float startTime; private float waitTime;这里的主要指的是检测范围,炸弹爆炸的时候有一定的范围影响,需要设置炸弹的范围。其实炸弹爆炸后游戏物体也要收到物理影响,还需要知道受爆炸影响的layer层级。
public float radius; // 范围半径 public LayerMask targetLayer; // 受爆炸影响的层级需要设置一个作用力,当爆炸范围检测到受爆炸影响的物体时,需要给他们添加上这个力, 让他们在爆炸的瞬间受力的影响弹出去。
public float bombForce;unity系统提供了OnDrawGizmos函数用来可视化检测范围,在这里可视化一个球形的范围,传入检测的中心点就是当前炸弹的位置,检测范围就是前面定义的radius变量。
// 检测范围可视化 public void OnDrawGizmos() { // 中心点/检测范围 Gizmos.DrawWireSphere(transform.position, radius); }在脚本中添加了2.1的可视化代码之后,在unity中修改参数可以看到一圈白色的线,就是炸弹爆炸时的检测范围。 但是这个检测范围并不是随便设置的,应该是播放爆炸动画时的爆炸范围,需要根据爆炸特效的最大范围来确定,最后我把radius的取值确定在1.35~1.4之间。 检测的图层LayerMask是包括炸弹周围的环境,游戏Player和敌人,还有炸弹本身。那么在设置targetLayer时需要把Enviroment,NPC,Bomb都勾选。
主要使用的方法是让炸弹爆炸的时候检测周围所有的碰撞体,然后为这些碰撞体施加一个作用力。使用物理检测的方法Physics2D来进行检测。 在文章前面做了一个圆形的检测范围,使用Physics2D.OverlapCircleAll方法可以获得该范围中所有的碰撞体,也就知道了有哪些物体是可以施加作用力的。该方法返回的是一个数组,此外还需要定义一个临时数组来存放检测到的碰撞体。
⚠️在进行检测的时候,炸弹本身也是会被检测进去的,但是爆炸影响的物体中不包含炸弹本身,所以在每次检测之前需要临时将炸弹的碰撞体脱离。但是物体的碰撞体一旦消失之后,该物体就会自然的下落脱离地面。所以还需要添加刚体组件把重力设置为0
private Collider2D coll; // 用于脱离炸弹碰撞体 private Rigidbody2D rb; // 用于设置炸弹重力防止掉出屏幕Physics2D.OverlapCircleAll方法需要传入三个参数(检测中心点,检测范围,图层)
public void Explosion() { // 检测范围之前脱离炸弹的碰撞体 coll.enabled = false; // 重力设置为0防止掉落出地面 rb.gravityScale = 0; // 坐标,检测范围,图层 Collider2D[] aroundObjects = Physics2D.OverlapCircleAll(transform.position, radius, targetLayer); }物理检测的前提条件是物体需要有刚体和碰撞体,可以循环数组中所有的碰撞体获得他们的刚体,并为这个刚体施加弹出去的作用力。 在这个循环中,每一个检测的物体需要与当前的炸弹的坐标进行对比,得到物体在炸弹的某一方向坐标pos(当前炸弹的位置-物体的位置),上边或者下边或者左边或者右边等。每一个检测到的物体一定有刚体组件,使用组件的AddForce()方法为它添加一个反方向的作用力达到物体被弹开的效果。
AddForce需要传入的参数( -pos炸弹威力+向上方向炸弹威力,冲击力ForceMode2D.Impulse)
foreach (var i in aroundObjects) { // 判断物体的方向 Vector3 pos = transform.position - i.transform.position; i.GetComponent<Rigidbody2D>().AddForce((-pos + Vector3.up) * bombForce, ForceMode2D.Impulse); }上面写的爆炸方法是一个爆炸瞬间的事件方法,需要返回Unity找到bomb_explosion动画,为动画的第一帧添加这个方法。 同时炸弹爆炸之后应该消失,还应该写一个销毁的方法。
// 炸弹消失的事件方法 public void Destroy() { Destroy(gameObject); }在添加了事件方法以后,动画效果还需要最后一步,进行炸弹引爆到爆炸的动画切换。此前炸弹的动画默认是引爆动画的,不进行切换之前会一直处于引爆状态。 开始时间获取当前的游戏时钟。 在Start()方法里添加startTime = Time.time; 在Update里利用开始事件和等待事件进行检测是否已经满足固定的炸弹引爆cd,当满足条件后,进行动画的切换。
void Update() { // 如果当前的游戏时间大于开始时间+等待时间 if (Time.time > startTime + waitTime) anim.Play("bomb_explosion"); }在unity中为等待时间和作用力赋值后启动游戏进行测试。我在这里设置的等待引爆时间waitTime = 2,爆炸力boomForce = 6。 爆炸效果测试如下图:
当我加大boomForce修改为8的时候再次测试发现了一个bug。 如上图所示,凳子爆炸后弹出被卡进了墙体,这需要修改椅子的刚体组件中的Collision Detection 参数修改为Continuous防止物体对象穿过所有静态碰撞体,此外场景中的所有物体都需要需改这一参数。
