3D 拖曳檢測器

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

DragDetector 實例促進並鼓勵與體驗中的 3D 物件互動,例如開門和抽屜、滑動部分、抓取和拋擲保齡球、拉回和發射彈弓等等。主要功能包括:

  • 在任何 BasePartModel 下放置 DragDetector使其可拖曳,通過所有輸入(滑鼠、觸控、遊戲控制器和 VR),完全不需要一行代碼。

  • 從幾種 拖曳樣式 中選擇,定義物件如何 對動作的反應,並可以選擇性地應用 軸或移動限制

  • 腳本可以 響應對拖曳物件的操作 以驅動 UI 或做出邏輯決策,例如根據滑動牆開關調暗房間的光線。

  • 玩家可以操作固定的部分或模型,並且當釋放時,它們會保持在您放置的位置。

  • DragDetectors 在 Studio 中運行,只要您 使用 選取移動縮放旋轉 工具,這使得在編輯時測試和調整可拖曳物件變得更加容易。

使物件可拖曳

要使任何部分或模型可拖曳,只需在其下添加 DragDetector 作為直接子項。

  1. 資源管理器 窗口中,將鼠標懸停在 PartMeshPartModel 上,然後單擊 ⊕ 按鈕。將顯示上下文菜單。

  2. 從菜單中插入一個 DragDetector

  3. 默認情況下,物件現在將在地面平面中可拖曳,但您可以自定義其 DragStyle,定義其對 運動的反應,並可以選擇性地應用 軸或移動限制

自定義拖曳檢測器

拖曳樣式

DragDetectors 將游標運動映射到虛擬線條和平面,以計算擬議的 3D 運動。通過 DragStyle 屬性,可以從不同的映射中選擇,以滿足您的需求。例如,TranslatePlane 在虛擬平面上產生平移,而 RotateAxis 則圍繞虛擬軸旋轉。

設置描述
TranslateLine沿檢測器的 Axis 進行 1D 運動,默認為世界 Y 軸。
TranslatePlane在垂直於檢測器的 Axis 的平面中進行 2D 運動,默認為世界 XZ 平面。
TranslatePlaneOrLine在垂直於檢測器的 Axis 的平面中進行 2D 運動,以及在激活 修飾符 時,沿檢測器的 Axis 進行 1D 運動。
TranslateLineOrPlane沿檢測器的 Axis 進行 1D 運動,以及在激活 修飾符 時,在垂直於檢測器的 Axis 的平面中進行 2D 運動。
TranslateViewPlane在與相機視圖垂直的平面中進行 2D 運動。在此模式下,即使在拖曳時,該平面也不斷更新,並將始終面向相機的當前視圖。
RotateAxis圍繞檢測器的 Axis 進行旋轉,默認為世界 Y 軸。
RotateTrackballTrackball 旋轉,可以通過 TrackballRadialPullFactorTrackballRollFactor 屬性進一步自定義。
BestForDevice鼠標和遊戲控制器為 TranslatePlaneOrLine;觸控為 TranslatePlane;VR 為 6DOF
Scriptable通過 SetDragStyleFunction() 提供的自定義函數計算所需的運動。

拖曳方向

默認情況下,3D 運動和相關的 DragStyle 映射到世界空間。然而,您可能希望改變 ReferenceInstanceOrientationAxis,例如在將拖曳檢測器構建到具有可調部件的 模型 時。

屬性描述默認
ReferenceInstance提供 參考幀 的樞紐實例。DragFrame 參照此參考幀來表示。如果參考幀為 nil,則平移將在世界空間中沿著(或在垂直於)Axis 屬性進行。nil
Orientation指定相對於參考幀的運動軸的 YXZ 旋轉(不改變參考幀本身的方向)。線性平移和軸旋轉將在此重新定義的 Y 軸上進行,平面平移將在 XZ 平面上進行。更改此值會自動更新 Axis,反之亦然。(0, 0, 0)
Axis主要運動軸,以參考幀為基準來表示。更改此值會自動更新 Orientation,反之亦然。(0, 1, 0)

