碰撞

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

碰撞發生在兩個 3D 物體在 3D 世界中接觸時。為了自定義碰撞處理,BasePart 提供了一組 碰撞事件碰撞過濾 技術,您可以控制哪些物理組件與其他組件發生碰撞。

碰撞事件

碰撞 事件 發生在兩個 BaseParts 在 3D 世界中接觸或停止接觸時。您可以通過 TouchedTouchEnded 事件來檢測這些碰撞,這些事件會在任何一部分的 CanCollide 屬性值下觸發。在考慮部分的碰撞處理時,請注意以下幾點:

  • 一個部分的 CanTouch 屬性決定它是否觸發碰撞事件。如果設置為 false,則 TouchedTouchEnded 都不會觸發。
  • 一個部分的 CanCollide 屬性影響它是否會與其他部分 物理 碰撞並導致力量作用於它們。即使對於一個部分禁用 CanCollide,仍然可以通過 TouchedTouchEnded 事件來檢測接觸和非接觸。
  • TouchedTouchEnded 事件僅僅因 物理 移動而觸發,而不是因為 PositionCFrame 的變化導致一個部分與另一個部分交叉或停止交叉。
  • 頂層的 Terrain 類別從 BasePart 繼承,因此您可以將 碰撞組 分配給 Terrain,以決定其他 BaseParts 是否與 Terrain 鬆散的體素發生碰撞。

Touched

Touched 事件在 BasePart 與另一個部分或 Terrain 鬆散的體素接觸時觸發。它僅因 物理模擬 而觸發,當該部分的 PositionCFrame 被明確設置為使其與另一部分或鬆散的體素交叉時不會觸發。

以下代碼模式顯示了如何將 Touched 事件連接到自定義 onTouched() 函數。請注意,事件會將 otherPart 參數傳遞給函數,指示參與碰撞的另一部分。

部件碰撞

local Workspace = game:GetService("Workspace")
local part = Workspace.Part
local function onTouched(otherPart)
print(part.Name .. " 與 " .. otherPart.Name .. " 發生碰撞")
end
part.Touched:Connect(onTouched)

請注意,Touched 事件可能會因微小的物理碰撞而快速多次觸發,例如當一個移動的物體“穩定”在靜止位置中或當一個碰撞涉及 多部分模型 時。為了避免觸發多於必要的 Touched 事件,您可以實現一個簡單的防抖系統,通過實例 屬性 強制實施“冷卻”時間。

帶冷卻的部件碰撞

local Workspace = game:GetService("Workspace")
local part = Workspace.Part
local COOLDOWN_TIME = 1
local function onTouched(otherPart)
if not part:GetAttribute("Touched") then
print(part.Name .. " 與 " .. otherPart.Name .. " 發生碰撞")
part:SetAttribute("Touched", true) -- 將屬性設置為 true
task.wait(COOLDOWN_TIME) -- 等待冷卻時間
part:SetAttribute("Touched", false) -- 重置屬性
end
end
part.Touched:Connect(onTouched)

TouchEnded

TouchEnded 事件在整個 BasePart 的碰撞邊界離開另一個 BasePart 或填滿的 Terrain 鬆散體素的邊界時觸發。它僅因 物理模擬 而觸發,當該部分的 PositionCFrame 被明確設置使其停止與另一部分或鬆散體素交叉時不會觸發。

以下代碼模式顯示了如何將 TouchEnded 事件連接到自定義 onTouchEnded() 函數。與 Touched 一樣,事件會將 otherPart 參數發送給該函數,指示涉及的另一部分。

非碰撞檢測

local Workspace = game:GetService("Workspace")
local part = Workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " 不再接觸 " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)

碰撞過濾

碰撞 過濾 定義了哪些物理部分與其他部分發生碰撞。您可以通過 碰撞組 配置多個物件的過濾,或使用 NoCollisionConstraint 實例控制 部件對部件 的碰撞。

碰撞組

碰撞 讓您將 BaseParts 分配給專用組,並指定它們是否與其他組中的物件發生碰撞。位於不發生碰撞組中的部分會完全穿透彼此,即使兩個部分的 CanCollide 屬性設置為 true

在上面視頻中,旋轉的物體位於不同的碰撞组中,因此它們會與其他顏色的物體發生碰撞,但不會與自己顏色的物體發生碰撞

您可以輕鬆通過 Studio 的 碰撞組 編輯器來設置碰撞組,該編輯器可以通過 Studio 的 窗口 ⟩ 3D 菜單訪問。

編輯器支援 列表視圖,更適合 停靠 在 Studio 的左側或右側,或支援更寬的 表格視圖,更適合停靠在頂部或底部。

碰撞組編輯器中的列表視圖示例

註冊組

編輯器包括一個 默認 碰撞組,該組無法重新命名或刪除。所有 BaseParts 默認屬於此組,除非分配給其他組,這意味著它們將與 默認 組中的所有其他物件發生碰撞。

