Unity中使用RaycastNonAlloc设计扇形视野

为了开发类似潜行游戏的角色视野能力,在Unity中找到了一个叫做RaycastNonAlloc的射线,但是网上资料比较少,为了避免自己日后忘记,在这里写出来。下面是整个工具组建,其中的MyLinkList来自一个博主提供的工具类,链接如下:http://www.manew.com/blog-11763-7490.html

public class InputVision : MonoBehaviour
{
    MyLinkList<Collider2D> target;
    RaycastHit2D[] jieguo;
    [SerializeField, TooltipAttribute("射线最远距离")]
    float vision = 1.6f;
    [SerializeField, TooltipAttribute("射线偏移距离")]
    float offset = 1.6f;
    [SerializeField, TooltipAttribute("射线每步的偏移量")]
    float interval = 0.5f;
    [SerializeField, TooltipAttribute("射线数")]
    int rayNumber = 3;
    //控制变量
    bool[] tags;
    int shu;
    bool isnewup = true;
    //循环查找所需的参数
    float offsetrange;
    float currentoffset;

    private void Start()
    {
        target = new MyLinkList<Collider2D>();
        jieguo = new RaycastHit2D[5];
        isnewup = true;
        offsetrange = offset * 2 / rayNumber;
        Debug.Log("offsetrange:" + offsetrange);
        currentoffset = 0;
    }
    private void Update()
    {
        updateVision();
    }

    //获取列表中是否有该角色
    int getCollider2DByname(Collider2D col)
    {
        for (int _i = 0; _i < target.GetLength(); _i++)
        {
            if (target.GetLength() < 1) return -1;
            if (target.GetElem(_i + 1).name.Equals(col.name))
            {
                return _i;
            }
            if (_i == target.GetLength()) return -1;
        }
        return -1;
    }
    //进行一次线性查看
    int lineLook(Vector3 direction) {
        float proportion = (float)(System.Math.Sqrt(vision * vision) / System.Math.Sqrt(direction.x * direction.x + direction.y * direction.y)); ;
        Vector3 directions = transform.TransformPoint(transform.localPosition + direction*proportion);
        Debug.DrawLine(transform.position,
            directions, Color.green);
        return Physics2D.RaycastNonAlloc(transform.position,
            directions-transform.position, jieguo, vision);
    }
    //进行一次视线更新
    void updateVision() {
        if (isnewup) {
            shu = target.GetLength();
            tags = new bool[20];
            isnewup = false;
        }
        for (int _i=0;_i< rayNumber;_i++) {
            int number = lineLook(new Vector3((-offset + _i * offsetrange+currentoffset) / vision, 1));
            if (number > 0)
            {
                for (int _j = 0; _j < number; _j++)
                {
                    int key = getCollider2DByname(jieguo[_j].collider);
                    if (key > -1) tags[key] = true;
                    else
                    {
                        if (!transform.parent.gameObject.name.Equals(jieguo[_j].collider.name)&&
                            !(jieguo[_j].collider.name.Equals("model")&& transform.parent.gameObject.name.Equals(jieguo[_j].collider.transform.parent.name)))
                            target.Append(jieguo[_j].collider);
                    }
                }
            }
        }
        currentoffset += interval;
        if (currentoffset> offsetrange) {
            currentoffset = 0;
            isnewup = true;
            for (int _i = 0; _i < shu; _i++)
            {
                if (!tags[_i]) target.Delete(_i + 1);
            }
            string _s = "目前扫描到: ";
            for (int _i = 0; _i < target.GetLength(); _i++)
            {
                _s += target.GetElem(_i + 1).name + "; ";
            }
            Debug.Log(_s);
        }
    }
}

代码的核心是Physics2D.RaycastNonAlloc这个方法,其他功能选项都是为其服务。

首先为了动态的控制看到的物体,这里用链表而不是数组来存看见的东西,至于性能方面有没有区别这里先不管。然后为了泛用性,我将扇形扫描的相关数值接口都暴露了出来,下面是我在unity中设置的值以及节点树。

Vision上挂脚本,model上放模型,NPC是个空壳,此外所有互动模型都要加上碰撞体才能被发现。

首先在Start里面初始化链表以及RaycastNonAlloc要用的数组和其他相关变量。

然后在Update里面开始调用视线更新。

视线更新根据参数判断这是不是新的一次侦察,如果是就初始化。然后根据射线数分配每条射线的活动范围,即每帧只有指定的射线数在侦察,每帧位移一段距离,在活动完自己的活动范围之后将侦察到的结果综合起来,判断旧的看见物体有哪些还看得见哪些看不见,以此为根据进行链表的删除和增加。

这个侦察部分我借鉴了另外一个博主的思路,博主帖子链接如下:

https://blog.csdn.net/l773575310/article/details/73251093

然后是最关键的线性查看,即给出一个方向,将查看到的结果返回回来。这部分因为Physics2D.RaycastNonAlloc没有画线功能,所以为此还加了Debug.DrawLine用于画线,方便直观查看射线范围。这部分要注意的就是坐标轴的换算,本地坐标和世界坐标是不一样的,此外RaycastNonAlloc是用方向作为射线方向的参照,这个方向是以零点为参照系,如果不注意很容易出问题。

以上就是目前折腾出来的视线范围组件,目前已经调试没有问题,如果有新的bug我会进一步完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值