對運動的反應

ResponseStyle 屬性指定物件如何對擬議的運動作出反應,取決於該物件是否 Anchored

設置固定行為非固定行為
Geometric在運行體驗和 Studio 編輯模式下,固定物件的位置/方向將被更新為精確反映擬議的運動。對於未固定的物件,其行為與固定物件相同。然而,在運行體驗中,物件將在拖曳開始時被固定,並在拖曳釋放時恢復為未固定狀態。
Physical固定物件將默認為 Geometric 行為,因為它不受力的影響。未固定的物件將受到 約束力 的影響,這將試圖將其移動到擬議的運動所給定的位置和/或方向。
Custom該物件將完全不移動,但 DragFrame 仍然會被更新,您可以根據自己的意願 響應拖曳操作(與固定相同)

軸和移動限制

默認情況下,3D 運動沒有任何限制,僅受 DragStyle 的內在限制。如果需要,您可以對平移和旋轉應用最小和最大限制。請注意,這些不是約束;它們僅僅妨礙拖曳檢測器生成運動的嘗試,以保持在限制之內。

屬性描述默認

MinDragTranslation
MaxDragTranslation

限制每個維度的拖曳平移。如果 MaxDragTranslation 大於 MinDragTranslation,則平移將被限制在該範圍內。(0, 0, 0)

MinDragAngle
MaxDragAngle

僅在 DragStyle 設定為 RotateAxis 時相關。如果 MaxDragAngle 大於 MinDragAngle,則旋轉將被限制在該範圍內。0

拖曳權限

玩家對特定拖曳檢測器實例的互動權限可以通過 PermissionPolicy 屬性指定。默認設置為 Enum.DragDetectorPermissionPolicy.Everybody,也可以更改為支持腳本化的權限控件,如代碼範例所示。

設置描述
Nobody沒有玩家可以與 DragDetector 互動。
Everybody所有玩家都可以與 DragDetector 互動。
Scriptable玩家的拖曳權限將由通過 SetPermissionPolicyFunction() 註冊的函數來決定。在此設置下,未能註冊函數或返回無效結果將阻止所有玩家拖曳。
DragDetector - 腳本化拖曳權限

local dragDetector = script.Parent.DragDetector
dragDetector.PermissionPolicy = Enum.DragDetectorPermissionPolicy.Scriptable
dragDetector:SetPermissionPolicyFunction(function(player, part)
if player and player:GetAttribute("IsInTurn") then
return true
elseif part and not part:GetAttribute("IsDraggable") then
return false
else
return true
end
end)

物理響應

假定拖動者的 響應樣式 設定為 Physical,並且應用於一個未固定的物件,該物件將受到約束力的影響,這些約束力將試圖將其移動到擬議運動所給定的位置/方向。您可以通過以下屬性進一步自定義物理響應:

屬性描述默認
ApplyAtCenterOfMass為 false 時,拖曳力應用於用戶點擊的點。為 true 時,力應用於物件的質量中心。false
MaxForce物件到達其目標的最大施加力。10000000
MaxTorque物件到達其目標的最大施加扭矩。10000
Responsiveness更高的值會使物件更快達到其目標。10

修飾符輸入

一些 DragStyle 模式允許用戶按住 修飾符 鍵/按鈕,以以不同方式操作拖曳的物件。默認情況下,修飾符在 PC 上為 LeftControl,在遊戲控制器上為 ButtonR1,在 VR 上為 ButtonL2。您可以通過拖曳檢測器實例的 KeyboardModeSwitchKeyCodeGamepadModeSwitchKeyCodeVRSwitchKeyCode 屬性自定義這些修飾符。

複製

RunLocally 屬性為 false(默認)時,客戶端解釋所有輸入以生成數據並將其發送到伺服器以進行拖曳。在此模式下,所有自定義事件信號和註冊的函數必須在伺服器的 Scripts 中。

