在 3D 世界中,两个 3D 对象接触时发生碰撞。为了自定义碰撞处理,BasePart 有一个组合包含碰撞事件和碰撞过滤器技术,您可以控制哪些物理组合与其他人相互碰撞。
碰撞事件
在 3D 世界中触摸两个 BaseParts 时发生碰撞事件。您可以通过 Touched 和 1> Class.BasePart.TouchEnded|TouchEnded
- Class.BasePart.Touched|Touched 和 TouchEnded 事件仅发生在 物理 移动结果,而不是从1> Class.BasePart.Position|Position1> 或4> Class.BasePart.CFrame|CFrame4>
已触摸
Class.BasePart.Touched|Touched 事件发生,当一个 Class.BasePart 与另一个 地形 碰触时,它只会发射作为结果 of1> 物理模拟
下面的代码示例显示了如何将 Touched 事件连接到自定义 onTouched() 函数。注意,事件将 otherPart 参数发送到函数,表示其他部分参与了碰撞。
部件碰撞
local part = workspace.Part
local function onTouched(otherPart)
print(part.Name .. " collided with " .. otherPart.Name)
end
part.Touched:Connect(onTouched)
注意,Touched 事件可以在快速成功的顺序发射多次,例如当移动对象“设置”到休息位置或当碰撞涉及<a href="/workspace/reference/engine/datamodel">多重零件模型</a>。
冷却时间与零件碰撞
local part = workspace.Part
local COOLDOWN_TIME = 1
local function onTouched(otherPart)
if not part:GetAttribute("Touched") then
print(part.Name .. " collided with " .. otherPart.Name)
part:SetAttribute("Touched", true) -- 将属性设置为 true
task.wait(COOLDOWN_TIME) -- 等待冷却时间
part:SetAttribute("Touched", false) -- 重置属性
end
end
part.Touched:Connect(onTouched)
触摸已结束
Class.BasePart.TouchEnded|TouchEnded 事件触发,当 BasePart 的整个碰撞边界超出另一个 Class.BasePart
下面的代码示例显示了如何将 TouchEnded 事件连接到自定义 onTouchEnded() 函数。 喜欢 Touched ,该事件将 1> otherPart1> 参数发送到函数,表示参与其他部分。
非碰撞检测
local part = workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " is no longer touching " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)
碰撞过滤器
碰撞 过滤 定义哪些物理部件与其他部件碰撞。您可以通过碰撞群组配置过滤器或通过零件-到-零件基础上控制碰撞。
碰撞群组
碰撞群组 让您将Class.BasePart|BaseParts分配到专用群组,并指定是否与其他群组中的人发生碰撞。 非碰撞群组内的零件通过互相完全通过,即使两个零件的Class.BasePart.CanCollide|CanCollide属性设置为true。
您可以通过 Studio 的 碰撞群组编辑器 轻松设置碰撞群组,该操作可以通过单击 碰撞群组 按钮在 模型 选项卡中访问。
编辑器在 either 列表视图 中使用,这使 Studio 左或右侧的 docking 更有利,或在更宽的 桌子视图 中使用,这使 Studio 的 docking 更有利。
注册群组
编辑器包含一个 默认 碰撞群组,该群组不能被重命名或删除。 所有 BaseParts 都会自动属于此默认群组,除非另一个组分配,否则它们将与其他对象在 默认 群组中碰撞。
要创建一个新的碰撞群组:
点击 添加群组 按钮位于编辑器面板的顶部,输入一个新的群组名称,然后按输入。 新群组会在列表视查看的两个列中,或在左列和上方的行中显查看。
如有必要,请重复此过程,为每个群组选择一个独特且描述性的名称。注意,您可以在开发中通过单击其字段或选择它并单击 重命名 按钮来更改群组的名称。
配置群组碰撞
在默认配置下,所有组中的对象都会相互碰撞。为了防止在一个组中的对象与在另一个群组中的对象碰撞,请在每个行/列中的相应位置/方块中未选择 取消选择 。
在下面的例子中, 方块 组中的对象将不会与 门 群组中的对象碰撞。
将对象分配到群组
要将对象分配到您通过 Studio 编辑器注册的组:
选择一个或多个 BaseParts 可用于碰撞群组的一部分。
将它们分配到群组,单击行为其行为值为 ⊕ 的按钮,对象可以属于一个群组,因此将它们放置在新群组中移除它们从当前群组。
一旦分配,新组将被反射在对象的 CollisionGroup 属性下。
StudioSelectable 碰撞组
在 Studio 中,工具使用碰撞过滤器系统来确定在 3D 视图中单击时哪些对象是候选人,当单击 3D 视窗时,对象的分配碰撞组不会 不 与 StudioSelectable 一起碰撞。
例如,如果您在赛车体验中拥有检查点,其有效区域由大型透明部件定义,您可以将其分配到 检查点 碰撞组,然后使用 StudioSelectable 使该组不可碰撞,以便在编辑底部地图几何时不会阻塞。
对于插件验证码,建议您将 "StudioSelectable" 作为您找到零件时在 RaycastParams 下的冲突组过滤器时使用。这允许您的插件匹配创建者期望从内置 Studio 工具中期待的选择机制。
推荐插件选择射线投射
local UserInputService = game:GetService("UserInputService")local raycastParams = RaycastParams.new()raycastParams.CollisionGroup = "StudioSelectable" -- 要遵循这个规则raycastParams.BruteForceAllSlow = true -- 可以选择" false" 的零件local mouseLocation = UserInputService:GetMouseLocation()local mouseRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)local filteredSelectionHit = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 10000, raycastParams)
零件到零件过滤
要防止两个特定零件之间的碰撞,而不设置 碰撞群组,例如在车轮和其他部件之间,请考虑 无碰撞 约束。优势包括:
- 不需要碰撞群组和/或配置脚本,因此您可以轻松创建并共享具有自定义碰撞过滤器的模型。
- 连接的零件不会相互碰撞,但它们仍然可以与其他对象碰撞。
禁用角色碰撞
Roblox 玩家角色默认会相互碰撞。这可能会导致有趣但不是有意图的游戏行为,例如角色跳上 друг друга来达到特定区域。 如果此行为不是您想要的,您可以通过以下 Script 在 ServerScriptService 中禁止它。
脚本 - 禁用角色碰撞
local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")
PhysicsService:RegisterCollisionGroup("Characters")
PhysicsService:CollisionGroupSetCollidable("Characters", "Characters", false)
local function onDescendantAdded(descendant)
-- 为任何后代设置碰撞组
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "Characters"
end
end
local function onCharacterAdded(character)
-- 处理现有和新的子代物理设置
for _, descendant in character:GetDescendants() do
onDescendantAdded(descendant)
end
character.DescendantAdded:Connect(onDescendantAdded)
end
Players.PlayerAdded:Connect(function(player)
-- 检测玩家角色添加时间
player.CharacterAdded:Connect(onCharacterAdded)
end)
模型碰撞
Model 对象是从 BasePart 继承的容器,因此它们不能直接连接到 BasePart.Touched 或 0>Class.BasePart
下面的代码示例连接所有 BaseParts 的多重零件模型到碰撞事件并跟踪总共有多少碰撞次数。
模型碰撞
local model = script.Parent
local numTouchingParts = 0
local function onTouched(otherPart)
-- 忽略与自己交叉的模型实例
if otherPart:IsDescendantOf(model) then return end
-- 增加触摸模型零件的数量
numTouchingParts += 1
print(model.Name, "intersected with", otherPart.Name, "| Model parts touching:", numTouchingParts)
end
local function onTouchEnded(otherPart)
-- 忽略模型与自身不相交的实例
if otherPart:IsDescendantOf(model) then return end
-- 减少触摸模型零件的数量
numTouchingParts -= 1
print(model.Name, "un-intersected from", otherPart.Name, "| Model parts touching:", numTouchingParts)
end
for _, child in model:GetChildren() do
if child:IsA("BasePart") then
child.Touched:Connect(onTouched)
child.TouchEnded:Connect(onTouchEnded)
end
end
网格和固体模型碰撞
MeshPart 和 PartOperation (由 固定建模 加入的零件) 是 0> Class.BasePart
Class.TriangleMeshPart.CollisionFidelity|CollisionFidelity 属性有以下选项,从低到高,从稳定性到最佳性能影响的顺序:
- 箱子 — 创建一个限定碰撞方块,对于小型或非交互对象非常适合。
- 船体 — 生成一个凹陷度较小的船体,适合用于有较小的间隙或空腔的对象。
- 默认 — 生成一个约形状,该形状支持凹陷,适合具有半透明交互需求的复杂对象。
- 精确矢量分解 — 提供最精确的忠实度,但仍然不是 1:1 的视觉表示。此选项的性能成本最高,且需要更长的时间才能计算。
了解有关碰撞精确度选项的性能影响和如何减缓它们的影响,请参阅性能优化。了解有关选择碰撞精确度选项以平衡您的精确度需求和性能要求的深度走through,请参阅这里。