i coded this script so when i triggered proximityPrompt it will set the part to the player head until i triggered the proximityPrompt again, but instead the part is just does nothing. here is the script:
local DragObject = script.Parent
local Prompt = script.Parent:WaitForChild("ProximityPrompt")
local Players = game:GetService("Players")
Prompt.Triggered:Connect(function(plr)
local player = Players:GetPlayerFromCharacter(plr.Parent
if player then
local Head = player.Character:FindFirstChild("Head")
if Head then
while true do
wait(0.01)
DragObject.CFrame = Head.CFrame * CFrame.new(0, 0, -2) * CFrame.Angles(0, math.rad(180), 0)
end
end
end
)
end)
local PlayerService = game:GetService("Players")
local DragObject = script.Parent
local ProximityPrompt = script.Parent:WaitForChild("ProximityPrompt")
local ObjectOnHead = false
ProximityPrompt.Triggered:Connect(function(Player)
if ObjectOnHead == true then
ObjectOnHead = false
return
end
local Character = Player.Character
local Head = if Character then Character:FindFirstChild("Head") else nil
if Character and Head then
ObjectOnHead = true
repeat task.wait()
if DragObject and Head then
DragObject.CFrame = Head.CFrame * CFrame.new(Vector3.new(0, 0, -2)) * CFrame.Angles(0, math.rad(180), 0)
end
until ObjectOnHead == false or Head == nil or DragObject == nil
ObjectOnHead = false
end
end)
i just realized i need a script with client runContext and i recode the code to this
local PlayerService = game:GetService("Players")
local DragObject = script.Parent
local ProximityPrompt = script.Parent:WaitForChild("ProximityPrompt")
local ObjectOnHead = false
local IsGrabbing = false
local Players = PlayerService:GetPlayers()
local player = PlayerService.LocalPlayer
local function Grab(Statement)
local Head = player.Character.Head
while Statement == true do
wait(0.01)
DragObject.CFrame = Head.CFrame * CFrame.new(0, 0, -1.5) * CFrame.Angles(0, math.rad(0), 0)
end
end
ProximityPrompt.Triggered:Connect(function(Player)
if IsGrabbing == false then
DragObject.CanCollide = false
IsGrabbing = true
ProximityPrompt.ActionText = "Drop"
Grab(true)
else
DragObject.CanCollide = false
IsGrabbing = false
ProximityPrompt.ActionText = "Grab"
Grab(false)
end
end)
it was work, but when i click the prompt again it wont stop goes to the player head position like this
Edit: Sorry, just realized what you need help with; my brain’s too fried to process, haha. I’ll still keep this reply if you want to take ideas or a new perspective.
Add a collision check before moving it to the head position; this will prevent the part from moving into buildings or the map, but this is your game and script. Do whatever you want, as you see fit.
Also, filter out rotations and only include positional movements to avoid flickering caused by rotations not being filtered from the final CFrame while moving, as shown in the video above.
I also recommend using lerps (Linear interpolation) to slightly smooth the part movement. It will make it feel more polished and smooth.
That’s all I have. Unfortunately, I’m too tired to go into detail, so I’m just offering suggestions and fixes based on the video you sent.
i did add collision check, and i just recode my script again… and it kinda work, but when i try to drop the part this happens:
the script rn:
local PlayerService = game:GetService("Players")
local DragObject = script.Parent
local ProximityPrompt = script.Parent:WaitForChild("ProximityPrompt")
local ObjectOnHead = false
local IsGrabbing = false
local Players = PlayerService:GetPlayers()
local player = PlayerService.LocalPlayer
local function Grab(Statement)
local Head = player.Character.Head
while Statement == true do
wait(0.01)
DragObject.CFrame = Head.CFrame * CFrame.new(0, 0, -DragObject.PivotOffset.Z) * CFrame.Angles(0, math.rad(0), 0)
if Statement == false then
DragObject.CFrame = nil
break
end
end
end
ProximityPrompt.Triggered:Connect(function(Player)
if IsGrabbing == false then
DragObject.CanCollide = false
IsGrabbing = true
ProximityPrompt.ActionText = "Drop"
Grab(true)
else
DragObject.CanCollide = true
IsGrabbing = false
ProximityPrompt.ActionText = "Grab"
Grab(false)
end
end)
i have 2 option
1, gave up the grabbing mechanic
2. Completely redo it until its work
first you should check for any errors in the studio output local player = Players:GetPlayerFromCharacter(plr.Parent
the line above will stops teh code from proceeding to the next line since this is a syntax error
while true do
wait(0.01)
DragObject.CFrame = Head.CFrame * CFrame.new(0, 0, -2) * CFrame.Angles(0, math.rad(180), 0)
end
instead of this infinite while loop that doesn’t break, use Renderstepped with connection variable which you can disconnect
sample code
local dragging = false
local dragConnection
dragging = not dragging
if dragging then
if DragObject.Anchored then
DragObject.Anchored = false
end
print("Started dragging")
dragConnection = game:GetService("RunService").RenderStepped:Connect(function()
if head then
DragObject.CFrame = head.CFrame * CFrame.new(0, 0, -2) * CFrame.Angles(0, math.rad(180), 0)
end
end)
else
print("Stopped dragging")
if dragConnection then
dragConnection:Disconnect()
dragConnection = nil
end
end
or a repeat while loop
sample code
dragging = not dragging
repeat
task.wait(0.01)
if head then
DragObject.CFrame = head.CFrame * CFrame.new(0, 0, -2) * CFrame.Angles(0, math.rad(180), 0)
end
until not dragging
The most efficient way is to weld the model’s primaryPart/part above the player’s head and unweld it depeding on circumstances; but the model/parts had to be unanchored
-- DragHelper Module
local RunService = game:GetService("RunService")
local DragHelper = {}
DragHelper.Offset = Vector3.new(0, 5, 0)
-- Internal state
local activeRenderLoop = nil
local isRepeating = false
local currentWeld = nil
local originalPositions = {} -- Stores dragObject → CFrame
function DragHelper.StopAll()
DragHelper.StopRenderStep()
DragHelper.StopRepeat()
DragHelper.Unweld()
end
-- Save original position
local function storeOriginal(dragObject)
if dragObject:IsA("Model") then
originalPositions[dragObject] = dragObject:GetPivot()
elseif dragObject:IsA("BasePart") then
originalPositions[dragObject] = dragObject.CFrame
end
end
-- Public method to restore original CFrame
function DragHelper.ReturnToOriginalPosition(dragObject)
local saved = originalPositions[dragObject]
if saved then
if dragObject:IsA("Model") then
dragObject:PivotTo(saved)
elseif dragObject:IsA("BasePart") then
dragObject.CFrame = saved
end
else
warn("No saved position for dragObject")
end
end
-- Get the correct attachment part
local function getPrimary(dragObject)
if dragObject:IsA("Model") then
-- Wait for PrimaryPart to be set
local timeout = 5
local startTime = tick()
while not dragObject.PrimaryPart and tick() - startTime < timeout do
task.wait()
end
if not dragObject.PrimaryPart then
warn("Model has no PrimaryPart after waiting!")
return nil
end
return dragObject.PrimaryPart
elseif dragObject:IsA("BasePart") then
return dragObject
else
warn("Invalid drag object type.")
return nil
end
end
-- Apply position safely (works for both Model and Part)
local function applyCFrame(dragObject, targetCFrame)
if dragObject:IsA("Model") then
dragObject:PivotTo(targetCFrame)
elseif dragObject:IsA("BasePart") then
dragObject.CFrame = targetCFrame
end
end
-- Method 1: Weld
function DragHelper.WeldToHead(dragObject, head)
if currentWeld then currentWeld:Destroy() end
local part = getPrimary(dragObject)
if not part or not head then return end
-- Move above head
local targetCFrame = head.CFrame * CFrame.new(DragHelper.Offset)
applyCFrame(dragObject, targetCFrame)
-- Unanchor parts
if dragObject:IsA("Model") then
for _, p in ipairs(dragObject:GetDescendants()) do
if p:IsA("BasePart") then
p.Anchored = false
end
end
else
dragObject.Anchored = false
end
-- Weld
local weld = Instance.new("WeldConstraint")
weld.Part0 = head
weld.Part1 = part
weld.Parent = part
currentWeld = weld
end
function DragHelper.Unweld()
if currentWeld then
currentWeld:Destroy()
currentWeld = nil
end
end
-- Method 2: Repeat Until
function DragHelper.RepeatDrag(dragObject, head, stopFlagFn)
isRepeating = true
local part = getPrimary(dragObject)
if not part or not head then return end
task.spawn(function()
repeat
task.wait(0.01)
local targetCFrame = head.CFrame * CFrame.new(DragHelper.Offset)
applyCFrame(dragObject, targetCFrame)
until stopFlagFn and stopFlagFn() or not isRepeating
end)
end
function DragHelper.StopRepeat()
isRepeating = false
end
-- Method 3: RenderStepped
function DragHelper.RenderStepDrag(dragObject, head)
local part = getPrimary(dragObject)
if not part or not head then return end
if activeRenderLoop then
activeRenderLoop:Disconnect()
activeRenderLoop = nil
end
activeRenderLoop = RunService.RenderStepped:Connect(function()
local targetCFrame = head.CFrame * CFrame.new(DragHelper.Offset)
applyCFrame(dragObject, targetCFrame)
end)
end
function DragHelper.StopRenderStep()
if activeRenderLoop then
activeRenderLoop:Disconnect()
activeRenderLoop = nil
end
end
return DragHelper
usage code
--local script
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DragHelper = require(ReplicatedStorage:WaitForChild("DragHelper"))
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local head = character:WaitForChild("Head")
local partToDrag = workspace:WaitForChild("Rig")--set your model/part
DragHelper.RenderStepDrag(partToDrag,head)
task.delay(5, function()
DragHelper.StopRenderStep()
end)
--[[use drepeatDrag]]
--local shouldStop = false
---- Start dragging above the head
--DragHelper.StopAll() -- Optional, clears other drag modes
--DragHelper.RepeatDrag(partToDrag, head, function()
-- return shouldStop
--end)
---- ⏱️ Stop after 5 seconds:
--task.delay(5, function()
-- shouldStop = true
--end)
--[[use weld drag]]
--DragHelper.WeldToHead(partToDrag, head)
---- ⏱️ Unweld after 5 seconds
--task.delay(5, function()
-- DragHelper.Unweld()
--end)