射线(Ray):
Ray
结构体包含两个主要部分:一个起点(origin
)和一个方向(direction
)。射线检测(Raycast):
Physics.Raycast
方法用于执行射线检测。Ray
或起点和方向向量)。QueryTriggerInteraction
)。LayerMask:
LayerMask.NameToLayer
方法将层级的名称转换为对应的层级索引。QueryTriggerInteraction:
UseGlobal
:使用全局设置(Physics.queriesHitTriggers
)。Collide
:总是与触发器交互。Ignore
:忽略触发器。重载方法:
Physics.Raycast
有多个重载版本,允许不同的参数传递方式。// 1. 最原始的射线检测
// 准备一条射线
Ray r3 = new Ray(Vector3.zero, Vector3.forward);
// 进行射线检测 如果碰撞到对象 返回true
// 参数一:射线
// 参数二: 检测的最大距离 超出这个距离不检测
// 参数三:检测指定层级(不填检测所有层)
// 参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器 Ignore-忽略触发器 不填使用UseGlobal
// 返回值:bool 当碰撞到对象时 返回 true 没有 返回false
if (Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象");
}
// 还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
// 就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象2");
}
碰撞检测:
光照和着色:
在射线投射中,如果射线与物体发生碰撞,RaycastHit
结构体中的 normal
属性会存储碰撞点处物体表面的法线。这可以用于:
在 Unity 中,您可以使用 RaycastHit
结构体中的 normal
属性来获取碰撞点处的法线。
Raycasting (射线投射):
Physics.Raycast
是 Unity 中用于检测射线是否与游戏世界中的物体发生碰撞的方法。RaycastHit (射线击中信息):
RaycastHit
是一个结构体,用于存储射线投射的结果。RaycastHit
会包含碰撞点、法线、碰撞物体等信息。LayerMask (层级遮罩):
LayerMask
用于指定射线投射应该检测哪些层级的物体。LayerMask.NameToLayer
方法可以将层级的名称转换为层级索引。QueryTriggerInteraction (触发器交互):
UseGlobal
使用全局设置,Collide
表示检测触发器,Ignore
表示忽略触发器。out 参数:
out
关键字用于定义一个输出参数,允许方法返回额外的信息。重载方法:
Physics.Raycast
有多个重载版本,可以传入射线或起点和方向。using UnityEngine;
public class RaycastExample : MonoBehaviour
{
void Update()
{
// 定义射线的起点和方向
Ray ray = new Ray(transform.position, transform.forward);
// 物体信息类 RaycastHit
RaycastHit hitInfo;
// 射线
// RaycastHit 是结构体,是值类型。Unity 会通过 out 关键字在函数内部处理后,得到碰撞数据后返回到该参数中
// 距离
// 检测指定层级(不填检测所有层)
// 是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器 Ignore-忽略触发器 不填使用 UseGlobal
if (Physics.Raycast(ray, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
Debug.Log("碰撞到了物体 得到了信息");
// 碰撞器信息
Debug.Log("碰撞到物体的名字: " + hitInfo.collider.gameObject.name);
// 碰撞到的点
Debug.Log("碰撞到的点: " + hitInfo.point);
// 法线信息
Debug.Log("法线信息: " + hitInfo.normal);
// 得到碰撞到对象的位置
Debug.Log("碰撞到对象的位置: " + hitInfo.transform.position);
// 得到碰撞到对象 离自己的距离
Debug.Log("离自己的距离: " + hitInfo.distance);
}
else
{
Debug.Log("没有碰撞到任何物体");
}
// 另一种重载,不用传入射线,直接传入起点和方向
if (Physics.Raycast(Vector3.zero, Vector3.forward, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
Debug.Log("使用起点和方向的射线投射也碰撞到了物体");
}
else
{
Debug.Log("使用起点和方向的射线投射没有碰撞到任何物体");
}
}
}
Physics.RaycastAll
方法用于从射线发出点开始,沿着射线方向检测所有碰撞到的物体。它返回一个 RaycastHit
数组,每个元素包含碰撞信息。
参数说明:
Ray
或 Vector3
起点和 Vector3
方向的组合)。LayerMask
),用于指定检测哪些层级的物体。QueryTriggerInteraction
),用于决定是否检测触发器。RaycastHit
结构体包含碰撞信息,如碰撞点、碰撞物体的 GameObject
、碰撞法线等。
Physics.RaycastAll
有一个重载版本,允许直接使用起点和方向来创建射线。
Physics.RaycastNonAlloc
方法用于检测射线与物体的碰撞,但它不会分配新的数组,而是使用传入的数组来存储碰撞信息。如果发生碰撞,它会返回碰撞的数量。
根据这些知识点,下面是补全的代码:
// 定义射线的起点和方向
Ray ray = new Ray(Vector3.zero, Vector3.forward);
// 定义最大检测距离
float maxDistance = 1000f;
// 定义层级掩码,只检测名为"Monster"的层
LayerMask monsterLayer = 1 << LayerMask.NameToLayer("Monster");
// 使用Physics.RaycastAll检测射线与物体的碰撞
RaycastHit[] hits = Physics.RaycastAll(ray, maxDistance, monsterLayer, QueryTriggerInteraction.UseGlobal);
// 遍历所有碰撞结果并打印碰撞物体的名称
for (int i = 0; i < hits.Length; i++)
{
print("碰到的所有物体 名字分别是 " + hits[i].collider.gameObject.name);
}
// 使用重载版本的Physics.RaycastAll,直接传入起点和方向
hits = Physics.RaycastAll(Vector3.zero, Vector3.forward, maxDistance, monsterLayer, QueryTriggerInteraction.UseGlobal);
// 使用Physics.RaycastNonAlloc检测射线与物体的碰撞,并使用已有的数组来存储结果
if (Physics.RaycastNonAlloc(ray, hits, maxDistance, monsterLayer, QueryTriggerInteraction.UseGlobal) > 0)
{
// 如果有碰撞发生,遍历碰撞结果并打印碰撞物体的名称
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].collider != null) // 确保hits数组中的元素不是空的
{
print("碰撞到的物体 名字是 " + hits[i].collider.gameObject.name);
}
}
}
参数类型明确性:
Physics.Raycast
或相关方法时,需要明确每个参数的类型和它们代表的意义。float
类型,代表射线的最大检测距离。int
类型,代表层级掩码(LayerMask
),用于指定检测哪些层级的物体。错误的参数传递:
Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"))
是错误的,因为第二个参数 1000
应该是一个 float
类型,而不是 int
类型。正确的参数传递:
float
类型,例如 Physics.Raycast(r3, maxDistance, 1 << LayerMask.NameToLayer("Monster"))
,其中 maxDistance
是一个 float
类型的变量。层级掩码的使用:
LayerMask
)是一个 int
类型的位掩码,用于指定哪些层级的物体应该被射线检测到。1 << LayerMask.NameToLayer("Monster")
可以创建一个只检测名为 "Monster" 层的层级掩码。参数顺序:
触发器交互设置:
QueryTriggerInteraction
枚举用于控制是否检测触发器。它可以是 UseGlobal
、Collide
或 Ignore
。总结这些知识点,您可以修正代码如下:
// 定义射线
Ray r3 = new Ray(Vector3.zero, Vector3.forward);
// 定义最大检测距离,注意这里是float类型
float maxDistance = 1000.0f;
// 定义层级掩码,只检测名为"Monster"的层
LayerMask monsterLayer = 1 << LayerMask.NameToLayer("Monster");
// 正确的调用方式,注意距离参数是float类型
if (Physics.Raycast(r3, maxDistance, monsterLayer))
{
// 碰撞检测到的逻辑
}