Skip to content

PhysicsService ​

概览 ​

字段值
KindService · 服务 Service
Realmcommon

继承关系 ​

  • 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类型默认值说明
ContinuousCollisionEnabledBoolfalse控制物理引擎是否启用连续碰撞检测(CCD),用于减少高速运动物体的穿透现象。

关联类型 ​

函数 (14) ​

Raycast ​

签名:Raycast(origin: Vector3, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (射线检测结果(无命中返回nil))

从 origin 出发沿 direction 方向发射一条射线进行检测,返回命中结果 RaycastResult;若该射线没有命中任何对象则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。

参数类型说明
originVector3射线起点
directionVector3射线方向(长度=最大距离)
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("射线未命中任何单位")
end

Blockcast ​

签名:Blockcast(cframe: CFrame, size: Vector3, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (命中结果(无命中返回nil))

以 cframe 与 size 描述一个方块形状,并让该方块沿 direction 方向推进做形状投射,返回首次命中的 RaycastResult;若整个推进过程中没有命中任何对象则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。

⚙ cframe 必须传 CFrame。当前运行包可能在首次桥接 CFrame 时写 warning,但调用仍会完成。

参数类型说明
cframeCFrame方块位置与朝向
sizeVector3方块尺寸
directionVector3投射方向(长度=最大距离)
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 用于控制哪些对象参与本次检测。

参数类型说明
positionVector3球心位置
radiusFloat球半径
directionVector3投射方向(长度=最大距离)
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("球形投射未命中任何目标")
end

Shapecast ​

签名:Shapecast(part: Unit, direction: Vector3, raycastParams?: RaycastParams) -> RaycastResult | nil (命中结果(无命中返回nil))

以作为参数的 Unit 的碰撞形状作为投射体,沿 direction 方向推进做形状投射,返回首次命中的 RaycastResult;若整个推进过程中没有命中则返回 nil。可选的 raycastParams 用于控制哪些对象参与本次检测。

参数类型说明
partUnit进行检测的部件
directionVector3投射方向(长度=最大距离)
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

注册一个新的碰撞组,供后续碰撞关系设置使用。

⚙ 碰撞组注册属于服务端权威配置;客户端只读取已同步的碰撞关系,不负责注册。

参数类型说明
nameString碰撞组名称

返回值 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

设置两个碰撞组之间是否允许发生碰撞。

⚙ 碰撞关系修改属于服务端权威配置;客户端不应调用本方法承担初始化职责。

参数类型说明
name1String碰撞组名称1
name2String碰撞组名称2
collidableBool是否可碰撞

返回值 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 (是否可碰撞)

查询两个碰撞组之间当前是否允许发生碰撞。

参数类型说明
name1String碰撞组名称1
name2String碰撞组名称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)
end

GetEngineRegisteredCollisionGroups ​

签名: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)
end

GetUserRegisteredCollisionGroups ​

签名: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)
end

GetCollisionWithGroupDict ​

签名:GetCollisionWithGroupDict(collisionGroupName: String) -> void

按名称查询指定碰撞组的关系;最新 Meta 未声明返回值,当前不要依赖返回数据。

⚙ 最新 Meta 仅声明 collisionGroupName 参数,未声明返回值;在 Meta 补齐前不要把运行时观察到的值当作公开 Table 契约。

参数类型说明
collisionGroupNameString碰撞组名称

返回值 void

示例代码

返回值契约尚未公开

lua
-- @runtime client
print('GetCollisionWithGroupDict 的返回值尚未写入 Meta,请勿依赖')

GetPartBoundsInBox ​

签名:GetPartBoundsInBox(cframe: CFrame, size: Vector3, overlapParams?: OverlapParams) -> Array&lt;Unit&gt; (AABB与OBB重叠的Unit列表)

在空间中用 cframe 与 size 描述一个盒子,查询包围盒与该盒子重叠的 Unit,并返回这些 Unit 组成的列表。可选的 overlapParams 用于控制哪些对象参与本次查询。

⚙ cframe 必须传 CFrame;不要把 Quaternion 作为 CFrame.FromMatrix 的基向量参数。当前运行包可能在首次桥接 CFrame 时写 warning,但查询仍会返回数组。

参数类型说明
cframeCFrameOBB位姿
sizeVector3OBB尺寸
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&lt;Unit&gt; (AABB与球重叠的Unit列表)

以 position 为球心、radius 为半径构造球形查询范围,查询包围盒与该球重叠的 Unit,并返回这些 Unit 组成的列表。可选的 overlapParams 用于控制哪些对象参与本次查询。

参数类型说明
positionVector3球心位置
radiusFloat球半径
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))
end

GetPartsInPart ​

签名:GetPartsInPart(part: Unit, overlapParams?: OverlapParams) -> Array&lt;Unit&gt; (与part碰撞形状精确重叠的Unit列表)

以作为参数的 Unit 的碰撞形状为基准进行重叠查询,返回与该形状精确重叠的 Unit 列表。可选的 overlapParams 用于控制哪些对象参与本次查询。

参数类型说明
partUnit参与检测的参考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()