欢迎光临散文网 会员登陆 & 注册

Unity小白: 简单地 做伤害判定(重投原创)

2021-10-31 09:43 作者:熔炎矢紫  | 我要投稿

了实现自己想要的功能而在网上找七找八,有时毫无头绪,只能无能狂怒。

—— 相信许多unity的新手都经历过这样的事情。

转入主题:如何使用unity做伤害判定?

做伤害判定有许多种方式,如Trigger、刚体碰撞、RayCast等,不过这次我们要运用BoxCastAll

BoxCastAll的原理很 简 单 :在指定坐标发射一条射线,射线末端是一个方形的检测区域的中心,然后返回射线与检测区域的所有检测信息。 其API如下:

注:检测区域的大小是2倍的输入值,示意图如下


了解了这些,我们就可以开始了。

打开你的unity。



新建两脚本,分别取名为RoleHP、Projectile:

文件及文件夹名称最好取英文,不然控制台会出现乱码



给Projectile添加变量:

    public Transform 子弹根;    

    //在子弹执行隔帧检测修补时,检测将以上一帧投射部坐标即lastPos为起点,终于当前子弹头部坐标

    public Transform 子弹头部;

    public Transform 投射部;

    public float 速度;

    public float 下坠;

    //BoxCastAll检测盒体的大小

    public Vector3 检测范围;

    public LayerMask 检测层级;

    public float 距离;

    List<RoleHP> HitHP;

    Collider HitObj;

    float correct;

    public bool Gizmo;

    Transform gizmoObj;

    Quaternion quat;

    Vector3 lookAt, speed, lastPos,castArea,投射原点;



在update中设置子弹的运动



注:此处的Time.deltaTime解释为 增量时间,其数值为 1/当前的每秒帧数;假设游戏运行时,1秒是N帧,也就是播放了60个画面,执行完,耗时1秒。

x米=(增量时间 * 1秒总帧数)秒 *10米/秒

这样无论帧率是多是少,设置物体1秒移动几米,子弹每秒移动的距离就是几米

若不按照以上的方式进行移动,那么在帧率不同的时候,物体移动的速度可能也会随之变化


既然有帧率,那么物体的移动就是有 间隔 的:

高速运动中的物体帧与帧之间是有明显空隙的


因此,如果物体的移动速度过快,则会出现检测不到子弹正常轨道上的物体的情况;同理,有时候游戏中角色移动过快就会出现无视碰撞地穿墙。




新增 纠正检测 函数,然后在移动代码的后方进行引用:

    private void 纠正检测()

    {

        castArea = 检测范围;

        correct = Vector3.Distance(子弹头部.position, lastPos);

        lookAt = Vector3.Normalize(子弹头部.position - lastPos);

        if (correct > 检测范围.z)

        {  //进行补帧检测

            投射原点 = lastPos;

            castArea.z = correct;

        }

        else

        {  //保持原检测范围不变

            投射原点 = 投射部.position;

            castArea.z = 检测范围.z;

        }

    }

 



继续在Update里添加 检测 的代码:

            quat = Quaternion.LookRotation(lookAt);

            quat.eulerAngles =new Vector3(quat.eulerAngles.x,quat.eulerAngles.y,子弹根.rotation.eulerAngles.z) ;

            Hits = Physics.BoxCastAll(投射原点, castArea / 2, lookAt, quat, castArea.z / 2, 检测层级);

            foreach (var hit in Hits)

            {                              

                                                                                  判断攻击的逻辑靠你们自己写了...............

            }

代码原理如下:

接着:执行运动代码,子弹正式开始移动,然后子弹的位置开始变化。此时,update的代码就运转到 纠正检测函数。虽然子弹的位置产生变化,变量lastPos记录的还是子弹 上 一 帧 的位置,以此就可以“获取上一帧位置”。用vector3.distance获取当前帧与上一帧的距离

(此处“lookAt”=子弹头部.position - lastPos 是为了   获 取  lastPos朝向子弹头部.position的方向)。

代码运转到了BoxCastAll部分,检测投射从lastPos中发出,射线距离等于检测范围的z轴(这样做的原因是为了让方盒检测范围充当主要检测部分,射线暂时不需要),从“上一帧坐标”朝向当前坐标。这里填写的“quat”是一个quaternion(四元数),用来调整检测盒体的旋转方向(重头戏):

BoxCastAll的旋转是需代码更改的,它不会无端端受任何物体的影响。

理想状态下,方盒的起始点是lastPos,终点是投射部.position。因此其quat = LookRotation(lookAt)       .............这就完了吗?

不,如果你想要检测再精密一点,这个盒体的z轴就要与子弹根的z轴一致。因此子弹在围绕Z轴旋转时,检测盒体也会跟着旋转 

代码为  quat.eulerAngles = new Vector3(quat.eulerAngles.x, quat.eulerAngles.y, 子弹根.rotation.eulerAngles.z);


然后检测到的物体只能是指定层级且带有碰撞体组件的。

待获取检测信息后,foreach (var hit in Hits)会从所有检测到的物体中遍历每个检测到的物体。若有物体满足条件: 该物体没有在 List数组“所有击中物”之内,且包含脚本“HP”。则该物体可以被赋予伤害,然后调用其脚本“HP”上的伤害函数。然后添加该物体至 List数组“所有击中物”之内。最后就用lastPos = transform.position; 来更新“上一帧位置”,以便下一帧update的继续调用。


//忘记加子弹延时销毁了,请大家需要的自行加上。


如果你还是听不懂我的十级鬼语的,那么就让可视化的Gizmos来告诉你吧!

(使用时要保证子弹根即其以上的父物体的scale值为1,1,1哦! 不然Gizmos会有误差的!)



在Resources文件夹(无则新建)下新建一个预制体名为Gizmos。

给Gizmos添加一个子物体方盒,其z轴前进0.5个单位

如图,纹理可以自己加


然后添加如此代码


注,这样子 生成的gizmos物体除编辑窗口外是看不见的哦!

作者自鞭,这应该是受到了新建图层的影响





然后别看了!写你的代码去吧!


Unity小白: 简单地 做伤害判定(重投原创)的评论 (共 条)

分享到微博请遵守国家法律