开始之前
理解 Vector3、Part 和 nil 检查。新建 Lesson22 Baseplate。
Course overview
不用真的扔出一个方块,也能知道前方有没有墙。Raycast 从起点沿一个方向检查,返回最先碰到的对象。
这是一台测距仪,不是武器。你会读取距离,并用一条细光线画出结果,帮助自己理解向量。
理解 Vector3、Part 和 nil 检查。新建 Lesson22 Baseplate。
朝前探测 50 studs 的 Sensor,Output 显示命中物体和距离。
有墙时命中墙,无墙时返回 nil;改变长度会改变可探测范围。

Learning route
每完成一小步,就测试一次。先说出你预计会看到什么,再用 Play 和 Output 检查,不用急着一次写完所有代码。
先采用最容易预测的排列:探测器位于 Z=-4,墙位于 Z=-24,两者都在 X=0。探测方向是 Sensor 的本地前方,即 LookVector。
LookVector 本身长度约为 1,乘以 50 才表示探测 50 studs。Raycast 的第二个参数不是终点坐标。
RaycastParams 用来排除 Sensor,避免探测到自己。结果为 nil 时不能继续读取 result.Instance,必须分支处理。
CanCollide 决定物理阻挡,CanQuery 决定能否参与空间查询。一个没有碰撞的装饰物,仍可能被射线检测到。
测距返回的是首个命中表面,而不是一直穿透场景寻找目标名称。前面加一块箱子,结果就应该变成箱子。
Step by step
先采用最容易预测的排列:探测器位于 Z=-4,墙位于 Z=-24,两者都在 X=0。探测方向是 Sensor 的本地前方,即 LookVector。
默认 Orientation=0,0,0 时,LookVector 朝负 Z。转动 Sensor 也会改变射线方向,位置与朝向不要混在一起理解。
Step by step
LookVector 本身长度约为 1,乘以 50 才表示探测 50 studs。Raycast 的第二个参数不是终点坐标。
如果已知起点 origin 和终点 target,方向向量应该是 target - origin。把 target 直接传进去,可能会得到另一条完全不同的射线。
Step by step
RaycastParams 用来排除 Sensor,避免探测到自己。结果为 nil 时不能继续读取 result.Instance,必须分支处理。
可见的细线是我们额外创建的 Part,不是 Raycast 自动生成的。它设为 CanQuery=false,避免以后再次探测时被自己的辅助线挡住。
local sensor = workspace:WaitForChild("Sensor")
local MAX_DISTANCE = 50
task.wait(3)
local origin = sensor.Position
local direction = sensor.CFrame.LookVector * MAX_DISTANCE
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {sensor}
local result = workspace:Raycast(origin, direction, params)
local finish = origin + direction
if result then
finish = result.Position
print("Hit:", result.Instance.Name, "Distance:", result.Distance)
else
print("Nothing within", MAX_DISTANCE)
end
local distance = (finish - origin).Magnitude
if distance > 0 then
local line = Instance.new("Part")
line.Name = "ProbeLine"
line.Anchored = true
line.CanCollide = false
line.CanTouch = false
line.CanQuery = false
line.Material = Enum.Material.Neon
line.Color = Color3.fromRGB(70, 220, 230)
line.Size = Vector3.new(0.12, 0.12, distance)
line.CFrame = CFrame.lookAt(origin, finish) * CFrame.new(0, 0, -distance / 2)
line.Parent = workspace
end
Step by step
CanCollide 决定物理阻挡,CanQuery 决定能否参与空间查询。一个没有碰撞的装饰物,仍可能被射线检测到。
本课不伤害命中对象,也不会删除墙。先把测量结果弄清楚,以后才将结果接到其他玩法上。
Step by step
测距返回的是首个命中表面,而不是一直穿透场景寻找目标名称。前面加一块箱子,结果就应该变成箱子。
不要为了不断更新距离就每帧无限创建辅助线。持续探测需要复用对象、控制频率,并清理不再使用的资源。

Homework
记录墙、空地和箱子三种情况下的对象名与距离。
把 Sensor 绕 Y 轴旋转 90°,重新摆墙到新的前方。
把方向改为 Vector3.new(0,-20,0),测量 Sensor 到地面的距离。
Exit questions
不是,是带长度的方向向量;已知终点时用终点减起点。
没有命中时会返回 nil,不能读取 nil.Instance。
不是,是脚本另建的辅助 Part。
避免后续射线先命中自己的可视化辅助物。
Explore further
正文代码可以直接复制。先确认脚本类型、放置位置,以及这段代码是完整版本还是小实验;不要把同一脚本的多个版本叠加运行。界面参考图已标注来源,图中的对象名可能与本课不同,请以操作步骤为准。