Понадобилось мне интерактивное управление объектами в игре «как в Roblox Studio» вечер покопавшись я нашёл два инструмента которые вроде как это позволяют.
- Handles — управления в стиле смещение и изменение размера объекта
- ArcHandles — управление поворотом объекта
Что даёт нам документация? Практически ничего. Но из неё можно узнать что:
- это элементы GUI, а следовательно размещаться должны в StarterGUI, чтобы попадать в GUI игрока
- т.к. это часть GUI, то взаимодействовать с ними мы можем только через локальные скрипты
Чем то это это напоминает UI Drag Detector и 3D Drag Detector т.к. по факту это их объединение в одно целое.
Ну да ладно. Вернёмся к нашим баранам.
Размещаем три парта в workspace и наши хандлеры в StarterGui:
В параметре Adornee каждого из них указываем на нужный парт и в итоге видим следующую картину (у простой ручки меняем параметр Style на Resize чтобы получить вариант Scale):
А далее не буду лить воду и просто дам локальные скрипты под каждой из ручек лежащий:
-- перемещение local handle = script.Parent -- управляющая ручка local part = handle.Adornee -- управляемый парт local minSize = 1 -- минимальный размер local oldDelta = 0 -- смещение от последнего движения handle.MouseDrag:Connect(function(face, distance) -- Enum направления и смещение local delta = distance - oldDelta -- новое смещение local direction = Vector3.fromNormalId(face) -- единичный вектор смещения -- смещение центра парта handle.Adornee:PivotTo(handle.Adornee.CFrame * CFrame.new(direction * delta)) oldDelta = distance end) -- сброс смещения когда отпущена кнопка handle.MouseButton1Up:Connect(function() oldDelta = 0 end)
-- изменение размера local handle = script.Parent local part = handle.Adornee local minSize = 1 -- минимальный размер local oldDelta = 0 -- смещение от последнего движения handle.MouseDrag:Connect(function(face, distance) -- Enum направления и смещение local delta = distance - oldDelta -- новое смещение local direction = Vector3.fromNormalId(face) -- единичный вектор смещения local size = Vector3.new(math.abs(direction.X), math.abs(direction.Y), math.abs(direction.Z)) -- положительный вектор local endSize = handle.Adornee.Size + delta * size -- расчёт нового размера handle.Adornee.Size = endSize handle.Adornee:PivotTo(handle.Adornee.CFrame * CFrame.new(direction / 2 * delta)) -- смещение центра парта oldDelta = distance end) handle.MouseButton1Up:Connect(function() -- сброс смещения когда отпущена кнопка oldDelta = 0 end)
-- изменение поворота local handle = script.Parent -- управляющая ручка local part = handle.Adornee -- управляемый парт local lastCFrame = nil -- стартовый CFrame local increment = 2 -- скорость поворота -- расчёт смещения с учётом ускорения function round(number) return math.floor((number / increment) + 0.5) * increment end function AngleFromAxis(axis, r) local relativeAngle = math.rad(round(math.deg(r))) -- получаем смещение угла return axis == Enum.Axis.X and {relativeAngle, 0, 0} -- поворот в зависимости от оси or axis == Enum.Axis.Y and {0, relativeAngle, 0} or axis == Enum.Axis.Z and {0, 0, relativeAngle} end handle.MouseDrag:Connect(function(axis, relativeAngle, delta) -- сложение CFrame в плане поворота part.CFrame = lastCFrame * CFrame.Angles(unpack(AngleFromAxis(axis, relativeAngle))) end) -- стартовый CFrame от которого начинается вращение handle.MouseButton1Down:Connect(function() lastCFrame = part.CFrame end)
Изменить их под себя вы можете самостоятельно. В том числе и в модуль запихнуть. 🙂