Instancja DragDetector ułatwia i zachęca do interakcji z obiektami 3D w doświadczeniu, takimi jak otwieranie drzwi i szuflad, przesuwanie części, chwytanie i rzucanie piłką do kręgli, naciąganie i strzelanie z procy, oraz wiele więcej. Kluczowe funkcje obejmują:
Umieść DragDetector pod dowolnym BasePart lub Model, aby uczynić go przeciągalnym za pomocą wszystkich wejść (mysz, dotyk, kontroler, VR), wszystko to bez jednej linii kodu.
Wybierz spośród kilku stylów przeciągania, zdefiniuj, jak obiekt reaguje na ruch, i opcjonalnie zastosuj limity osi lub ruchu.
Skrypty mogą reagować na manipulację przeciąganymi obiektami, aby napędzać UI lub podejmować decyzje logiczne, takie jak dostosowanie poziomu światła w pomieszczeniu na podstawie przesuwanego przełącznika.
Gracze mogą manipulować zablokowanymi częściami lub modelami, które pozostaną dokładnie tam, gdzie je umieścisz po zwolnieniu.
DragDetectors działają w Studio, o ile nie korzystasz z narzędzi Wybierz, Przenieś, Skaluj lub Obróć, co ułatwia testowanie i dostosowywanie przeciągalnych obiektów podczas edytowania.
Uczyń obiekty przeciągalnymi
Aby uczynić dowolną część lub model przeciągalnym, wystarczy dodać DragDetector jako bezpośredniego potomka.
W oknie Eksploratora najedź kursorem na Part, MeshPart lub Model i kliknij przycisk ⊕. Wyświetli się menu kontekstowe.
Z menu wstaw DragDetector.

