Unity3d Ray射线

推荐使用     LayerMask  代替 int表示层级,这样就可以在面板上多选了

public LayerMask obstacleMask;

Physics.Raycast(射线,碰撞体信息,射线长度多少米,要检测的碰撞层)

Physics.Raycast(起点,方向,碰撞体信息,射线长度多少米,要检测的碰撞层)

两种常用射线方法:
    A:从鼠标发射射线

if (Input.GetMouseButtonDown(0))
{
    //从摄像机到鼠标位置的一条射线
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    RaycastHit hit; //碰撞体信息
    if (Physics.Raycast(ray, out hit, 81f))
    {
        //碰撞到的点 hit.point 
        //碰撞到的物体  hit.transform.gameObject
    }
}

    B:从物体的某个方向发射,下面的是从角色下方发射81米长的射线 

​
RaycastHit hit; //碰撞体信息
//Physics.Raycast(起点,方向,碰撞体信息,射线长度多少米,要检测的碰撞层)
if (Physics.Raycast(transform.position, Vector3.down,out hit,  81f))
{
	//碰撞到的点 hit.point 
	//碰撞到的物体  hit.transform.gameObject
}

​

​

 下面代码演示了 射线只与地面层碰撞检测

​//从摄像机到鼠标位置的一条射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit; //碰撞体信息
int groundLayer = LayerMask.GetMask("Ground"); //要碰撞的层,得到地面layer层级
//Physics.Raycast(射线,碰撞体信息,射线长度多少米,要检测的碰撞层)
if (Physics.Raycast(ray, out hit, 81f, groundLayer))
{
	//碰撞到的点 hit.point 
	//碰撞到的物体  hit.transform.gameObject
}

​

 求射线穿过物体起点坐标和终点坐标?

求终点方法 从dis距离处 反向发射射线 ,一直碰到第一次正面碰到的物体,否则dis距离减一

缺点:dis越远 消耗的运行时间越长 达到3秒以上.

using System;
using System.Collections;
using UnityEngine;
public class Test12 : MonoBehaviour
{
    public Transform SendPos;
    public Transform endPos_Obj;
    public Transform startPos_obj;

    void SendRay(Vector3 pos,Vector3 dir, Action<RaycastHit> onHit)
    {
        var raycast = default(RaycastHit);
        var rey = new Ray(pos, dir);
        var isHit = Physics.Raycast(rey, out raycast, 2000f);
        Debug.DrawRay(SendPos.position, dir, Color.green);
        if (isHit)
        {
            Debug.DrawLine(SendPos.position, raycast.point, Color.red);
            onHit(raycast);
        }
    }

    //求终点方法 从dis距离处 反向发射射线 ,一直碰到第一次正面碰到的物体,否则dis距离减一

    private string start_nameHit;
    private string end_nameHit="";
    private float dis = 250f;
    IEnumerator FindBackPos()
    {
        do
        {
            var pos = startPos_obj.position + SendPos.up * dis;
            SendRay(pos, -SendPos.up, x =>
            {
                end_nameHit = x.transform.name;
                if (end_nameHit != start_nameHit)
                {
                    dis -= 1f;
                }
                else
                {
                    endPos_Obj.position = x.point;
                }
            });
            yield return new  WaitForEndOfFrame();
        } while (end_nameHit != start_nameHit);
    }
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        SendRay(SendPos.position, SendPos.up, y =>
        {
            startPos_obj.position = y.point;
            start_nameHit = y.transform.name;
            StartCoroutine(FindBackPos());
        });

        Debug.DrawLine(SendPos.position, SendPos.position+SendPos.up*500,Color.green);
    }
}

 

为飞鸟装上自动导航仪

小鸟在空间中自由飞翔,不会撞到障碍物,通过射线 探测环境 从而避障,

也可以用在鱼类

using UnityEngine;

public class Fly : MonoBehaviour
{
    /// <summary>
    /// 自身的大小半径
    /// </summary>
    public float boundsRadius = 2.5f;
    //射线的探测距离
    public float collisionAvoidDst = 1f;

    public float speed = 3f;
    /// <summary>
    /// 探测碰撞层,墙体 树啊等
    /// </summary>
    public LayerMask obstacleMask;
    void Awake()
    {
        CacularAngle();
    }
    // Update is called once per frame
    void Update()
    {
        Vector3 dir = ObstacleRays();
        transform.position += dir * speed * Time.deltaTime;
        transform.forward = dir;
    }

    const int numViewDirections = 300;
    public static  Vector3[] rayDirections;

    /// <summary>
    /// 求出球体 中心 到 边缘 300度 3D 向量,分割3D圆的角度
    /// </summary>
    static void CacularAngle()
    {
        rayDirections = new Vector3[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; //0到1的距离
            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);
            rayDirections[i] = new Vector3(x, y, z);
        }
    }

    /// <summary>
    /// 求没有障碍物的方向:从物体的前方以一定的角度递增,直到找到一个没有被阻挡的方向
    /// </summary>
    /// <returns></returns>
   Vector3 ObstacleRays()
   {
       Vector3[] rayDirections = BoidHelper.directions;

       for (int i = 0; i < rayDirections.Length; i++)
       {
           Vector3 dir = transform.TransformDirection(rayDirections[i]);
           Ray ray = new Ray(transform.position, dir);
           Debug.DrawRay(transform.position, dir,Color.red,0.5f);
           if (!Physics.SphereCast(ray, boundsRadius, collisionAvoidDst, obstacleMask))
           {
               Debug.DrawRay(transform.position, dir, Color.green, 0.5f);
               return dir;
           }
       }
       return transform.forward;
   }

}

鼠标相对于角色的方向 向量

    /// <summary>
    ///鼠标相对于角色的方向 向量
    /// </summary>
    public static Vector3 Player_relative_mouse_direction(Vector3 playerPos)
    {
        //原理 : 通过把鼠标位置 转换成3d坐标
        //鼠标相对于角色的方向 = 鼠标3d坐标 - 角色坐标

        Vector3 dir = Vector3.forward;
        //从摄像机通过一个屏幕点的射线,摄像机位置 =》屏幕点方向 的射线
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit = new RaycastHit();
        if (Physics.Raycast(ray, out hit))
        {
            Vector3 hitPos = hit.point;

            //向量减法 和y无关,所以同步一下高度
            playerPos.y = hitPos.y;
            //向量减法,得到一个向量,包含方向和距离
            dir = (hitPos - playerPos);
            //归一化 去除距离 ,只要方向,如果不去除距离 ,那么角色闪到鼠标点击的位置
            dir = dir.normalized;
        }
        return dir;
    }

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值