Unity 的射线检测

这篇具有很好参考价值的文章主要介绍了Unity 的射线检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Unity版本2020.3.32f1c1

目录

Ray

RaycastHit

Physics.Raycast()

RaycastHit[]

  Layer

应用

1.对Bad层级的物体进行着色

2.从相机发射射线与地面进行射线交互

3.运动的物体在场景中进行避障

总结

参考资料


Ray

原理是发射一条射线,传入起始点和起始方向当做射线的起点和方向。

 Ray ray = new Ray(transform.position, transform.forward);

在OnDrawGizmos()函数中画出来

  private void OnDrawGizmos()
    {
        Ray ray = new Ray(transform.position, transform.forward);
        Gizmos.color = Color.blue;

        Gizmos.DrawRay(ray);

    }    

RaycastHit

之后我们在场景中添加两个包含Collider的物体,我希望其中一个物体发出射线可以感知到另一个物体。Unity中通过RaycastHit结构体来存储射线的交互信息,结构如下所示:

unity 射线检测,unity,游戏引擎,游戏程序

Physics.Raycast()

Physics.Raycast()返回true,可以用它来表示射线是否与游戏对象发生交互.Physics.Raycast一共有16个重载方法,可以按需选择。

public static bool Raycast(Ray ray, out RaycastHit hitInfo, [Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction); 

上面的参数分别是射线,射线交互结构体,检测的最大距离(默认最大),层模板(默认所有),查询触发器交互(默认全局)。

如果设置了LayerMask参数的话,射线只会和游戏对象是这个Layer的交互,其他的游戏对象不会与射线发生交互;QueryTriggerInteraction默认参数表示查询使用全局 Physics.queriesHitTriggers 设置,还有两个可选值,Ignore表示忽略,当游戏对象的Collider组件下的Is Trigger被勾选后,射线检测也将不会与其交互;Collider参数表示始终报告触发器命中。

if (Physics.Raycast(ray, out hit,Mathf.Infinity,badMask,QueryTriggerInteraction.Ignore))
        {
            Gizmos.color = Color.green; 
            Gizmos.DrawLine(transform.position, hit.point);
        }

RaycastHit[]

除了声明单个RaycastHit外,还可以设置RaycastHit[]数组,Physcis.RaycastAll可以获得所有的与射线交互的信息,这里我传入了第三个参数LayerMask,将下图中红框内的物体的层级设置为了badMask,这样射线检测只会与这个层级的物体发生交互,最后打印出了三个物体的名称,以及RaycastHit[]数组的大小。

        RaycastHit[] hits;

        hits = Physics.RaycastAll(ray,Mathf.Infinity,badMask);
        for (int i = 0; i < hits.Length; i++)
        {
            Debug.Log(hits[i].collider.gameObject.name);
        }
        Debug.Log(hits.Length);

unity 射线检测,unity,游戏引擎,游戏程序

unity 射线检测,unity,游戏引擎,游戏程序

 Layer

 在写的时候发现从不同地方获取到的LayerMask的int值不同。

[SerializeField] private LayerMask badMask这样通过面板获得的值是2^value ,value是在Unity面板中Layer的数值,插一嘴Layer中用四个字节也就是32位来表示,每一个Layer占据其中一位,如此来说badMask.value返回的就是十进制表示的数;通过结构体hit.collider.gameObject.layer获得的就是上文中说的value,也就是占据哪一位的数值。

如果想要比较二者是否相同,需要进行转换:

if (Mathf.Pow(2,(hit.collider.gameObject.layer)) == badMask.value)

unity 射线检测,unity,游戏引擎,游戏程序

应用

1.对Bad层级的物体进行着色

看效果图,有的没有被着色,是因为被前面的对象遮住了,一个解决办法是顺带更改前面对象的层级,让它不再被射线交互。

unity 射线检测,unity,游戏引擎,游戏程序

public class Sphere : MonoBehaviour
{
    [SerializeField] private Material recordBad;
    [SerializeField] private Material originBad;
    [SerializeField] private LayerMask badMask;

    private void OnDrawGizmos()
    {
        Ray ray = new Ray(transform.position, transform.forward);
        Gizmos.color = Color.blue;

        //Gizmos.DrawRay(ray);

        RaycastHit hit;
        Gizmos.color = Color.blue;
        Gizmos.DrawLine(transform.position, transform.TransformPoint(Vector3.forward * 10));
        //Gizmos.color = Color.black;
        //Gizmos.DrawLine(transform.position, Vector3.forward);

        RaycastHit[] hits;

        hits = Physics.RaycastAll(ray,Mathf.Infinity,badMask);
        for (int i = 0; i < hits.Length; i++)
        {
            Debug.Log(hits[i].collider.gameObject.name);
        }
        Debug.Log(hits.Length);

        if (Physics.Raycast(ray, out hit,Mathf.Infinity,badMask,QueryTriggerInteraction.Ignore))
        {
            Gizmos.color = Color.green; 
            Gizmos.DrawLine(transform.position, hit.point);
            hit.collider.gameObject.GetComponent<Renderer>().material = recordBad;
        }
    }
}

2.从相机发射射线与地面进行射线交互

        Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, ground))
        {
            Vector3 point =  hit.point;
            controller.LookAt(point);
        }
        public void LookAt(Vector3 lookPoint)
    {
        Vector3 heightCorrectedPoint = new Vector3(lookPoint.x, transform.position.y, lookPoint.z);
        transform.LookAt(heightCorrectedPoint);
    }

