衝突は、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 part = workspace.Part
local function onTouched(otherPart)
print(part.Name .. " が " .. otherPart.Name .. " と衝突しました")
end
part.Touched:Connect(onTouched)Touchedイベントは、動いているオブジェクトが「落ち着く」位置に収束する際や、マルチパーツモデルが関与する衝突のような微妙な物理的衝突に基づいて、短時間に複数回発火する可能性があります。必要以上にTouchedイベントをトリガーしないようにするために、インスタンス属性を通じて「クールダウン」期間を強制するシンプルなデバウンスシステムを実装できます。
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 part = workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " は " .. otherPart.Name .. " に触れていません")
end
part.TouchEnded:Connect(onTouchEnded)衝突フィルタリング
衝突フィルタリングは、どの物理パーツが他のパーツと衝突するかを定義します。多数のオブジェクトに対してフィルタリングを設定するには衝突グループを使用するか、NoCollisionConstraintインスタンスを使用してパーツ間の衝突を制御できます。
衝突グループ
衝突グループを使用すると、BasePartsを専用のグループに割り当て、他のグループのオブジェクトと衝突するかどうかを指定できます。衝突しないグループ内のパーツは、両方のパーツがCanCollideプロパティをtrueに設定していても、完全に通過します。衝突グループは、WorkspaceまたはWorldModelの単位で作成および構成されます。
スタジオの衝突グループエディタを通じて、衝突グループを簡単に設定できます。このエディタは、スタジオのウィンドウ ⟩ 3Dメニューからアクセスできます。
グループの登録
Workspaceは、自身の構成可能な衝突グループの状態を保存します。さらに、任意のWorldModelは、クエリのために独自の衝突グループを使用することを選択できます。
エディタには、名前を変更したり削除したりできない1つのデフォルト衝突グループが含まれています。すべてのBasePartsは、他のグループに割り当てられない限り、このデフォルトグループに自動的に属し、デフォルトグループ内の他のすべてのオブジェクトと衝突します。
新しい衝突グループを作成するには:
デフォルトでは、グループはWorkspaceに登録されますが、場所に少なくとも1つのWorldModelがある場合、衝突グループエディタの上部に選択ドロップダウンが表示されます。このドロップダウンを使用して、異なるWorldModelインスタンス間で衝突グループを構成します。

任意のWorldModelに対して、ワークスペースの衝突グループを使用をオンに切り替えることで、そのクエリにWorkspaceの衝突グループを使用させることができます。

エディタパネルの上部にあるグループを追加ボタンをクリックし、新しいグループ名を入力してEnterを押します。新しいグループは、リストビューの両方の列またはテーブルビューの左列と上部の行に表示されます。

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

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

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

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

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

プラグインコードでは、カーソルの下にあるパーツを見つける際に、RaycastParamsの衝突グループフィルタとして"StudioSelectable"を割り当てることをお勧めします。これにより、プラグインがクリエイターが組み込みのスタジオツールから期待する選択メカニクスに一致するようになります。
local UserInputService = game:GetService("UserInputService")
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 Players = game:GetService("Players")
workspace:RegisterCollisionGroup("Characters")
workspace: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プロパティには、忠実度とパフォーマンスへの影響が低い順から高い順に以下のオプションがあります。
- ボックス — 小さなまたは非対話型のオブジェクトに最適なバウンディング衝突ボックスを作成します。
- ハル — 突出した凹みや空洞の少ないオブジェクトに適した凸包を生成します。
- デフォルト — 凹面をサポートする近似衝突形状を生成し、半詳細な相互作用ニーズを持つ複雑なオブジェクトに適しています。
- 精密凸分解 — 最も正確な忠実度を提供しますが、視覚的表現の1:1の表現ではありません。このオプションは最も高価なパフォーマンスコストがかかり、エンジンが計算するのに時間がかかります。

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