Unity射线的使用

2017年04月13日 17:09 0 点赞 0 评论 更新于 2025-11-21 13:38

一、射线的定义

射线是3D世界中从一个点向一个特定方向发射的一条无终点的线。当射线在发射轨迹中与其他物体发生碰撞时,它将停止发射。

二、射线的用途

在Unity中,射线的应用范围较为广泛,主要用于碰撞检测(例如,判断子弹飞行是否击中目标)、角色移动等场景。

三、相关API

1. Camera.main.ScreenPointToRay(Vector3 pos)

该方法返回一条射线 Ray,此射线从摄像机出发,指向屏幕上指定的一个点。

2. Camera.main.ViewportPointToRay(Vector3 pos)

该方法同样返回一条射线 Ray,不过这条射线是从摄像机出发,指向视口(视口之外无效)指定的一个点。

3. Ray 射线类

Ray 类用于表示射线,可通过它来定义射线的起始点和方向。

4. RaycastHit 光线投射碰撞信息

RaycastHit 类用于存储射线与物体碰撞后的相关信息,如碰撞点、碰撞物体的 transformrigidbody 等。

5. Physics.Raycast 系列方法

方法一:bool Physics.Raycast(Vector3 origin, Vector3 direction, float distance, int layerMask)

当光线投射与任何碰撞器交叉时返回 true,否则返回 false

方法二:bool Physics.Raycast(Ray ray, Vector3 direction, RaycastHit out hit, float distance, int layerMask)

在场景中投下一条可与所有碰撞器碰撞的光线,并返回碰撞的细节信息。

方法三:bool Physics.Raycast(Ray ray, float distance, int layerMask)

当光线投射与任何碰撞器交叉时返回 true,否则返回 false

方法四:bool Physics.Raycast(Vector3 origin, Vector3 direction, RaycastHit out hit, float distance, int layerMask)

当光线投射与任何碰撞器交叉时返回 true,否则返回 false

注意:如果从一个球型体的内部到外部用光线投射,返回值为 false

参数理解

  • origin:在世界坐标中射线的起始点。
  • direction:射线的方向。
  • distance:射线的长度。
  • hit:使用C#中 out 关键字传入一个空的碰撞信息类,碰撞后会对其进行赋值。通过该参数可以得到碰撞物体的 transformrigidbodypoint 等信息。
  • layerMask:只选定 Layermask 层内的碰撞器,忽略其它层内的碰撞器,实现选择性的碰撞。

6. RaycastHit[] RaycastAll(Ray ray, float distance, int layerMask)

投射一条光线并返回所有碰撞信息,即返回一个 RaycastHit[] 结构体。

四、示例代码

示例一:基本射线检测

using UnityEngine;
using System.Collections;

public class RayTest : MonoBehaviour {
// 主摄像机
private Camera mainCrma;
// 碰撞信息
private RaycastHit objhit;
// 射线
private Ray _ray;

// 初始化
void Start () {
mainCrma = Camera.main;
}

void Update () {
if (Input.GetMouseButtonDown(0)) {
// 从摄像机发出一条射线,指向点击的坐标
_ray = mainCrma.ScreenPointToRay(Input.mousePosition);
// 显示一条射线,只有在Scene视图中才能看到
Debug.DrawLine(_ray.origin, objhit.point, Color.red, 2);
if (Physics.Raycast(_ray, out objhit, 100)) {
GameObject gameObj = objhit.collider.gameObject;
Debug.Log("Hit objname: " + gameObj.name + " Hit objlayer: " + gameObj.layer);
}
}
}
}

示例二:使用 layerMask 参数

using UnityEngine;
using System.Collections;

public class LayerMaskTest : MonoBehaviour {
// 主摄像机
private Camera mainCrma;
// 碰撞信息
private RaycastHit objhit;
// 射线
private Ray _ray;
// 层掩码
private LayerMask mask;

// 初始化
void Start () {
mainCrma = Camera.main;
// 实例化mask到cube这个自定义的层级之上
mask = 1 << (LayerMask.NameToLayer("cube"));
}

void Update () {
if (Input.GetMouseButtonDown(0)) {
// 从摄像机发出一条射线,指向点击的坐标
_ray = mainCrma.ScreenPointToRay(Input.mousePosition);
// 划出射线,只有在Scene视图中才能看到
Debug.DrawLine(_ray.origin, objhit.point, Color.red, 2);
if (Physics.Raycast(_ray, out objhit, 100, mask.value)) {
GameObject gameObj = objhit.collider.gameObject;
Debug.Log("Hit objname: " + gameObj.name + " -- Hit objlayerName: " + LayerMask.LayerToName(10));
}
}
}
}

layerMask 参数使用说明

  • 1 << 10:打开第10层。
  • ~(1 << 10):打开除了第10层之外的所有层。
  • ~(1 << 0):打开所有的层。
  • (1 << 10) | (1 << 8):打开第10层和第8层。