Oh Cool!, I recently like 10 minutes ago or something worked on my grabbing script. I faced the issue that if the player grabbed an object and hold it below its own character in third person it would send the player flying.
I tried various methods in order to calculate if the player is touching the model (beware this was a model and not a part). From raycasting to magnitude, from making the whole part collide to basically forcing the CFrame to be 1 stud above the player.
Anyway, long story I know. I don’t think i have a solution for you right away. But I imagine with raycasting you will come a whole end. I just put this here as inspiration code.
In your code you make somewhere the dragball when you move your objects. Assuming the first line is that dragball.
dragball == The blue sphere placed on the part when clicking it
local DragBall = createDragBall();
-- Since I work with models I kinda have to do this, If you are only using a part
-- I would suggest to group that part into a model.
local pk; -- Set the primary Key
if GrabObject:IsA("Model") then -- GrabObject references the object you are lifting, in this case mouse.Target
GrabObject.PrimaryPart = DragBall; -- Make the dragball the primary part of the model
pk = GrabObject; -- set the PK variable to the GrabObject
elseif GrabObject.Parent:IsA("Model") then -- Same story but without `GrabObject.Parent`
GrabObject.Parent.PrimaryPart = DragBall;
pk = GrabObject.Parent;
end
-- Amazing, now we made ourself an object which we can work with.
local partTouched = {}; --- Make a local list which keeps track of ontouch events
if pk ~= nil then -- make sure the PK is not nil
-- Time for the magic
local descendants = pk:GetDescendants(); -- Get all descendants from the PK
for _, descendant in pairs(descendants) do -- Iterate over them
if descendant:IsA("Part") -- Check for all valid part options, we dont want anything else, (This is just particulair in my case... you can do it differently ofcourse)
or descendant:IsA("UnionOperation")
or descendant:IsA("MeshPart")
or descendant:IsA("TrussPart")
or descendant:IsA("WedgePart")
or descendant:IsA("CornerWedgePart")
or descendant:IsA("SpawnLocation")
then -- This block is important since it will assign the touch events
local touchEvent = descendant.Touched:connect(function(hit) -- Make a touched event of the part in question
if hit ~= nil and hit.Parent ~= nil and hit.Parent:FindFirstChild("Humanoid") ~= nil then -- so in my story I explained I had issues when the part was hitting my character, therefor this line, you could ignore it
-- Next thing is to simply force the whole model a few studs higher and my problem was solved
pk:SetPrimaryPartCFrame(CFrame.new(Vector3.new(pk.PrimaryPart.CFrame.Position.X, pk.PrimaryPart.CFrame.Position.Y + 0.5, pk.PrimaryPart.CFrame.Position.Z)))
end
end)
table.insert(partTouched, touchEvent) -- finally, lets populate that list we made
end
end
end
Alright, so you will now end up with a List which contains all the Touch events of each part of the model you are dragging at that moment. It’s very important after you while Dragger do
loop you disconnect all those events.
if #partTouched > 0 then
for _, touchEvent in pairs(partTouched) do
touchEvent:disconnect();
end
end
If you do this you can check for each part in the model if its hitting something, from there you could perhaps manage to force it back? You can also put invisble parts on each side of the model with a weld to the model. If one is touched raycast to the object that is touching it,… something like
-- To check whats below the object
local ray = Ray.new(Vector3.new(hit.Position.x, hit.Position.y, hit.Position.z), Vector3.new(0, -1, 0).unit * 500);
local ignoreList = {hit, player.Character};
local target, position = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList);
Its a lot of info and I don’t expect this is a straight up solution for your problem, however I hope it inspires you to find a suitable solution