It’s kind of irritating that the UserInputService doesn’t have a way to give 3D position. MouseMovement > Position returns the pixel-based screen coordinates (as a Vector3: [X, Y, 0]).
The script, which runs locally, uses that 2D coordinate to get the mouse’s position via the Camera’s ScreenPointToRay method. If you have something else that works feel free to post it.
local Players = game:GetService("Players")
local Camera = workspace.CurrentCamera
function GetMousePoint(X, Y)
local RayMag1 = Camera:ScreenPointToRay(X, Y) --Hence the var name, the magnitude of this is 1.
local NewRay = Ray.new(RayMag1.Origin, RayMag1.Direction * 1000)
local Target, Position = workspace:FindPartOnRay(NewRay, Players.LocalPlayer.Character)
return Position
end
--Listen to UserInputService's "InputChanged" event, and get the
--Position property of the InputObject, which will be a Vector3. Pass X and Y into the
--function. It will return a position in the 3D world.
Just set TargetFilter to the player’s character and simply read its properties. This is already kept track of anyway so might as well be used.
i.e.:
local mouse = game.Players.LocalPlayer:GetMouse()
-- either this or listen to PropertyChanged on "Character" whenever that's out:
game.Players.LocalPlayer.CharacterAdded:connect(
function(char)
mouse.TargetFilter = char
end
)
-- read mouse.Hit, mouse.Target whenever you want
The only thing it doesn’t have a property for is the surface normal at the hit position, but it didn’t seem like you needed that. If you do need that you can raycast with mouse.UnitRay (ray already constructed for you)
EDIT: actually mouse.Hit returns a CFrame that has the hit normal as one of its axis vectors, I think.
I believe it doesn’t work so well with touch screens (mobile & tablet), especially if you want to drag things in 3D space. I used a similar method to Xan for my work on it.
Mouse.Hit returns a CFrame whose lookVector is in the direction from Camera.CFrame.p → Mouse.Hit.p – of course its Point is at the clicked point.
I would have used the Mouse for this normally, but since most new scripts are expected to use the UserInputService, it’d be kind of useless to have a UserInputService listener on top of a mouse listener in the aspect that it feels more redundant to have both.
This is kind of a personal thing, so I would use the mouse if I just need mouse input only, but if I need to use mouse alongside the UserInputService at all I’ll just use my little function.
I disagree. If you’re using your own target filter system, you should definitely use the method in the OP. It’s redundant to get a result from the PlayerMouse when you then need to apply your filter after and cast another ray anyway.
On top of that, PlayerMouse is basically legacy API now. It’s suggested to move away from it entirely. I would quote the post from a Roblox staff member, but I’m not on my computer at the moment.
We can only use this in a UserInputServices InputChanged event, but how would I use this if I only want to get the mouse position once when the player clicks using the function.
UserInputService.InputBegan, check if Input.UserInputState is Enum.UserInputState.MouseButton1, and then you can get the 3D mouse position.
It’s not smart to do this every time the mouse moves if you don’t need to. Also, limit the magnitude of the world ray to be as low as possible, because the longer it is, the higher the performance cost is.