I need help with a script that makes the part the script is in move to the cursor when holding down on the object(with a clickdetector)
Its similar to a few games where you can click and hold and the part will fling around, I don’t need it to fling around, just follow the cursor and drop when you stop holding down.
Keep in mind that I’m still very new to scripting.
> local target = script.Parent
>
> local CursorId = "rbxassetid://6739628607"
>
> local ClickDetector = Instance.new("ClickDetector")
>
> ClickDetector.Parent = target
>
> ClickDetector.MaxActivationDistance = 18
>
> ClickDetector.CursorIcon = "CursorId"
>
> ClickDetector.MouseClick:Connect(function()
>
> --Where I need help--
>
> end)
You’re probably going to want to look into RunService, UserInputService and PlayerMouse.
Here’s an example, try inserting it into StarterPlayerScripts:
local players = game:GetService('Players')
local userInputService = game:GetService('UserInputService')
local runService = game:GetService('RunService')
local mouse = players.LocalPlayer:GetMouse() -- get the player's mouse object
userInputService.InputBegan:Connect(function(key, isSystemReserved)
if key.UserInputType == Enum.UserInputType.MouseButton1 then -- if the key/input object is the mouse button 1
local part = mouse.Target -- this returns the object at the target, basically a ray is casted from your screen from the position your mouse is at
if part then -- we need this if statement, otherwise it would error if we, for example, clicked on the sky
while userInputService:IsMouseButtonPressed() do -- while the mouse button is pressed
part.Position = mouse.Hit.p -- move the part to the mouse hit position. Mouse.Hit returns a CFrame value so we only want the position component, not the rotation
runService.RenderStepped:Wait() -- this basically means that it is going to wait until a new frame is rendered to check if the button is down, then go into the loop again
end
end
end
end)
Oh, sorry i should of explained. I need only some parts to be able to be picked up, is there a way I could put a value of some sort into objects that I want to grab? Sorry for the constant questions :I
You could probably add them to a folder. Then add an if statement like if part:IsDescendantOf(folder). You could also go for the value method that you mentioned but I recommend IsDescendantOf for simplicity’s sake.
local players = game:GetService('Players')
local userInputService = game:GetService('UserInputService')
local runService = game:GetService('RunService')
local partsToPickUp = workspace.PartsToPickUp -- can be any instance such as a model, folder, even a part if you really wanted it to
local mouse = players.LocalPlayer:GetMouse() -- get the player's mouse object
userInputService.InputBegan:Connect(function(key, isSystemReserved)
if key.UserInputType == Enum.UserInputType.MouseButton1 then -- if the key/input object is the mouse button 1
local part = mouse.Target -- this returns the object at the target, basically a ray is casted from your screen from the position your mouse is at
if part then -- we need this if statement, otherwise it would error if we, for example, clicked on the sky
if part:IsDescendantOf(partsToPickUp) then -- if the part is a descendant (either the part is or one of the part's ancestors are a child of the partsToPickUp instance)
while userInputService:IsMouseButtonPressed() do -- while the mouse button is pressed
part.Position = mouse.Hit.p -- move the part to the mouse hit position. Mouse.Hit returns a CFrame value so we only want the position component, not the rotation
runService.RenderStepped:Wait() -- this basically means that it is going to wait until a new frame is rendered to check if the button is down, then go into the loop again
end
end
end
end
end)
Although, on line 13 it says “Argument 1 missing or nil”
It also doesn’t seem to pick it up, I created a folder with a part, the folders named “PartsToPickUp”
Ok, I accidently had a server script version of it lol. It still seems to say the same error(without the 2nd one) whenever I click the part. I apologize for all this trouble!
Found the issue, it was because IsMouseButtonDown requires a UserInputType enum as an argument. I also added the TargetFilter, otherwise the part would move around weirdly because the ray would keep casting onto the part you’ve picked up.
local players = game:GetService('Players')
local userInputService = game:GetService('UserInputService')
local runService = game:GetService('RunService')
local partsToPickUp = workspace.PartsToPickUp -- can be any instance such as a model, folder, even a part if you really wanted it to
local mouse = players.LocalPlayer:GetMouse() -- get the player's mouse object
userInputService.InputBegan:Connect(function(key, isSystemReserved)
if key.UserInputType == Enum.UserInputType.MouseButton1 then -- if the key/input object is the mouse button 1
local part = mouse.Target -- this returns the object at the target, basically a ray is casted from your screen from the position your mouse is at
mouse.TargetFilter = part
if part then -- we need this if statement, otherwise it would error if we, for example, clicked on the sky
if part:IsDescendantOf(partsToPickUp) then -- if the part is a descendant (either the part is or one of the part's ancestors are a child of the partsToPickUp instance)
while userInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) do -- while the mouse button is pressed
part.Position = mouse.Hit.p -- move the part to the mouse hit position. Mouse.Hit returns a CFrame value so we only want the position component, not the rotation
runService.RenderStepped:Wait() -- this basically means that it is going to wait until a new frame is rendered to check if the button is down, then go into the loop again
end
end
end
end
end)
Works great! Although, there are a few concerns for me:
1.It seems sometimes the part will teleport back to its original position.
2.The part sinks into the objects by 1 stud, it’s not that big of a deal as it jumps back up after you release but it can cause physics issues.
3. Sometimes the part wont fall(almost like physics is disabled) until a couple secs or I move another part.
I feel bad as this has been going on for a while, sorry!
1- Try using :SetNetworkOwner on the part. Ensure you’re doing it from a server script. You’re going to have to look into remote events and functions if you are planning on using it with more than one player though.
2- You can offset its CFrame by 0.5x its size. Thankfully, Roblox made offsetting CFrames easy!
part.CFrame *= CFrame.new(0, part.Size.Y / 2, 0) -- offset it on the Y axis by 1/2 of its size
3- That’s weird. I’m thinking it might have something to do with network ownership since physics are simulated on the server IIRC. And since the part is unanchored and the server has network ownership of it, that’s likely to happen.