當兩個 3D 物件在 3D 世界中接觸時,會發生碰撞。對於自定义的碰撞處理,BasePart 有一組 碰撞事件 和 碰撞過濾 技巧,因此您可以控制哪些物理裝配會與其他裝配碰撞。
碰撞事件
當兩個 BaseParts 在 3D 世界中相碰或停止相碰時,會發生碰撞事件 **** 您可以通過 Touched 和 TouchEnded 發生的事件偵測這些碰撞,無論哪一方的 CanCollide 屬性值是否相同。當考慮零件的碰撞處理時,請注意以追蹤中事項:
- 零件的 CanCollide 屬性會影響它是否會與其他零件 物理 碰撞並導致力量對它們作用。即使在某個部分禁用了 CanCollide,您也可以通過 Touched 和 TouchEnded 事件偵測到觸摸和非觸摸。
已觸摸
當 Touched 事件發生時,會與另一個 BasePart 或 地形 氣體接觸。它只會在 物理模擬 的結果發射,並不會在零件的 Position 或 CFrame 被明確設置為與另一個零件或體素交叉時發射。
以下代碼模式顯示了如何將 Touched 事件連接到自定义 onTouched() 函數。請注意,事件會將 otherPart 參數傳送給函數,表示另一個參與碰撞的部分。
零件碰撞
local Workspace = game:GetService("Workspace")
local part = Workspace.Part
local function onTouched(otherPart)
print(part.Name .. " collided with " .. otherPart.Name)
end
part.Touched:Connect(onTouched)
請注意, 事件可以根據微妙的物理碰撞快速連續發射多次,例如當移動物體"定居"到休息位置或當碰撞涉及多個零件模型時。為了避免觸發超過必要的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 .. " collided with " .. otherPart.Name)
part:SetAttribute("Touched", true) -- 將特性設為真值
task.wait(COOLDOWN_TIME) -- 等待冷卻時間
part:SetAttribute("Touched", false) -- 重設特性
end
end
part.Touched:Connect(onTouched)
已結束觸摸
當 TouchEnded 事件發生時,整個碰撞邊界的 BasePart 退出另一個 BasePart 或已填滿的 地形 體素時,將發生事件。它只會在物理模擬 的結果發射 ,並且不會在零件的Position或CFrame被明確設置為停止與另一個零件或體素交叉時發射。
以下代碼模式顯示了如何將 TouchEnded 事件連接到自定义 onTouchEnded() 函數。像 Touched 一樣,事件會將 otherPart 參數傳送給函數,表示另一個參與的部分。
非碰撞偵測
local Workspace = game:GetService("Workspace")
local part = Workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " is no longer touching " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)
碰撞過濾
碰撞 過濾 定義哪些物理部件會與其他部件碰撞。您可以通過 衝突群 配置數個對象的過濾,或者可以通過 零件對零件 基礎控制衝突,使用 個實例。
衝突群組
碰撞 群組 讓您指派 BaseParts 給專用群組,並指定是否與其他群組的碰撞。非碰撞群中的零件完全穿過對方,即使兩個零件的 CanCollide 屬性都設為 true 。
您可以通過 Studio 的 碰撞群組編輯器 設置碰撞群組,可以通過點擊工具欄的 碰撞群組 按鈕來訪問。

編輯器在 列檢視 中運行,這會使 靠左側或右側停靠 到 Studio,或在更廣泛的 表檢視 中,這會使停靠向上或向下。

註冊群組
編輯器包含一個 預設 碰撞群組,無法重命名或刪除。所有 BaseParts 自動屬於此預設群組,除非指定到另一個群組,否則意味著它們將與 預設 群組中的所有其他對象碰頭。
要創建新的碰撞群組:
點擊編輯器面板頂部的 添加群組 按鈕,輸入新的群組名稱,然後按下 Enter 。新群組出現在列表檢視的兩個列或表檢視的左列和上行中。
如有需要,重複此過程,選擇每個群組獨特且具有描述性的名稱。請注意,您可以在開發期間變更群組名稱,點擊其欄位,或選擇它並點擊 重命名 按鈕。
配置群組碰撞
在預設配置下,所有群組中的對象會相互碰撞。為了防止一個群組中的物件與另一個群組中的物件發生碰撞, 取消 在相應行/列中的方塊勾選。
在下面的例子中,立方體群組中的對象不會與門群組中的對象碰撞。

將對象分配給群組
若要將對象分配給你已註冊的群組:
選擇一個或多個 BaseParts 符合衝突群組一部分的資格。
通過點擊其行的 ⊕ 按鈕將它們分配給該群組。物件只能屬於一個衝突群組,一次,因此將它們放置在新的群組中會將它們從目前的群組中移除。
一旦分配,新群組將在對物件的 CollisionGroup 屬性下反映。

可選擇的衝突群組工作室
工作室中的工具使用衝突過濾系統來確定哪些對象是候選對象,當單擊3D視角時。其指定的碰撞群不與 StudioSelectable 碰撞的物件將被忽略。
例如,如果你有一個競賽體驗中的檢查點的有效區域由大型透明零件定義,你可以將它們分配給一個 檢查點 碰撞集群,然後使該集群與 StudioSelectable 不可碰撞,以便它們在編輯基礎地圖幾何時不會擋路。

對於插件代碼,建議您在尋找鼠標下的零件時,將 指定為碰撞群過濾器,當尋找零件時。這樣可以讓您的插件與創作者習慣使用內置 Studio 工具的選擇機制相匹配。
建議的插件選擇射線投射
local UserInputService = game:GetService("UserInputService")local Workspace = game:GetService("Workspace")local raycastParams = RaycastParams.new()raycastParams.CollisionGroup = "StudioSelectable" -- 遵循慣例raycastParams.BruteForceAllSlow = true -- 因此可以選擇「false」的 CanQuery 零件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")
local CollisionGroupName = "Characters"
PhysicsService:RegisterCollisionGroup(CollisionGroupName)
PhysicsService:CollisionGroupSetCollidable(CollisionGroupName, CollisionGroupName, false)
local function setCollisionGroup(model)
-- 將碰撞群應用於模型中所有現有零件
for _, descendant in model:GetDescendants() do
if descendant:IsA("BasePart") then
descendant.CollisionGroup = CollisionGroupName
end
end
end
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
setCollisionGroup(character)
end)
-- 如果玩家已經有角色,立即應用衝突群組
if player.Character then
setCollisionGroup(player.Character)
end
end)
模型碰撞
Model 對象是用來容納零件的容器,而不是從 BasePart 中繼承,因此無法直接連接到 BasePart.Touched 或 BasePart.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, "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 (由 實體建模 連接的零件)是 BasePart 的子類,因此網格和實體建模的零件繼承了與普通零件相同的 碰撞事件 和 碰撞過濾選項 。然而,由於網格和模型零件通常具有更複雜的幾何形狀,因此它們具有一種獨特的 CollisionFidelity 屬性,決定物理邊界與視覺表示的碰撞處理精確度。
CollisionFidelity 屬性有以下選項,從低到高的順序是:
- 盒子 — 創建一個綁定碰撞方塊,適合小或非互動對象。
- 船體 —生成凸起的船體,適合具有較少凹陷或空洞的對象。
- 預設 — 生產大約碰撞形狀,支持凹陷,適合具有半細節化互動需求的複雜對象。
- 精確凸起分解 — 提供最精確的忠實度,但仍不是視覺的 1:1 表示。此選項的性能成本最高,需要更長時間才能讓引擎計算。

要了解有關碰撞穩定性選項的性能影響以及如何應對它們的更多信息,請參閱性能最佳化。