I appreciate the information. I was able to quickly put together a prototype to show you using this information.
Please pardon my sluggish reaction time as well.
Your initial question was almost accurate. Since you are only multiplying with one direction, your gizmo will become “janky” if you flip sides because the controls will be inverted. To combat this, I created a function that changes the coordinates from Vector2 to Vector3 depending on your camera. This stage took a while, so eventually I just made on my own function. Keep in mind that this is simply a rough sample to aid you in solving your issue. This is the outcome.
Pretend that there are some really cool direction pointers sticking out as your gyzmo
You can alter the sensetivity, so don’t worry about it.
We must first declare a few variables.
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Camera = game.Workspace.CurrentCamera
local Dragging = false
local StartPosition = nil
local InitialPosition = nil
local Sensetivity = 10
local Depth = 10
local Decelerate = 50
local Selected = Instance.new("Part", workspace) -- Demonstration purposes
Selected.Anchored = true
This function transforms the coordinates for us. Though not very exact, it serves its purpose. Later, you can always make improvements.
-- ignore the wierd function name it was actually supposed to be ScreenToWorld but I was and am so sleepy eepy
function MouseToScreen(Position: Vector2, Distance: number, Decelerate: number): Vector3
local Mouse = Player:GetMouse()
Position = Vector2.new(Position.X - Mouse.ViewSizeX / 2, -(Position.Y - Mouse.ViewSizeY / 2))
local CameraPosition = Camera.CFrame.Position
local CameraRotation = Camera.CFrame - CameraPosition
local objectPosition = CameraPosition + (CameraRotation * CFrame.new(Position.X/Decelerate, Position.Y/Decelerate, -Distance)).Position
return objectPosition
end
The applications will be explained in this important section. Ever notice when you press G
in Blender theres this sort of invisible grid where your mesh “slides” on?
Please excuse my crude illustration
Basically, this is what we do. We have two positions: the origin
(Start, Red) and the cursor point in three-dimensional space
(End, Green). Then we calculate thier magnitude (Distance) and direction. This results in the same effect as the Blender
“plane”. The world directions and drag directions can now be multiplied!
Heres a visual demonstration.
These inputs are not intended to be the optimal choices and are only being used for demonstration purposes.
function OnMouseChanged()
if Dragging then
local EndPosition = Vector2.new(Player:GetMouse().X, Player:GetMouse().Y)
local StartWorldPos = MouseToScreen(Vector2.new(StartPosition.X, StartPosition.Y), Depth, Decelerate)
local EndWorldPos = MouseToScreen(Vector2.new(EndPosition.X, EndPosition.Y), Depth, Decelerate)
local DragDirection = (EndWorldPos - StartWorldPos).Unit
local DragDistance = (EndWorldPos - StartWorldPos).Magnitude
if DragDistance == 0 then
Selected.Position = InitialPosition
return
end
-- This is just a simulation of your gizmos.
if UserInputService:IsKeyDown(Enum.KeyCode.X) then
Selected.Position = DragDirection * Vector3.new(1, 0, 0) * DragDistance * Sensetivity + InitialPosition
end
if UserInputService:IsKeyDown(Enum.KeyCode.Y) then
Selected.Position = DragDirection * Vector3.new(0, 1, 0) * DragDistance * Sensetivity + InitialPosition
end
if UserInputService:IsKeyDown(Enum.KeyCode.Z) then
Selected.Position = DragDirection * Vector3.new(0, 0, 1) * DragDistance * Sensetivity + InitialPosition
end
end
end
local function OnMouseDown(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
Dragging = true
StartPosition = Vector2.new(Player:GetMouse().X, Player:GetMouse().Y)
InitialPosition = Selected.Position
end
end
local function OnMouseUp(input)
if Dragging and input.UserInputType == Enum.UserInputType.MouseButton1 then
Dragging = false
end
end
UserInputService.InputChanged:Connect(OnMouseChanged)
UserInputService.InputEnded:Connect(OnMouseUp)
UserInputService.InputBegan:Connect(OnMouseDown)
That’s basically it. It took over three hours, which surprises me (In a bad way, took way too long ), but hey, it works!
Full source code
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Camera = game.Workspace.CurrentCamera
local Dragging = false
local StartPosition = nil
local InitialPosition = nil
local Sensetivity = 10
local Depth = 10
local Decelerate = 50
local Selected = Instance.new("Part", workspace)
Selected.Anchored = true
function MouseToScreen(Position: Vector2, Distance: number, Decelerate: number): Vector3
local Mouse = Player:GetMouse()
Position = Vector2.new(Position.X - Mouse.ViewSizeX / 2, -(Position.Y - Mouse.ViewSizeY / 2))
local CameraPosition = Camera.CFrame.Position
local CameraRotation = Camera.CFrame - CameraPosition
local objectPosition = CameraPosition + (CameraRotation * CFrame.new(Position.X/Decelerate, Position.Y/Decelerate, -Distance)).Position
return objectPosition
end
function OnMouseChanged()
if Dragging then
local EndPosition = Vector2.new(Player:GetMouse().X, Player:GetMouse().Y)
local StartWorldPos = MouseToScreen(Vector2.new(StartPosition.X, StartPosition.Y), Depth, Decelerate)
local EndWorldPos = MouseToScreen(Vector2.new(EndPosition.X, EndPosition.Y), Depth, Decelerate)
local DragDirection = (EndWorldPos - StartWorldPos).Unit
local DragDistance = (EndWorldPos - StartWorldPos).Magnitude
if DragDistance == 0 then
Selected.Position = InitialPosition
return
end
-- This is just a simulation of your gizmos.
if UserInputService:IsKeyDown(Enum.KeyCode.X) then
Selected.Position = DragDirection * Vector3.new(1, 0, 0) * DragDistance * Sensetivity + InitialPosition
end
if UserInputService:IsKeyDown(Enum.KeyCode.Y) then
Selected.Position = DragDirection * Vector3.new(0, 1, 0) * DragDistance * Sensetivity + InitialPosition
end
if UserInputService:IsKeyDown(Enum.KeyCode.Z) then
Selected.Position = DragDirection * Vector3.new(0, 0, 1) * DragDistance * Sensetivity + InitialPosition
end
end
end
local function OnMouseDown(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
Dragging = true
StartPosition = Vector2.new(Player:GetMouse().X, Player:GetMouse().Y)
InitialPosition = Selected.Position
end
end
local function OnMouseUp(input)
if Dragging and input.UserInputType == Enum.UserInputType.MouseButton1 then
Dragging = false
end
end
UserInputService.InputChanged:Connect(OnMouseChanged)
UserInputService.InputEnded:Connect(OnMouseUp)
UserInputService.InputBegan:Connect(OnMouseDown)
This example is located in the StarterCharacterScripts and is saved as a local script
Ask away if you are having issues or questions. I’m not bothered.