主题
PhysicsService
概览
| 字段 | 值 |
|---|---|
| Kind | Service · 服务 Service |
| Realm | common |
继承关系
- Unit(4 属性 / 25 函数 / 6 事件)
- [PhysicsService](1 属性 / 14 函数)
> Service 继承 Unit 仅表示运行时类型关系;作者可用 API 以当前 Service 页面显式列出的成员为准,不自动包含 Unit 的创建、层级或销毁能力。
PhysicsService 提供空间查询与碰撞组管理能力:可执行射线、方块、球体、形状和重叠范围查询,也可注册碰撞组并配置组间碰撞关系。空间查询按公开的 common Realm 使用;碰撞组注册和关系变更由服务端权威配置。
适用场景
需要检测射线路径、查询指定盒体或半径内的单位,或配置特定碰撞组之间是否碰撞时使用。
使用要点
通过 game:GetService("PhysicsService") 获取服务。Raycast、Blockcast、Spherecast、Shapecast 的过滤参数在最新 Meta 中为可选;只有需要实例列表或碰撞组过滤时才构造 RaycastParams。
注意事项
PhysicsService 提供物理碰撞检测与碰撞组管理。Raycast/Blockcast/Spherecast 返回 RaycastResult 或 nil;未命中时应依次检查方向向量长度、目标 PhysicsActive/CanQuery、FilterDescendantsInstances 和 CollisionGroup 关系。碰撞组注册与关系变更以服务端为权威,客户端不应承担配置职责。GetCollisionWithGroupDict 的最新 Meta 尚未声明返回值;在公开契约补齐前,不要读取或遍历其返回结果。2026-08-11 当前运行包的 CFrame 桥接在首次调用 Blockcast/GetPartBoundsInBox 时可能写入 Lua VM warning,但调用会完成并返回结果;这是运行包告警,不应改用错误的 FromMatrix(pos, Quaternion) 形态规避。
代码示例
执行射线检测
lua
-- @runtime client
local PhysicsService = game:GetService('PhysicsService')
local origin = Vector3.New(0, 10, 0)
local direction = Vector3.New(0, -100, 0)
local params = RaycastParams.New()
local hit = PhysicsService:Raycast(origin, direction, params)
if hit ~= nil and hit.Instance ~= nil then
print('命中单位:', hit.Instance.Name, '距离:', hit.Distance)
else
print('射线未命中')
end属性 (1)
| Name | 类型 | 默认值 | 说明 |
|---|---|---|---|
ContinuousCollisionEnabled | Bool | false | 控制物理引擎是否启用连续碰撞检测(CCD),用于减少高速运动物体的穿透现象。 |
关联类型
函数 (14)
Raycast
签名:Raycast(origin: Vector3, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (射线检测结果(无命中返回nil))
从 origin 出发沿 direction 方向发射一条射线进行检测,返回命中结果 RaycastResult;若该射线没有命中任何对象则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。
| 参数 | 类型 | 说明 |
|---|---|---|
origin | Vector3 | 射线起点 |
direction | Vector3 | 射线方向(长度=最大距离) |
raycastParams? | RaycastParams | 射线过滤参数(可选) |
返回值 RaycastResult | nil (射线检测结果(无命中返回nil))
示例代码
向下发射射线并按过滤列表排除探针单位
lua
-- @runtime client
-- 获取物理服务与世界服务
local physicsService = game:GetService("PhysicsService")
local world = game:GetService("World")
-- 创建一个探针单位,稍后把它排除在检测之外,避免自命中
local probeUnit = world:CreateUnit("WorldUnit", {
BodyType = Enums.BodyType.Kinematic, -- 运动学刚体,可作为查询参与方
CanQuery = true, -- 允许被物理查询命中
})
local raycastParams = RaycastParams.New()
raycastParams.FilterType = Enums.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = { probeUnit }
-- 从高处向下发射一条长度 50 的射线
local origin = Vector3.New(0, 10, 0)
local direction = Vector3.New(0, -50, 0)
local rayResult = physicsService:Raycast(origin, direction, raycastParams)
if rayResult then
print("射线命中:", rayResult.Instance, "命中点:", rayResult.Position, "距离:", rayResult.Distance)
else
print("射线未命中任何单位")
endBlockcast
签名:Blockcast(cframe: CFrame, size: Vector3, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (命中结果(无命中返回nil))
以 cframe 与 size 描述一个方块形状,并让该方块沿 direction 方向推进做形状投射,返回首次命中的 RaycastResult;若整个推进过程中没有命中任何对象则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。
⚙ cframe 必须传 CFrame。当前运行包可能在首次桥接 CFrame 时写 warning,但调用仍会完成。
| 参数 | 类型 | 说明 |
|---|---|---|
cframe | CFrame | 方块位置与朝向 |
size | Vector3 | 方块尺寸 |
direction | Vector3 | 投射方向(长度=最大距离) |
raycastParams? | RaycastParams | 过滤参数(可选) |
返回值 RaycastResult | nil (命中结果(无命中返回nil))
示例代码
向下执行方块投射
lua
-- @runtime client
local PhysicsService = game:GetService('PhysicsService')
local cframe = CFrame.New(0, 5, 0)
local size = Vector3.New(2, 2, 2)
local direction = Vector3.New(0, -10, 0)
local result = PhysicsService:Blockcast(cframe, size, direction)
print(result and '方块投射命中' or '方块投射未命中')Spherecast
签名:Spherecast(position: Vector3, radius: Float, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (命中结果(无命中返回nil))
以 position 为球心、radius 为半径构造球体作为投射体,并让该球体沿 direction 方向推进做形状投射,返回首次命中的 RaycastResult;若整个推进过程中没有命中则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。
| 参数 | 类型 | 说明 |
|---|---|---|
position | Vector3 | 球心位置 |
radius | Float | 球半径 |
direction | Vector3 | 投射方向(长度=最大距离) |
raycastParams? | RaycastParams | 过滤参数(可选) |
返回值 RaycastResult | nil (命中结果(无命中返回nil))
示例代码
向下扫掠球体检测最近命中
lua
-- @runtime client
-- 获取物理服务单例
local physicsService = game:GetService("PhysicsService")
-- 球心位置、半径与扫掠方向
local spherePosition = Vector3.New(0, 15, 0)
local sphereRadius = 2
local sweepDirection = Vector3.New(0, -40, 0) -- 向量长度即最大扫掠距离
local castParams = RaycastParams.New()
-- 沿方向扫掠球体,返回最近的一次命中
local sphereHit = physicsService:Spherecast(spherePosition, sphereRadius, sweepDirection, castParams)
if sphereHit then
print("球形投射命中:", sphereHit.Instance, "命中点:", sphereHit.Position, "距离:", sphereHit.Distance)
else
print("球形投射未命中任何目标")
endShapecast
签名:Shapecast(part: Unit, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (命中结果(无命中返回nil))
以作为参数的 Unit 的碰撞形状作为投射体,沿 direction 方向推进做形状投射,返回首次命中的 RaycastResult;若整个推进过程中没有命中则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。
| 参数 | 类型 | 说明 |
|---|---|---|
part | Unit | 进行检测的部件 |
direction | Vector3 | 投射方向(长度=最大距离) |
raycastParams? | RaycastParams | 过滤参数(可选) |
返回值 RaycastResult | nil (命中结果(无命中返回nil))
示例代码
使用临时形状执行投射并清理
lua
-- @runtime client
local PhysicsService = game:GetService('PhysicsService')
local World = game:GetService('World')
local shapeUnit = World:CreateUnit('WorldUnit', {
Position = Vector3.New(0, 5, 0),
Scale = Vector3.New(1, 1, 1),
})
if shapeUnit == nil then return end
local result = PhysicsService:Shapecast(shapeUnit, Vector3.New(0, -10, 0))
if result ~= nil then
print('形状投射命中:', result.Instance and result.Instance.Name)
end
shapeUnit:Destroy()RegisterCollisionGroup
签名:RegisterCollisionGroup(name: String) -> void
注册一个新的碰撞组,供后续碰撞关系设置使用。
⚙ 碰撞组注册属于服务端权威配置;客户端只读取已同步的碰撞关系,不负责注册。
| 参数 | 类型 | 说明 |
|---|---|---|
name | String | 碰撞组名称 |
返回值 void
示例代码
在服务端注册碰撞组
lua
-- @runtime server
local PhysicsService = game:GetService('PhysicsService')
local groupName = 'DemoPlayer'
pcall(function()
PhysicsService:RegisterCollisionGroup(groupName)
end)CollisionGroupSetCollidable
签名:CollisionGroupSetCollidable(name1: String, name2: String, collidable: Bool) -> void
设置两个碰撞组之间是否允许发生碰撞。
⚙ 碰撞关系修改属于服务端权威配置;客户端不应调用本方法承担初始化职责。
| 参数 | 类型 | 说明 |
|---|---|---|
name1 | String | 碰撞组名称1 |
name2 | String | 碰撞组名称2 |
collidable | Bool | 是否可碰撞 |
返回值 void
示例代码
在服务端配置碰撞关系
lua
-- @runtime server
local PhysicsService = game:GetService('PhysicsService')
pcall(function() PhysicsService:RegisterCollisionGroup('DemoPlayer') end)
pcall(function() PhysicsService:RegisterCollisionGroup('DemoGhost') end)
PhysicsService:CollisionGroupSetCollidable('DemoPlayer', 'DemoGhost', false)CollisionGroupsAreCollidable
签名:CollisionGroupsAreCollidable(name1: String, name2: String) -> Bool (是否可碰撞)
查询两个碰撞组之间当前是否允许发生碰撞。
| 参数 | 类型 | 说明 |
|---|---|---|
name1 | String | 碰撞组名称1 |
name2 | String | 碰撞组名称2 |
返回值 Bool (是否可碰撞)
示例代码
在服务端配置后核对碰撞关系
lua
-- @runtime server
local PhysicsService = game:GetService('PhysicsService')
pcall(function() PhysicsService:RegisterCollisionGroup('DemoPlayer') end)
pcall(function() PhysicsService:RegisterCollisionGroup('DemoGhost') end)
PhysicsService:CollisionGroupSetCollidable('DemoPlayer', 'DemoGhost', false)
local canCollide = PhysicsService:CollisionGroupsAreCollidable('DemoPlayer', 'DemoGhost')
print('两个碰撞组是否可碰撞:', canCollide)GetRegisteredCollisionGroups
签名:GetRegisteredCollisionGroups() -> Array<String> (碰撞组名称列表)
获取所有已注册的碰撞组名称列表,包括引擎预留和用户注册的。
返回值 Array<String> (碰撞组名称列表)
示例代码
幂等注册后读取全部碰撞组
lua
-- @runtime server
local PhysicsService = game:GetService('PhysicsService')
pcall(function() PhysicsService:RegisterCollisionGroup('DemoPlayer') end)
pcall(function() PhysicsService:RegisterCollisionGroup('DemoGhost') end)
for index, name in ipairs(PhysicsService:GetRegisteredCollisionGroups()) do
print('碰撞组', index, name)
endGetEngineRegisteredCollisionGroups
签名:GetEngineRegisteredCollisionGroups() -> Array<String> (引擎预留碰撞组名称列表)
获取引擎预留的碰撞组名称列表。
返回值 Array<String> (引擎预留碰撞组名称列表)
示例代码
获取引擎预留碰撞组列表
lua
-- @runtime client
-- 获取 PhysicsService 服务
local physicsService = game:GetService("PhysicsService")
-- 获取引擎预留的碰撞组名称列表
local engineGroups = physicsService:GetEngineRegisteredCollisionGroups()
-- 输出引擎预留碰撞组数量及名称
print("引擎预留碰撞组数量: " .. #engineGroups)
for i, name in ipairs(engineGroups) do
print("引擎碰撞组[" .. i .. "]: " .. name)
endGetUserRegisteredCollisionGroups
签名:GetUserRegisteredCollisionGroups() -> Array<String> (用户碰撞组名称列表)
获取用户通过 RegisterCollisionGroup 注册的碰撞组名称列表。
返回值 Array<String> (用户碰撞组名称列表)
示例代码
读取用户注册的碰撞组
lua
-- @runtime server
local PhysicsService = game:GetService('PhysicsService')
pcall(function() PhysicsService:RegisterCollisionGroup('DemoPlayer') end)
for index, name in ipairs(PhysicsService:GetUserRegisteredCollisionGroups()) do
print('用户碰撞组', index, name)
endGetCollisionWithGroupDict
签名:GetCollisionWithGroupDict(collisionGroupName: String) -> void
按名称查询指定碰撞组的关系;最新 Meta 未声明返回值,当前不要依赖返回数据。
⚙ 最新 Meta 仅声明 collisionGroupName 参数,未声明返回值;在 Meta 补齐前不要把运行时观察到的值当作公开 Table 契约。
| 参数 | 类型 | 说明 |
|---|---|---|
collisionGroupName | String | 碰撞组名称 |
返回值 void
示例代码
返回值契约尚未公开
lua
-- @runtime client
print('GetCollisionWithGroupDict 的返回值尚未写入 Meta,请勿依赖')GetPartBoundsInBox
签名:GetPartBoundsInBox(cframe: CFrame, size: Vector3, overlapParams?: OverlapParams) -> Array<Unit> (AABB与OBB重叠的Unit列表)
在空间中用 cframe 与 size 描述一个盒子,查询包围盒与该盒子重叠的 Unit,并返回这些 Unit 组成的列表。可选的 overlapParams 用于控制哪些对象参与本次查询。
⚙ cframe 必须传 CFrame;不要把 Quaternion 作为 CFrame.FromMatrix 的基向量参数。当前运行包可能在首次桥接 CFrame 时写 warning,但查询仍会返回数组。
| 参数 | 类型 | 说明 |
|---|---|---|
cframe | CFrame | OBB位姿 |
size | Vector3 | OBB尺寸 |
overlapParams? | OverlapParams | 过滤参数(可选) |
返回值 Array<Unit> (AABB与OBB重叠的Unit列表)
示例代码
查询方框范围内的单位
lua
-- @runtime client
local PhysicsService = game:GetService('PhysicsService')
local cframe = CFrame.New(0, 5, 0)
local size = Vector3.New(10, 10, 10)
local units = PhysicsService:GetPartBoundsInBox(cframe, size)
print('范围内单位数:', #units)GetPartBoundsInRadius
签名:GetPartBoundsInRadius(position: Vector3, radius: Float, overlapParams?: OverlapParams) -> Array<Unit> (AABB与球重叠的Unit列表)
以 position 为球心、radius 为半径构造球形查询范围,查询包围盒与该球重叠的 Unit,并返回这些 Unit 组成的列表。可选的 overlapParams 用于控制哪些对象参与本次查询。
| 参数 | 类型 | 说明 |
|---|---|---|
position | Vector3 | 球心位置 |
radius | Float | 球半径 |
overlapParams? | OverlapParams | 过滤参数(可选) |
返回值 Array<Unit> (AABB与球重叠的Unit列表)
示例代码
查询球形范围内的所有单位
lua
-- @runtime client
-- 获取物理服务单例
local physicsService = game:GetService("PhysicsService")
-- 球形查询的中心点与半径
local centerPosition = Vector3.New(0, 5, 0)
local queryRadius = 15
local overlapParams = OverlapParams.New()
local unitsInRadius = physicsService:GetPartBoundsInRadius(centerPosition, queryRadius, overlapParams)
print("球形范围内单位数量:", #unitsInRadius)
for index, unit in ipairs(unitsInRadius) do
print(string.format("第 %d 个单位: %s", index, unit.Name))
endGetPartsInPart
签名:GetPartsInPart(part: Unit, overlapParams?: OverlapParams) -> Array<Unit> (与part碰撞形状精确重叠的Unit列表)
以作为参数的 Unit 的碰撞形状为基准进行重叠查询,返回与该形状精确重叠的 Unit 列表。可选的 overlapParams 用于控制哪些对象参与本次查询。
| 参数 | 类型 | 说明 |
|---|---|---|
part | Unit | 参与检测的参考Unit |
overlapParams? | OverlapParams | 过滤参数(可选) |
返回值 Array<Unit> (与part碰撞形状精确重叠的Unit列表)
示例代码
查询临时形状的重叠单位并清理
lua
-- @runtime client
local PhysicsService = game:GetService('PhysicsService')
local World = game:GetService('World')
local queryPart = World:CreateUnit('WorldUnit', {
Position = Vector3.New(0, 0, 0),
Scale = Vector3.New(2, 2, 2),
})
if queryPart == nil then return end
for index, unit in ipairs(PhysicsService:GetPartsInPart(queryPart)) do
print('重叠单位', index, unit.Name)
end
queryPart:Destroy()