Unity子弹反弹效果实现

依旧是用那万年不变的场景和人物......

先来看看大概的效果: 

想要实现子弹反弹其实还是相当容易的,在2D界面控制子弹的旋转只有z轴,而如果想要在3D中实现则要对三个轴进行修改,本次是针对2D的效果实现,可能之后会在此页增加3D反弹效果。

当子弹在物体发生碰撞时,要使得子弹沿着想要的方向上反弹需要获得子弹和物体在接触面的法向量,然后子弹的运动方向与法向量进行轴对称,然后将返回给过修改为子弹的运动方向即可,进行反射的函数为Vector2.Reflect(),接收的参数第一个是入射向量,一个是法线向量,由于我这里使用的子弹运动方式是transform.Translate,使得我的子弹旋转和z轴有关,因此必须将z轴转换为2维向量,法线向量如何获得呢?在碰撞函数的碰撞体有collision.GetContact(int index).normal方法,返回第index个碰撞点上的法线向量,index默认一般是0,最后部分是代码展现如何将角度制转换为二维向量。

    private void OnCollisionEnter2D(Collision2D collision)
    {
        //将角度制转换为弧度制   
        float Angle_Z = transform.rotation.eulerAngles.z * Mathf.Deg2Rad;

        //拿到旋转向量,以便之后进行反射计算
        Vector2 Direction = new Vector2(Mathf.Cos(Angle_Z), Mathf.Sin(Angle_Z));

        //做反射运算,得到反射后的选择向量
        Vector2 Out_Direction = Vector2.Reflect(Direction, collision.GetContact(0).normal);

        //向旋转向量转为弧度制
        Angle_Z = Mathf.Atan2(Out_Direction.y, Out_Direction.x);

        //重新转换回角度制,并修改子弹角度,达成反射效果
        transform.rotation = Quaternion.Euler(0, 0, Angle_Z * Mathf.Rad2Deg);
    }

不懂每一行代码作用的可以看这里详细介绍,Angle_Z是为了将2D界面的物体的旋转向量转化为float值表示角度,但是必须要将其乘以Mathf.Deg2Rad转化为弧度制,这个的原因是因为Z轴的值直接进行三角函数计算得到向量不是正确的方向向量,因为角度计算的标准是弧度值,你可以打开手机的计算器试一试sin30是否是0.5,然后你就会发现得到是一个很小的负数,而sin30π/180才是0.5,这样你就能理解为啥要转换为弧度制。Direction则是利用三角函数计算得到方向向量,最后利用Reflect计算反射向量的方法得到反射向量,然后转换回角度制即可。

另外一提,如果你使用的是类似控制玩家移动的方式如输入轴,一个X轴向一个Y轴向或者类似的方法,可以省去转换的麻烦,当然我使用这种移动方式是为了容易实现子弹曲线转弯追踪,换成这种方式控制子弹追踪可就难多了(笑)。

更新另一种情况的碰撞反弹,以上的使用条件仅限于碰撞体要有没有勾选了触发器选项的碰撞体,不然在OnTrggier方法中返回的collision碰撞信息无法使用GetContact方法获取法线向量。如果需要获得不使用碰撞情况前提下的法线向量,则需要借助射线检测,而射线检测返回的碰撞体信息中就有normal表示射线检测得到的法线向量。

代码展示以下,其实基本和上一种使用方法是一样的:

//大部分的逻辑是一样的,但是少部分我还是要提一下
    float Angle_Z = transform.rotation.eulerAngles.z * Mathf.Deg2Rad;

    Vector2 Direction = new(Mathf.Cos(Angle_Z), Mathf.Sin(Angle_Z));

//layer是要检测的图层,为LayerMask类型,Distance表示检测的距离,为float类型
//利用射线检测检拿到物理信息
    RaycastHit2D hit = Physics2D.Raycast(transform.position, Direction, Distance, layer);

    Direction = Vector2.Reflect(Direction, hit.normal);

    Angle_Z = Mathf.Atan2(Direction.y, Direction.x);

    transform.rotation = Quaternion.Euler(0, 0, Angle_Z * Mathf.Rad2Deg);

另外提醒,使用射线检测时获取碰撞的位置要用point而不是coilder,因为你碰撞的位置绝对不会使物体的中心,而且这个点的位置很可能会使在碰撞体内部(就算只有0.001左右的差距)所以更多情况下用的不是RaycastHit2D的方法二用的是另一种方式拿到整个射线区域的物体,RaycastHit2D[] hits = Physics2D.RaycastAll(transform.position, Direction, Distance, layer);。

图示效果:

猜你喜欢

转载自blog.csdn.net/WEIWEI6661012/article/details/130096124