还有一种方式是通过Plane来接收射线,返回的distance表示沿射线与平面相交的距离。如果射线平行于平面,函数返回false并设置enter为零。如果射线指向与平面相反的方向,则函数返回false并设置enter为沿射线的距离(负值)。

        Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
        float distance;
        Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
        if (groundPlane.Raycast(ray, out distance))
        {
            Vector3 point = ray.GetPoint(distance);
            //Debug.DrawLine(ray.origin, point, Color.red);
            controller.LookAt(point);
        }

射线检测

3.运动的物体在场景中进行避障

unity 射线检测,unity,游戏引擎,游戏程序

以物体为圆心,规定半径和生成的点的数量,近似以点来近似球表面

public static class BoidHelper {

    const int numViewDirections = 300;
    public static readonly Vector3[] directions;

    static BoidHelper () {
        directions = new Vector3[BoidHelper.numViewDirections];

        float goldenRatio = (1 + Mathf.Sqrt (5)) / 2;
        float angleIncrement = Mathf.PI * 2 * goldenRatio;

        for (int i = 0; i < numViewDirections; i++) {
            float t = (float) i / numViewDirections;
            //对应二维的半径R
            float inclination = Mathf.Acos (1 - 2 * t);
            float azimuth = angleIncrement * i;

            //球坐标转直角坐标
            float x = Mathf.Sin (inclination) * Mathf.Cos (azimuth);
            float y = Mathf.Sin (inclination) * Mathf.Sin (azimuth);
            float z = Mathf.Cos (inclination);
            directions[i] = new Vector3 (x, y, z);
        }
    }

}
 Vector3 ObstacleRays()
    {
        rayDirections = BoidHelper.directions;
        if (rayDirections != null)
        {
            flag = true;
        }

        for (int i = 0; i < rayDirections.Length; i++)
        {
            Vector3 dir = cachedTransform.TransformDirection(rayDirections[i]);
            Ray ray = new Ray(position, dir);
            if (!Physics.SphereCast(ray, settings.boundsRadius, settings.collisionAvoidDst, settings.obstacleMask))
            {
                return dir;
            }
        }

        return forward;
    }
 void OnDrawGizmosSelected()
    {
        if (flag)
        {
            DrawGizmos();
        }
    }

    void DrawGizmos()
    {
        Debug.LogFormat("进入DraGizmos");
        Debug.LogFormat("进入DraGizmos Flag");
        Gizmos.color = Color.red;
        foreach (var go in rayDirections)
            Gizmos.DrawSphere(position + go, 0.02f);
        Gizmos.color = Color.green;
        foreach (var go in rayDirections)
        {
            Vector3 dir = cachedTransform.TransformDirection(go) * SpherePointsRadius;
            Gizmos.DrawSphere(position + dir, radius);
        }


    }

总结

  • 想要一个物体被射线检测到,就必须加上Collider组件,Is Trigger并不影响射线检测
  • 生成一个射线需要五个参数,起始点,方向,碰撞信息结构体,范围距离,检测层
    • 起始点一般使用transform.position来表示
    • 方向一般使用transform.forward,表示当前物体正前方
    • 碰撞信息使用RaycastHit结构体来存贮,需要事先声明
    • 检测范围是float型,可不写,默认无限长
    • 检测层可不写,默认全检测
  • 如果你使用Debug.DrawLine()画了一条线而没有显示出来,不妨看看Gizmos有没有被关闭
  • Raycast返回值是Bool,而RaycastAll返回值则是RaycastHit结构体数组
  • 混淆点
    • Ray是一个类,表示射线
    • RaycastHit是一个结构体,记录射线的碰撞信息
    • Raycast和RaycastAll是函数,使用射线来检测碰撞,通过Physics来调用