RunLocally 屬性為 true 時,所有事件都不會複製到伺服器。所有自定義事件信號和註冊的函數必須在客戶端的 LocalScripts 中,並且必須使用 遠程事件 來將必要的更改傳播到伺服器。

腳本響應於點擊和拖曳

通過 事件信號、屬性變更、Scriptable 拖曳樣式和自定義函數,腳本可以對拖曳物件的操作作出響應,以驅動 UI 或做出邏輯決策,例如根據滑動牆開關調整房間的光線水平。

事件信號

通過以下事件信號,您可以檢測用戶何時開始、繼續及結束拖曳物件。

事件描述
DragStart當用戶開始拖曳物件時觸發。
DragContinue當用戶在 DragStart 被觸發後繼續拖曳物件時觸發。
DragEnd當用戶停止拖曳物件時觸發。
DragDetector - 事件信號

local dragDetector = script.Parent.DragDetector
local highlight = Instance.new("Highlight")
highlight.Enabled = false
highlight.Parent = script.Parent
dragDetector.DragStart:Connect(function()
highlight.Enabled = true
end)
dragDetector.DragContinue:Connect(function()
end)
dragDetector.DragEnd:Connect(function()
highlight.Enabled = false
end)

拖曳框架變更

除了 事件信號 外,您還可以直接監控檢測器的 DragFrame 的變化。

DragDetector - DragFrame 變更

local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)

腳本化拖曳樣式

如果您將檢測器的 DragStyle 設定為 Scriptable,您可以提供自己的函數,該函數接受 Ray 並返回世界空間中的 CFrame。檢測器將移動運動,以便拖曳的物件移到該自定義位置/方向。

DragDetector - 腳本化拖曳樣式

local Workspace = game:GetService("Workspace")
local dragDetector = script.Parent.DragDetector
dragDetector.DragStyle = Enum.DragDetectorDragStyle.Scriptable
local cachedHitPoint = Vector3.zero
local cachedHitNormal = Vector3.yAxis
local function followTheCursor(cursorRay)
-- 排除拖曳物件的射線檢測
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {dragDetector.Parent}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local hitPoint = Vector3.zero
local hitNormal = Vector3.yAxis
local raycastResult = Workspace:Raycast(cursorRay.Origin, cursorRay.Direction, raycastParams)
if raycastResult then
hitPoint = raycastResult.Position
hitNormal = raycastResult.Normal.Unit
else
hitPoint = cachedHitPoint
hitNormal = cachedHitNormal
end
cachedHitPoint = hitPoint
cachedHitNormal = hitNormal
local lookDir1 = hitNormal:Cross(Vector3.xAxis)
local lookDir2 = hitNormal:Cross(Vector3.yAxis)
local lookDir = if lookDir1.Magnitude > lookDir2.Magnitude then lookDir1.Unit else lookDir2.Unit
return CFrame.lookAt(hitPoint, hitPoint + lookDir, hitNormal)
end
dragDetector:SetDragStyleFunction(followTheCursor)

自定義約束函數

拖曳檢測器沒有關於網格和吸附的內置運動規則,但您可以註冊自定義約束函數來在應用前編輯檢測器的 DragFrame。例如,您可以通過將位置四捨五入為網格增量的倍數來保持運動在網格上,或模擬棋盤遊戲中的每個棋子的合法運動規則。

DragDetector - 自定義約束函數