要創建新的碰撞組:

  1. 點擊編輯器面板頂部的 添加組 按鈕,輸入新組名稱並按 Enter。新組顯示在列表視圖的兩個列中,或在表格視圖的左列和上行中。

    在列表視圖的碰撞組編輯器中添加的新組
  2. 如有必要,重複該過程,為每個組選擇唯一且具描述性的名稱。請注意,您可以通過單擊其字段來變更組的名稱,或通過選擇它並單擊 重新命名 按鈕進行更改。

    在碰撞組編輯器中指示重新命名組的按鈕和字段

配置組碰撞

在默認配置下,所有組中的物件相互之間會發生碰撞。要防止一組中的物件與其他組中的物件發生碰撞,取消選中 相應行/列中的方框。

在以下示例中,Cubes 組中的物件將 Doors 組中的物件發生碰撞。

在碰撞組編輯器的列表視圖中配置的組

將物件指派給組

要通過 Studio 編輯器將物件指派給您 註冊的 碰撞組:

  1. 選擇一個或多個符合碰撞組條件的 BaseParts

  2. 通過單擊其行的 按鈕將它們分配給該組。物件一次只能屬於一個碰撞組,因此將它們放入新組中會將它們從當前組中移除。

    在碰撞組編輯器中指示選擇的部分添加到組的加號按鈕

一旦分配,新的組會在物件的 CollisionGroup 屬性下顯示。

作為部件的 CollisionGroup 屬性指示的所選碰撞組

StudioSelectable 碰撞組

Studio 中的工具使用碰撞過濾系統來確定在 3D 檢視區中單擊時哪些物件是可選的。指派的碰撞組不與 StudioSelectable 碰撞的物件將被忽略。

例如,如果您在賽車體驗中有檢查點,其有效區域由大型透明部件定義,您可以將它們指派給 Checkpoints 碰撞組,然後使該組與 StudioSelectable 不可碰撞,以便在編輯基於地圖的幾何體時不會妨礙操作。

配置為與 StudioSelectable 組不可碰撞的檢查點組

對於插件代碼,建議您在使用游標查找部件時將 "StudioSelectable" 指派為 RaycastParams 的碰撞組過濾器。這使得您的插件能夠匹配創作者從內建 Studio 工具學習到的選擇機制。

推薦的插件選擇射線

local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
local raycastParams = RaycastParams.new()
raycastParams.CollisionGroup = "StudioSelectable" -- 遵循這個約定
raycastParams.BruteForceAllSlow = true -- 這樣 CanQuery 為 "false" 的部件也可以被選中
local mouseLocation = UserInputService:GetMouseLocation()
local mouseRay = Workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local filteredSelectionHit = Workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 10000, raycastParams)

部件對部件過濾

要防止兩個特定部件之間的碰撞而不設置 碰撞組,例如車輛的輪子和車身之間的碰撞,請考慮使用 No Collision 約束。優勢包括:

  • 不需要碰撞組和/或配置腳本,因此您可以輕鬆創建和共享具有自定義碰撞過濾的模型。
  • 連接的部件將不會相互碰撞,但仍然可以與其他對象碰撞。

禁用角色碰撞

Roblox 玩家角色預設會相互碰撞。這可能導致有趣但意想不到的遊玩體驗,例如角色跳在一起以到達特定區域。如果不希望這種行為,您可以通過以下 ScriptServerScriptService 中防止它。

腳本 - 禁用角色碰撞

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.TouchedBasePart.TouchEnded 事件。要確定模型是否觸發碰撞事件,您需要遍歷它的子項並將自定義 onTouched()onTouchEnded() 函數連接到每個子 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, "與", otherPart.Name, "發生交叉 | 模型部件接觸:", numTouchingParts)
end
local function onTouchEnded(otherPart)
-- 忽略模型與自己不再交叉的實例
if otherPart:IsDescendantOf(model) then return end
-- 減少與模型部件接觸的計數
numTouchingParts -= 1
print(model.Name, "與", otherPart.Name, "不再交叉 | 模型部件接觸:", numTouchingParts)
end
for _, child in model:GetChildren() do
if child:IsA("BasePart") then
child.Touched:Connect(onTouched)
child.TouchEnded:Connect(onTouchEnded)
end
end

網格和實體模型碰撞

MeshPartPartOperation(通過 實體建模 連接的部件)是 BasePart 的子類,因此網格和實體建模的部件繼承與普通部件相同的 碰撞事件碰撞過濾 選項。然而,由於網格和實體建模的部件通常具有更複雜的幾何形狀,因此它們具有獨特的 CollisionFidelity 屬性,用於確定物理邊界與視覺表示之間在碰撞處理方面的精確對齊程度。

CollisionFidelity 屬性具有以下選項,根據精確度與性能影響從低到高排序:

  • Box — 創建包圍碰撞框,適合於小型或非交互式物體。
  • Hull — 生成一個凸包,適合於邊緣不明顯的物體。
  • Default — 生成近似的碰撞形狀,支持凹面,適合於具有半詳細交互需求的複雜物體。
  • PreciseConvexDecomposition — 提供最精確的精度,但仍不是視覺的 1:1 表現。此選項的性能成本最高,並且更耗時。
城堡塔的原始網格

有關碰撞精度選項的性能影響及如何減少其影響的更多信息,請參見 性能優化

©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。