Class.DragDetector 实例在体验中与 3D 对象互动,例如打开门和抽屉、滑动零件周围、抓取和投掷保龄球、拉动并发射弹跳、和 much more。 的关键功能包括:
将 DragDetector 放置在任意 BasePart 或 Model 下,通过所有输入(鼠标、触摸、游戏手柄和 VR),无需单行代验证码。
脚本可以 回应拖动对象的操作来驱动用户界面或做出理论上的决策,例如根据室内灯光水平调整灯阴控制器的水平。
玩家可以操作锚定的零件或模型,它们将在您释放时保持正确的位置。
Class.DragDetector|DragDetectors 在 Studio 中工作,直到您使用 选择 、移动 移动 、0>缩放0> 或DragDetectors3>工具,以便在编辑时测试和调整拖动对象更容易。
让对象可拖动
要将任何部分或模型拖动可拖动,请单击直接后后代 DragDetector 。
从菜单中,插入一个 拖动侦测器 。
默认情况下,对象现在将在地面平面中拖动,但您可以自定义其 DragStyle ,定义其 响应移动 方式,并且可选择 轴或移动限制 。
自定义拖动探测器
拖动样式
DragDetectors 地图曲线移动到虚拟线和飞机来计算所提出的3D移动。通过DragStyle属性,您可以选择从不同的映射满足您的需求。例如, TranslatePlane 生成在虚拟平面上的翻译,而
设置 | 描述 |
---|---|
TranslateLine | 1D 移动在探测器的 Axis 上,默认世界上的 Y 轴。 |
TranslatePlane | 在平面上与探测器的 Axis ,默认为世界上的 XZ 飞机。 |
TranslatePlaneOrLine | 在平面上与探测器的 Axis 和,当 调整因素 处于活动状态时, 1D 移动沿探测器的 Axis . |
TranslateLineOrPlane | 1D 移动沿探测器的 Axis ,当 调整器 处于活动状态时,在平面上与探测器的 Axis 之间的 2D 移动。 |
TranslateViewPlane | 在飞机上平行于相镜头查看图的 2D 运动。在此模式下,飞机正常更新,即使是拖动,也会始终面向相镜头的当前视查看。 |
RotateAxis | 在探测器的 Axis 上旋转,默认世界上的 Y 轴。 |
RotateTrackball | 通过 TrackballRadialPullFactor 和 TrackballRollFactor 属性进行跟踪球旋转。 |
BestForDevice | 翻译机或线路图 对于鼠标和游戏手柄; 翻译机 对于触摸; 6DOF 对于 VR。 |
Scriptable | 通过提供自定义函数计算所需的移动方式 SetDragStyleFunction()。 |
拖动方向
默认情况下,3D动作和相关的DragStyle 地图到世界空间。 您可以要求ReferenceInstance,Orientation或1> Class.DragDetector.Axis
属性 | 描述 | 默认 |
---|---|---|
ReferenceInstance | 一个例子,其中的中心为拖动探测器提供 参考框 。 DragFrame 用于此参考框,可以通过 GetReferenceFrame() 获取。 如 | nil |
Orientation | 指定关键框相对于参考框的移动轴的旋转 YXZ (不会更改参考框自身的方向) 。 线性翻译和轴向旋转将在此重新定向 Y 轴上, 平面翻译在 XZ 平面上。 更改此值会自动更新 1> Class.DragDetector.Axis|Axis1> | (0, 0, 0) |
Axis | 移动的主轴,与参考框相对。改变此值会自动更新 Orientation 和 vice versa。 | (0, 1, 0) |
机器人的反应
Class.DragDetector.ResponseStyle|ResponseStyle 属性指定对象在响应提议的运动时如何回应,这取决于对象是否是 Anchored 或不是。
设置 | 锚定行为 | 无锚定义的行为 |
---|---|---|
Geometric | 在运行体验和 Studio 编辑模式中,固定对象的位置/方向将被更新,以反映所提出的运动。 | 对于未锚定的对象,行为与锚定的对象相同。但在运行体验中,对象将在拖动开始时锚定,并在拖动释放时恢复为未锚定。 |
Physical | 一个锚定的对象将默认为 几何学 行为,因为它不受力学影响。 | 一个未锚定的对象将被移动 by 限制力 ,试图将其带到所提供的移动位置和/或方向。 |
Custom | 对象将不会移全部,但 DragFrame 仍会更新,您可以 按照拖动操作响应 ,但您喜欢。 | (与锚定相同) |
轴和移动限制
默认情况下,DragStyle 之上的 3D 运动不受限制。 如果需要,您可以对翻译和旋转的最小限制和最大限制进行适用。 请注意,这些不是限制;它们只是阻止拖动探测器在生成运动时遵循限制。
属性 | 描述 | 默认 |
---|---|---|
Class.DragDetector.MinDragTranslation|MinDragTranslation``Class.DragDetector.MaxDragTranslation|MaxDragTranslation | 限制在每个维度中拖动翻译。如果MaxDragTranslation大于MinDragTranslation,翻译将在该范围内进行压缩。 | (0, 0, 0) |
MinDragAngle MaxDragAngle | 仅适用于 DragStyle 设置为 RotateAxis 。如果 MaxDragAngle 大于 1> Class.DragDetorer.MinDragAngle|MinDragAngle1> ,旋转将在该范围内受到限制。 | 0 |
拖动权限
玩家可以通过 PermissionPolicy 属性指定与指定的拖动探测器实例交互的权限。默认为 Enum.DragDetectorPermissionPolicy.Everybody,可以通过 Class.DragDetectorPermission Policy 设置为 2> Class.DragDetectorPermission2> 支持脚本权限控制,如在代码示例中所示。
设置 | 描述 |
---|---|
Nobody | 没有玩家可以与 DragDetector 互动。 |
Everybody | 所有玩家都可以与 DragDetector 互动。 |
Scriptable | 玩家的拖动权限将被函数 SetPermissionPolicyFunction() 注册确定。在此设置中,注册函数或返回无效结果都会导致所有玩家无法拖动。 |
拖动探测器 - 脚本拖动权限
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)
物理响应
假设拖动器的 回应式 设置为 物理 并且应用于未锚定的对象,那个对象通过约束力试图将其移动到位置/方向给予的位置/方向。您可以通过以下属性进行进一步定制物理回应:
属性 | 描述 | 默认 |
---|---|---|
ApplyAtCenterOfMass | 在错误时,拖动力应用在用户点击的地方。 在真实时,力应用在对象的中心 масс。 | 否 |
MaxForce | 最大力量已应用于对象达成其目标。 | 10000000 |
MaxTorque | 最大扭矩已适用于对象达到目标。 | 10000 |
Responsiveness | 更高的值会导致目标更快地达到目标。 | 10 |
调整因素输入
复制
当 RunLocally 属性为 false (默认) 时,客户端会将所有输入转换为数据,发送到服务器执行拖动。在此模式中,所有自定义事件信号和注册函数必须位于服务器 Scripts 中。
当 RunLocally 属性是真的时,不会有事件复制到服务器。所有自定义事件信号和注册函数必须在客户端 LocalScripts 中,您必须使用 远程事件 来传播必要的更改到服务器。
脚本回应单击和拖动
通过事件信号、属性变更、Scriptable 拖动式样式、自定义函数,脚本可以对拖动对象进行操作,驱动用户界面或做出逻辑决策,例如调整室内灯光水平基于滑动墙面开关的暗灯等级。
事件信号
通过以下事件信号,您可以检测到用户开始拖动对象时开始、继续和结束。
事件 | 描述 |
---|---|
DragStart | 当用户开始拖动对象时,火焰会立即点燃。 |
DragContinue | 在 DragStart 已初始化后,用户继续拖动对象时发生。 |
DragEnd | 当用户停止拖动对象时,火焰会立即熄灭。 |
拖动探测器 - 事件信号
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 变更。
拖动探测器 - 拖动框架更改
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)
脚本拖动风格
如果您将探测器的 DragStyle 设置为 脚本可用 ,您可以提供您自己的函数,该函数会收集一个 Ray 并返回一个世界空间 1> Datatype.CFrame1>。探测器将移动移动器到那个自定义位置/方向。
拖动侦测器 - 脚本拖动式
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 之前。例如,您可以在网格上圆形位置保留移动位置,或者 simulate 一个棋盘游戏,规则的移动对象允许每个位置。
拖动检测器 - 自定义约束函数
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 = math.floor(SNAP_INCREMENT)
if snapIncrement < 1 then
return proposedMotion
end
local newWorldPosition = startPartPosition + proposedMotion.Position
local roundedX = math.floor(newWorldPosition.X / snapIncrement + 0.5) * snapIncrement
local roundedY = math.floor(newWorldPosition.Y / snapIncrement + 0.5) * snapIncrement
local roundedZ = math.floor(newWorldPosition.Z / snapIncrement + 0.5) * snapIncrement
local newRoundedWorldPosition = Vector3.new(roundedX, roundedY, roundedZ)
return proposedMotion.Rotation + (newRoundedWorldPosition - startPartPosition)
end
local connection = dragDetector:AddConstraintFunction(2, snapToWorldGrid)
-- When applicable, remove the constraint function by invoking connection:Disconnect()
示例使用
未锚定的物理对象
拖动探测器的基本实现是一个塔平衡游戏,在这里玩家必须小心移除部件并尝试保持塔的竖起。 在以下塔结构中,每个部件都有一个子 DragDetector 用默认 Class.DragDetector.DragStyle|DragStyle 的 DragStyle 以便玩家可以将部件从上向下拖动,但不能从上向
有可调整部件的固定模型
您可以轻松创建和共享主要锚定的模型,但有一个或多个子部件/模型,玩家可以拖动。例如,下面的桌子有两个抽屉,玩家可以打开以检查里面的内容。
拖动探测器和限制器
您可以使用 Constraints 与 Class.DragDetector.DragStyle|DragStyle 来组合拖动检测器,例如一个假面傀儡。在下面的设置中,控制手柄是锚定的,身体部位是未锚定的,限制将 marionette �
3D 用户界面
3D用户界面通过拖动检测器(例如调整滑块暗灯器的亮度)轻松达到可见水平。您还可以单独检测到 SpotLight 和
拖动侦测器 - 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)