There is a secret method (more so a method I came up with, that I havenât seen anyone else use), that makes grabbing objects in third person like wayyy nicer. The idea is simple, and itâs to calculate the PointerCFrame (in my grab system, I have a âpointerâ which is a blue ball that welds to grabed objects, and the pointer is what you control. I think itâs equivalent to the attachment in your code) by extending a ray from the camera, and only from the camera. An obvious downside to this approach is that, zooming in and out moves the grabbed object in and out as well, but itâs very easy to fix that. Take the distance between the camera and the characterâs head, and use that to cancel out the zooming in and out. Another âdownsideâ is that grabbed objects can very easily fall outside of the allowed grab range. In my case, objects just drop when that happens (I made it so the max distance can be like 1.4x the max distance required to start grabbing the object, so it cannot drop instantly). I actually like this downside a lot, because it makes it really easy to throw stuff around
Here is a video demonstrating how it behaves in third person
In your code, you take the head position, and add an offset to it using the direction the mouse is pointing, which is the common method
local screenPos = getCursorScreenPos()
local camera = workspace.CurrentCamera
local ray = camera:ViewportPointToRay(screenPos.X, screenPos.Y)
local direction = ray.Direction
local headPos = head.Position
local targetPos = headPos + direction.Unit * grabDistance
-- Set position target
alignPosition.Position = targetPos
This is the code I wrote to get the PointerCFrame (which is then directly passed to the AlignPosition)
local function GetPointerCFrame(CFrameOffsets)
local Rayinfo = Camera:ScreenPointToRay(Mouse.X,Mouse.Y,0)
local NewCamera = CFrame.lookAt(Rayinfo.Origin, Rayinfo.Origin + Rayinfo.Direction)
local DistanceOffset = NewCamera:ToObjectSpace(Head.CFrame).Z - CFrameOffsets.CharacterOffset
local Offset = DistanceOffset + Controls:GetScroll()
local Angle = Controls:GetRollCFrame()
local PointerCFrame = NewCamera*(CFrameOffsets.CameraPointOffset+Vector3.zAxis*Offset)*Angle
return PointerCFrame
end
Where CFrameOffsets.CharacterOffset is the initial distance from the camera to the characterâs head, when the player started the grab (CFrameOffsets.CharacterOffset = NewCamera:ToObjectSpace(Head.CFrame).Z)
And CFrameOffsets.CameraPointOffset is the initial CFrame offset from the camera, to the pointer
CFrameOffsets.PointerOffset = Target.CFrame:ToObjectSpace(MouseHit)
CFrameOffsets.CameraPointOffset = NewCamera:ToObjectSpace(Target.CFrame*CFrameOffsets.PointerOffset)
I donât know why itâs defined like this. I think Target.CFrame*CFrameOffsets.PointerOffset is the same as MouseHit (which is Mouse.Hit, but modified for other reasons)
Wrote this reply in hopes it can help. I donât know if this would work well for mobile, or if itâs a behavior you even want, but I think it could improve your grab system :P. I would like to open source my own grab system, but itâs not quite there (and I donât have the time), it has poor mobile support, and my attempt at preventing flying didnât work quite well. I would be willing to share a local file if anyone is interested
My grab script is also a bit overbuilt. itâs (over)filled with features. I like that yours is concise
Also, another tip, roblox added a RunContex property to scripts, which allows scripts to run under any container. It is particularly useful for modules, where you can bundle the whole thing (client scripts, server scripts, and remote events), into a single folder, that is then put into ReplicatedStorage. Makes it very easy for people to include into their games, and is also a way of organizing code I quite like