Yikes, I’ll have to update this because I found a major problem with my previous “solution”.
There were a few problems actually. The weld/unweld idea slowly caused inaccuracies, and the parts no longer lined up neatly. Also, my rotating system was really bad and I just didn’t like how it felt. Because of these problems, I actually restarted this project from scratch, and now I’m actually happy with the results.
Because of no longer needing to worry about welding the parts together, the code has also become much more manageable. For the dragging, instead of rotating the part via a vector in 3D space found from a 2D vector, I decided to keep the calculations in 2D, and apply the rotation via CFrame.Angles(). The movement itself is still used with the cube’s PrimaryPart, but what made this work over the original code is that changing the orientation of the PrimaryPart won’t move the rest of the model with it. This means I can constantly rotate the PrimaryPart back to default orientation, so all movements are relative to the cube’s current rotation. Everything is now handled with UserInputService so there’s no need for connections with RunService anymore. Overall, everything in this system is far better.
Here’s the relevant code, commented slightly better than before.
local ButtonsHeld = {} -- Tracks buttons being held. Used to know when dragging
local LastMousePos = nil -- Used to calculate how far mouse has moved
UserInputService.InputChanged:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.UserInputType == Enum.UserInputType.MouseMovement then -- runs every time mouse is moved
if ButtonsHeld["MouseButton2"] then -- makes sure player is holding down right click
local CurrentMousePos = Vector2.new(Mouse.X,Mouse.Y)
local change = (CurrentMousePos - LastMousePos)/5 -- calculates distance mouse traveled (/5 to lower sensitivity)
-- The angles part is weird here because of how the cube happens to be oriented. The angles may differ for other sections
Cube:SetPrimaryPartCFrame(Cube:GetPrimaryPartCFrame() * CFrame.Angles(0,math.rad(change.X),-math.rad(change.Y)))
LastMousePos = CurrentMousePos
-- This line makes everything possible. The PrimaryPart's orientation DOES NOT move the rest of the model with it.
Cube.PrimaryPart.Orientation = Vector3.new(0, 0, 0)
end
end
end)
UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.UserInputType == Enum.UserInputType.MouseButton2 then -- player starts dragging
LastMousePos = Vector2.new(Mouse.X,Mouse.Y)
ButtonsHeld["MouseButton2"] = true
end
end)
UserInputService.InputEnded:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.UserInputType == Enum.UserInputType.MouseButton2 then -- player stops dragging
ButtonsHeld["MouseButton2"] = nil
LastMousePos = nil
end
end)