Domyślnie obiekt będzie teraz przeciągalny w płaszczyźnie ground, ale możesz dostosować jego DragStyle, zdefiniować jak reaguje na ruch i opcjonalnie zastosować limity osi lub ruchu.
Dostosowywanie detektorów przeciągania
Styl przeciągania
DragDetectors mapują ruch kursora na wirtualne linie i płaszczyzny w celu obliczenia proponowanego ruchu 3D. Dzięki właściwości DragStyle możesz wybierać spośród różnych mapowań, które odpowiadają Twoim potrzebom. Na przykład, TranslatePlane produkuje translację w wirtualnej płaszczyźnie, podczas gdy RotateAxis produkuje obrót wokół wirtualnej osi.
| Ustawienie | Opis |
|---|---|
| TranslateLine | Ruch 1D wzdłuż Axis detektora, domyślnie wzdłuż osii Y świata. |
| TranslatePlane | Ruch 2D w płaszczyźnie prostopadłej do Axis detektora, domyślnie w płaszczyźnie XZ świata. |
| TranslatePlaneOrLine | Ruch 2D w płaszczyźnie prostopadłej do Axis detektora oraz, gdy modyfikator jest aktywny, ruch 1D wzdłuż osii Axis detektora. |
| TranslateLineOrPlane | Ruch 1D wzdłuż Axis detektora oraz, gdy modyfikator jest aktywny, ruch 2D w płaszczyźnie prostopadłej do Axis detektora. |
| TranslateViewPlane | Ruch 2D w płaszczyźnie prostopadłej do widoku kamery. W tym trybie płaszczyzna jest nieustannie aktualizowana, nawet podczas przeciągania, i zawsze będzie zwrócona w kierunku aktualnego widoku kamery. |
| RotateAxis | Obrót wokół Axis detektora, domyślnie wzdłuż osii Y świata. |
| RotateTrackball | Obrót trackball, dodatkowo dostosowywany poprzez właściwości TrackballRadialPullFactor i TrackballRollFactor. |
| BestForDevice | TranslatePlaneOrLine dla myszy i kontrolera; TranslatePlane dla dotyku; 6DOF dla VR. |
| Scriptable | Oblicza pożądany ruch za pomocą funkcji niestandardowej dostarczonej poprzez SetDragStyleFunction(). |
Kierunek przeciągania
Domyślnie ruch 3D i związany z nim DragStyle mapują się na przestrzeń świata. Możesz jednak захотеть zmienić ReferenceInstance, Orientation lub Axis, na przykład podczas budowania detektorów przeciągania w modelach z regulowanymi częściami.
| Właściwość | Opis | Domyślnie |
|---|---|---|
| ReferenceInstance | Instancja, której pivot zapewnia ramę odniesienia dla detektora przeciągania. DragFrame jest wyrażany względem tej ramy odniesienia, którą można uzyskać za pomocą GetReferenceFrame(). Jeśli rama odniesienia jest nil, translacja będzie w kierunku (lub w płaszczyźnie prostopadłej do) właściwości Axis w przestrzeni świata. | nil |
| Orientation | Określa YXZ obrót osi ruchu względem ramy odniesienia (nie zmienia orientacji samej ramy odniesienia). Linearna translacja i rotacja osiowe będą na tej obróconej osi Y, a translacja w płaszczyźnie XZ. Zmiana tej wartości automatycznie aktualizuje Axis i odwrotnie. | (0, 0, 0) |
| Axis | Główna oś ruchu, wyrażona względem ramy odniesienia. Zmiana tej wartości automatycznie aktualizuje Orientation i odwrotnie. | (0, 1, 0) |
Reakcja na ruch
Właściwość ResponseStyle określa, jak obiekt reaguje na proponowany ruch, w zależności od tego, czy obiekt jest Anchored czy nie.
| Ustawienie | Zachowanie zablokowane | Zachowanie niezablokowane |
|---|---|---|
| Geometric | Zarówno wewnątrz działającego doświadczenia, jak i w trybie edytora Studio, pozycja/orientacja zablokowanego obiektu będzie aktualizowana, aby dokładnie odzwierciedlać proponowany ruch. | Dla niezablokowanego obiektu, zachowanie jest takie samo jak dla zablokowanego obiektu. Jednak w działającym doświadczeniu obiekt będzie zablokowany na początku przeciągania i przywrócony do niezablokowanego po zwolnieniu przeciągania. |
| Physical | Zablokowany obiekt domyślnie będzie miał zachowanie Geometric, ponieważ nie jest poddawany siłom. | Niezablokowany obiekt będzie przenoszony przez siły ograniczające, które próbują przynieść go do pozycji/orientacji wskazanej przez proponowany ruch. |
| Custom | Obiekt nie poruszy się wcale, ale DragFrame nadal będzie aktualizowane i możesz reagować na manipulację przeciąganiem w dowolny sposób. | (to samo co zablokowany) |
Osi i limity ruchu
Domyślnie nie ma limitów 3D ruchu poza wrodzonymi ograniczeniami DragStyle. W razie potrzeby możesz zastosować minimalne i maksymalne limity dla translacji i rotacji. Zauważ jednak, że są to nie ograniczenia; jedynie utrudniają próby detektora przeciągania generowanie ruchu w celu pozostania w ramach limitów.
| Właściwości | Opis | Domyślnie |
|---|---|---|
| Limity dla translacji przeciągania w każdym wymiarze. Jeśli MaxDragTranslation jest większa niż MinDragTranslation, translacja będzie ograniczona do tego zakresu. | (0, 0, 0) | |
| Ważne tylko, jeśli DragStyle jest ustawione na RotateAxis. Jeśli MaxDragAngle jest większe niż MinDragAngle, rotacja będzie ograniczona do tego zakresu. | 0 |
Uprawnienia przeciągania
Uprawnienia graczy do interakcji z danym instancją detektora przeciągania można określić przez właściwość PermissionPolicy. Domyślnie jest ustawiona na Enum.DragDetectorPermissionPolicy.Everybody, a także może być zmieniana, aby wspierać kontrolowane uprawnienia skryptowe, jak pokazano w przykładzie kodu.
| Ustawienie | Opis |
|---|---|
| Nobody | Żaden gracz nie może interakcji z DragDetector. |
| Everybody | Wszyscy gracze mogą interagować z DragDetector. |
| Scriptable | Uprawnienia do przeciągania graczy będą określane przez funkcję zarejestrowaną za pomocą SetPermissionPolicyFunction(). W tym ustawieniu brak rejestracji funkcji lub zwrócenie nieprawidłowego wyniku uniemożliwi wszystkim graczom przeciąganie. |
DragDetector - Skryptowane uprawnienia przeciągania
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)
Odpowiedź fizyczna
Jeśli styl odpowiedzi detektora jest ustawiony na Physical i jest stosowany do niezablokowanego obiektu, obiekt ten будет przemieszczany przez siły ograniczające, które starają się przynieść go do pozycji/orientacji wskazanej przez proponowany ruch. Możesz dalej dostosować odpowiedź fizyczną za pomocą następujących właściwości:
| Właściwość | Opis | Domyślnie |
|---|---|---|
| ApplyAtCenterOfMass | Kiedy fałsz, siła przeciągania jest stosowana w punkcie, w którym użytkownik klika. Gdy prawda, siła jest zastosowana w środku masy obiektu. | false |
| MaxForce | Maksymalna siła zastosowana, aby obiekt osiągnął swój cel. | 10000000 |
| MaxTorque | Maksymalny moment obrotowy zastosowany, aby obiekt osiągnął swój cel. | 10000 |
| Responsiveness | Wyższe wartości sprawiają, że obiekt szybciej osiąga cel. | 10 |
Modyfikator wejściowy
Niektóre tryby DragStyle pozwalają użytkownikom przytrzymać klawisz/przycisk modyfikujący, aby manipulować przeciąganym obiektem w różny sposób. Domyślnie modyfikator to LeftControl na PC, ButtonR1 na kontrolerze, lub ButtonL2 na VR. Możesz dostosować te modyfikatory za pomocą właściwości KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode, lub VRSwitchKeyCode instancji detektora przeciągania.
Replikacja
Gdy właściwość RunLocally jest fałszywa (domyślnie), klient interpretuje wszystkie wejścia, aby generować dane, które wysyła do serwera, aby zrealizować przeciąganie. W tym trybie wszystkie niestandardowe sygnały zdarzeń i zarejestrowane funkcje muszą znajdować się w serwerowych Scripts.
Gdy właściwość RunLocally jest prawdziwa, żadne z wydarzeń nie są replikowane do serwera. Wszystkie niestandardowe sygnały zdarzeń i zarejestrowane funkcje muszą znajdować się w lokalnych LocalScripts, a zmiany musisz propogować do serwera za pomocą zdarzeń zdalnych.
Odpowiedzi skryptów na klikanie i przeciąganie
Dzięki sygnałom zdarzeń, zmianom właściwości, Scriptable stylowi przeciągania oraz niestandardowym funkcjom, skrypty mogą reagować na manipulację przeciąganymi obiektami, aby napędzać UI lub podejmować decyzje logiczne, takie jak dostosowanie poziomu światła w pomieszczeniu na podstawie przesuwanego przełącznika.
Sygnały zdarzeń
Za pomocą następujących sygnałów zdarzeń możesz wykryć, kiedy użytkownik zaczyna, kontynuuje i kończy przeciąganie obiektu.
| Zdarzenie | Opis |
|---|---|
| DragStart | Uruchamia się, gdy użytkownik zaczyna przeciągać obiekt. |
| DragContinue | Uruchamia się, gdy użytkownik kontynuuje przeciąganie obiektu po tym, jak DragStart zostało zainicjowane. |
| DragEnd | Uruchamia się, gdy użytkownik przestaje przeciągać obiekt. |
DragDetector - Sygnały zdarzeń
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)
Zmiany ramki przeciągania
Oprócz sygnałów zdarzeń, możesz monitorować zmiany w DragFrame detektora bezpośrednio.
DragDetector - Zmiany w DragFrame
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)
Skryptowany styl przeciągania
Jeśli ustawisz DragStyle detektora na Scriptable, możesz dostarczyć własną funkcję, która przyjmuje Ray i zwraca CFrame w przestrzeni świata. Detektor przeniesie ruch, aby przeciągany obiekt przeszedł do tej niestandardowej lokalizacji/orientacji.
DragDetector - Skryptowany DragStyle
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)
-- Wyklucz przeciągany obiekt z wykrywania raycast
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)
Niestandardna funkcja ograniczeń
Detektory przeciągania nie mają wbudowanych reguł ruchu dotyczących siatek i snu, ale możesz zarejestrować niestandardowe funkcje ograniczeń, aby edytować DragFrame detektora, zanim zostanie zastosowany. Na przykład, możesz utrzymać ruch na siatce, zaokrąglając pozycje do wielokrotności kroku siatki, lub symulować grę w szachy z zasadami ruchu legalnymi dla każdej figury.
DragDetector - Niestandardowa funkcja ograniczenia
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)
-- Gdy to konieczne, usuń funkcję ograniczenia wywołując connection:Disconnect()
Przykład użycia
Niezablokowane obiekty fizyczne
Podstawowa implementacja detektorów przeciągania to gra o równowadze wieży, w której gracze muszą ostrożnie usunąć elementy i starać się utrzymać wieżę w pionie. W poniższej strukturze wieży każdy element ma dziecko DragDetector z domyślnym DragStyle ustawionym na TranslatePlane, aby gracze mogli ciągnąć elementy na zewnątrz, ale nie w górę ani w dół.
Zablokowane modele z regulowanymi częściami
Możesz łatwo tworzyć i udostępniać modele, które są głównie zablokowane, ale mają jedną lub więcej części/modeli, które gracze mogą przeciągać. Na przykład, poniższe biurko ma dwie szuflady, które gracze mogą otworzyć, aby sprawdzić, co jest w środku.
Detektory przeciągania i ograniczenia
Możesz łączyć detektory przeciągania z Constraints, na przykład marionetka. W poniższym ustawieniu uchwyty sterujące są zablokowane, a części ciała są niezablokowane, a ograniczenia trzymają marionetkę razem. Ruch uchwytów za pomocą TranslateViewPlane DragStyle sprawia, że marionetka tańczy, a poszczególne części ciała mogą być także przesuwane za pomocą detektorów przeciągania, podczas gdy model zachowuje swoją integralność.
3D interfejsy użytkownika
3D interfejsy użytkownika można łatwo osiągnąć za pomocą detektorów przeciągania, takich jak dostosowywanie jasności SpotLight na podstawie suwaka dimmera. Możesz także odkryć indywidualnie osie X i Z, aby kontrolować różne aspekty 3D interfejsu użytkownika, takie jak Size, Speed, i Color ParticleEmitter.
DragDetector - 3D Interfejs użytkownika
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
-- Dostosuj rozmiar i prędkość cząstek na podstawie czynnika X detektora przeciągania
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)
-- Dostosuj kolor cząstek na podstawie czynnika Z detektora przeciągania
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)