local dragDetector = script.Parent.DragDetector
local startPartPosition = nil
local SNAP_INCREMENT = 4
dragDetector.DragStart:Connect(function()
startPartPosition = script.Parent.Position
end)
dragDetector.DragEnd:Connect(function()
startPartPosition = nil
end)
local function snapToWorldGrid(proposedMotion)
if startPartPosition == nil then
return proposedMotion
end
local snapIncrement = SNAP_INCREMENT // 1
if snapIncrement < 1 then
return proposedMotion
end
local newWorldPosition = startPartPosition + proposedMotion.Position
local roundedX = ((newWorldPosition.X / snapIncrement + 0.5) // 1) * snapIncrement
local roundedY = ((newWorldPosition.Y / snapIncrement + 0.5) // 1) * snapIncrement
local roundedZ = ((newWorldPosition.Z / snapIncrement + 0.5) // 1) * snapIncrement
local newRoundedWorldPosition = Vector3.new(roundedX, roundedY, roundedZ)
return proposedMotion.Rotation + (newRoundedWorldPosition - startPartPosition)
end
local connection = dragDetector:AddConstraintFunction(2, snapToWorldGrid)
-- 如果適用,通過調用 connection:Disconnect() 刪除約束函數

示例用法

非固定的物理物件

拖曳檢測器的基本實現是塔平衡遊戲,玩家必須小心地移除物品,並試圖保持塔的直立。在以下塔結構中,每個物件都有一個子 DragDetector,其默認 DragStyleTranslatePlane,以便玩家可以將物品往外拉,但不能往上或往下拉。

具有可調部件的固定模型

您可以輕鬆創建並分享以固定為主的模型,但有一個或多個子部件/模型供玩家拖曳。例如,以下辦公桌具有兩個抽屜,玩家可以打開以檢查裡面的內容。

拖曳檢測器和約束

您可以將拖曳檢測器與 Constraints 組合,例如布偶。在以下設置中,控制把手是固定的,身體部件是未固定的,而約束將布偶連接起來。使用 TranslateViewPlane DragStyle 移動把手使布偶跳舞,並且各個身體部件也可以使用拖曳檢測器進行移動,同時模型保持完整性。

3D 用戶界面

通過拖曳檢測器,3D 用戶界面很容易實現,例如根據滑動開關調整 SpotLight 的亮度。您還可以單獨檢測 XZ 軸,以控制 3D 用戶界面的兩個不同方面,例如 SizeSpeedColorParticleEmitter

DragDetector - 3D 用戶界面

local model = script.Parent
local slider = model.SliderPart
local originPart = model.OriginPart
local emitter = script.Parent.EmitterPart.ParticleEmitter
local dragDetector = slider.DragDetector
dragDetector.ReferenceInstance = originPart
dragDetector.MinDragTranslation = Vector3.zero
dragDetector.MaxDragTranslation = Vector3.new(10, 0, 10)
local dragRangeX = dragDetector.MaxDragTranslation.X - dragDetector.MinDragTranslation.X
local dragRangeZ = dragDetector.MaxDragTranslation.Z - dragDetector.MinDragTranslation.Z
local MIN_PARTICLE_SIZE = 1
local MAX_PARTICLE_SIZE = 1.5
local MIN_PARTICLE_SPEED = 2.5
local MAX_PARTICLE_SPEED = 5
local COLOR1 = Color3.fromRGB(255, 150, 0)
local COLOR2 = Color3.fromRGB(255, 0, 50)
local function updateParticles(emitter)
local dragFactorX = (dragDetector.DragFrame.Position.X - dragDetector.MinDragTranslation.X) / dragRangeX
local dragFactorZ = (dragDetector.DragFrame.Position.Z - dragDetector.MinDragTranslation.Z) / dragRangeZ
-- 根據拖曳檢測器的 X 因子調整粒子大小和速度
emitter.Size = NumberSequence.new{
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(0.1, MIN_PARTICLE_SIZE + ((MAX_PARTICLE_SIZE - MIN_PARTICLE_SIZE) * dragFactorX)),
NumberSequenceKeypoint.new(1, 0)
}
local speed = MIN_PARTICLE_SPEED + ((MAX_PARTICLE_SPEED - MIN_PARTICLE_SPEED) * dragFactorX)
emitter.Speed = NumberRange.new(speed, speed * 1.2)
-- 根據拖曳檢測器的 Z 因子調整粒子顏色
local color = COLOR2:Lerp(COLOR1, dragFactorZ)
emitter.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, color),
ColorSequenceKeypoint.new(1, color)
}
end
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
updateParticles(emitter)
end)
©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。