衝突は、2つの3Dオブジェクトが3D空間内で接触する際に発生します。カスタマイズされた衝突処理のために、BasePartには一連の衝突イベントと衝突フィルタリング技術があり、どの物理アセンブリが他と衝突するかを制御できます。
衝突イベント
衝突イベントは、2つのBasePartsが3D空間で接触したり、接触を停止したりする際に発生します。これらの衝突は、TouchedおよびTouchEndedイベントを通じて検出できます。これらのイベントは、いずれかのパートのCanCollideプロパティの値に関係なく発生します。パーツの衝突処理を考慮する際は、以下の点に注意してください。
- パーツのCanCollideプロパティは、他のパーツと物理的に衝突するかどうかに影響します。たとえCanCollideが無効になっていても、TouchedおよびTouchEndedイベントを通じて接触と非接触を検出できます。
- TouchedおよびTouchEndedイベントは、物理的な動きの結果としてのみ発火し、パーツのPositionやCFrameの変更によって他のパーツと交差したり、交差を停止したりする場合には発火しません。
Touched
Touchedイベントは、BasePartが他のパーツまたはTerrainボクセルと接触したときに発火します。このイベントは物理シミュレーションの結果としてのみ発火し、パーツのPositionやCFrameが明示的に設定されて他のパーツやボクセルと交差する場合には発火しません。
以下のコードパターンは、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ボクセルの範囲を出たときに発火します。このイベントは物理シミュレーションの結果としてのみ発火し、パーツのPositionやCFrameが明示的に設定されて他のパーツやボクセルとの交差を停止する場合には発火しません。
以下のコードパターンは、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に設定していても、完全に通過します。
スタジオの衝突グループエディタを通じて、衝突グループを簡単に設定できます。これはスタジオのウィンドウ ⟩ 3Dメニューからアクセスできます。
エディタは、スタジオの左側または右側にドッキングすることを好むリスト ビューまたは、上部または下部にドッキングすることを好む広いテーブル ビューのいずれかで機能します。

グループの登録
エディタには、名前を変更したり削除したりできないデフォルトの衝突グループが1つ含まれています。すべてのBasePartsは、他のグループに割り当てられない限り、このデフォルトグループに自動的に属し、デフォルトグループ内の他のすべてのオブジェクトと衝突します。
新しい衝突グループを作成するには:
エディタパネルの上部にあるグループを追加ボタンをクリックし、新しいグループ名を入力してEnterを押します。新しいグループはリストビューの両方の列、またはテーブルビューの左列と上部の行の両方に表示されます。

必要に応じてこのプロセスを繰り返し、各グループにユニークで説明的な名前を選択します。開発中にグループの名前を変更するには、そのフィールドをクリックするか、選択して名前を変更ボタンをクリックします。

グループの衝突を構成する
デフォルトの構成では、すべてのグループ内のオブジェクトは互いに衝突します。1つのグループ内のオブジェクトが別のグループのオブジェクトと衝突しないようにするには、該当する行/列のボックスのチェックを外します。
以下の例では、CubesグループのオブジェクトはDoorsグループのオブジェクトと衝突しません。

オブジェクトをグループに割り当てる
登録したグループにオブジェクトを割り当てるには、スタジオエディタを通じて次の手順を実行します:
衝突グループの一部として適格な1つ以上のBasePartsを選択します。
行の**⊕**ボタンをクリックしてグループに割り当てます。オブジェクトは一度に1つの衝突グループにしか属せないため、新しいグループに配置すると現在のグループから削除されます。

割り当てられると、新しいグループはオブジェクトのCollisionGroupプロパティに反映されます。

StudioSelectable衝突グループ
スタジオのツールは、3Dビューポートでクリックしたときにどのオブジェクトが選択候補になるかを決定するために衝突フィルタリングシステムを使用します。割り当てられた衝突グループがStudioSelectableと衝突しないオブジェクトは無視されます。
たとえば、レースゲームのチェックポイントが大きな透明なパーツによって定義されている場合、これらをCheckpoints衝突グループに割り当て、そのグループをStudioSelectableと衝突しないように設定することで、基盤となるマップのジオメトリを編集する際に邪魔にならないようにできます。

プラグインコードでは、カーソルの下にあるパーツを見つける際に、RaycastParamsの衝突グループフィルタとして"StudioSelectable"を割り当てることをお勧めします。これにより、プラグインが組み込みのスタジオツールから期待される選択メカニクスに一致します。
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)パート間フィルタリング
2つの特定のパーツ間の衝突を防ぐために、衝突グループを設定するのではなく、車両のホイールとシャーシの間のように、No Collision制約を考慮してください。利点には以下が含まれます:
- 衝突グループや構成スクリプトは必要ないため、カスタマイズされた衝突フィルタリングを持つモデルを簡単に作成して共有できます。
- 接続されたパーツは互いに衝突しませんが、他のオブジェクトとは衝突できます。
キャラクターの衝突を無効にする
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やBasePart.TouchEndedイベントに直接接続することはできません。モデルが衝突イベントをトリガーするかどうかを判断するには、その子をループして、各子BasePartにカスタムonTouched()およびonTouchEnded()関数を接続する必要があります。
以下のコードサンプルは、マルチパートモデルのすべての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メッシュおよびソリッドモデルの衝突
MeshPartおよびPartOperation(ソリッドモデリングによって結合されたパーツ)はBasePartのサブクラスであるため、メッシュおよびソリッドモデリングされたパーツは通常のパーツと同じ衝突イベントおよび衝突フィルタリングオプションを継承します。ただし、メッシュやソリッドモデリングされたパーツは通常、より複雑なジオメトリを持つため、物理的な境界が視覚的な表現とどれだけ正確に一致するかを決定する独自のCollisionFidelityプロパティがあります。
CollisionFidelityプロパティには、忠実度とパフォーマンスへの影響が低い順に以下のオプションがあります:
- ボックス — 小さなまたは非対話的なオブジェクトに最適なバウンディング衝突ボックスを作成します。
- ハル — 突出した凹みや空洞の少ないオブジェクトに適した凸ハルを生成します。
- デフォルト — 凹面をサポートする近似衝突形状を生成し、半詳細な相互作用ニーズを持つ複雑なオブジェクトに適しています。
- PreciseConvexDecomposition — 最も正確な忠実度を提供しますが、視覚の1:1表現ではありません。このオプションは最も高価なパフォーマンスコストがかかり、エンジンが計算するのに時間がかかります。

衝突忠実度オプションのパフォーマンスへの影響とそれを軽減する方法についての詳細は、パフォーマンス最適化を参照してください。