推荐使用 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;
}