参考资料

梦小天幼:详解Unity中的射线与射线检测

Coding Adventure: Boids文章来源地址https://www.toymoban.com/news/detail-725477.html

到了这里,关于Unity 的射线检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • unity中的射线碰撞检测

    在Unity中,射线碰撞检测是一种常用的技术,通常用于确定射线与场景中的物体是否相交,并获取相交点的信息。 1.创建射线: 使用 Ray 类或 RaycastHit 结构体创建射线。 Ray 表示射线的起点和方向,而 RaycastHit 用于存储射线与物体相交的信息,如相交点、法线等。 2.发射射线:

    2024年03月17日
    浏览(41)
  • 【超级入门】Unity如何实现画射线+射线检测+NavMeshAgent结合

           “射线检测 是在3D数字世界里选择某个特定物体常用的一种技术,如在3D、VR游戏中检测子弹命中敌人情况或者从地上捡起一支枪,这都要用到 射线检测 , 射线检测 是在3D数字空间中选择虚拟物体的最基本方法。 ” 效果: 我们先创建一个物体,挂脚本 RayTest ,代码

    2024年02月15日
    浏览(35)
  • 第二十八章 Unity射线检测

    本章节我们介绍一下射线。射线就是从一个固定点向一个方向发射出一条直线,在发射过程中需要判断该射线有没有与游戏物体发送碰撞。射线既可以用来检测射击游戏中武器指向目标;又可以判断鼠标是否指向游戏物体。射线的创建方式,一般使用代码来实现。接下来,我

    2024年02月11日
    浏览(59)
  • Unity3d 射线检测

    射线碰撞单个物体: 方式1:从摄像机向世界发射一条射线,通常用于检测鼠标指针有没有选择物体 方式2:创建从一个点到一个方向的射线 声明一个射线碰撞信息类 //进行碰撞检测并返回结果,检测信息会写入碰撞信息类 射线碰撞多个物体: 例:可以用射线检测人物与地面

    2024年02月08日
    浏览(40)
  • Unity 之`Physics.Raycast()`方法,射线检测

    当你在Unity中使用 Physics.Raycast() 方法时,你实际上是在进行一种射线检测,以查看一条射线是否与场景中的碰撞体相交。这可以用来实现很多不同的功能,如点击选择物体、射击命中检测等。以下是 Physics.Raycast() 方法的详细介绍: 参数解释: origin :射线的起点(3D世界坐标

    2024年02月11日
    浏览(39)
  • Unity 射线与碰撞范围检测【踩坑记录】

    射线检测在2D和3D的区别比较大 一定要加上对应的Collider组件 对应的函数只检测对应的Collider, Physics.Raycast 是不会检测到Collider 2D的(这个让我有一次debug了好久才发现) 对应API如下 可以使用 Debug.DrawLine(Vector3 origin,Vector3 destination,Color color) 和 Debug.DrawRay(Vector3 origin,Vector3 dir

    2023年04月08日
    浏览(31)
  • Unity 中检测射线穿过的所有的物体

     在开发中 有个需求,射线要检测所有穿过的物体。 代码如下:   运行结果  

    2024年02月14日
    浏览(37)
  • Unity在物体内部发射射线检测不到物体的解决方式

    在Unity2018.1.18上不大好用。

    2024年02月15日
    浏览(35)
  • Unity UGUI的PhysicsRaycaster (物理射线检测)组件的介绍及使用

    PhysicsRaycaster是Unity UGUI中的一个组件,用于在UI元素上进行物理射线检测。它可以检测鼠标或触摸事件是否发生在UI元素上,并将事件传递给相应的UI元素。 PhysicsRaycaster通过发射一条射线来检测UI元素。当射线与UI元素相交时,PhysicsRaycaster会将事件传递给相应的UI元素。 Event

    2024年02月15日
    浏览(46)
  • 【游戏开发实战】Unity实现类似GitHub地球射线的效果(LineRenderer | 贝塞尔曲线)

    一、前言 嗨,大家伙,我是新发。 好久不见,这是2022年第一篇博客,今天有同学私信我,问我在 Unity 中如何实现这种地球辐射线的效果, 这一看,我就想到了 GitHub 主页的地球射线, 那么,今天就来讲讲如何实现这个效果吧~ 本文最终效果如下: 本文工程源码见文章末尾

    2024年02月06日
    浏览(95)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包