I’m trying to make a grab system and everything was going fine until the curse of the blue orb. basically I tried adding a blue orb on the location of the part where the player first grabbed. Seemed simple enough I already had the grabbing itself working fine. But now this one blue dot has made it super janky. I think its because of the weld constraint being created mid script between it and the part but i’m not too sure. before adding it grabbing stuff would be fine but now I have to basically jumpstart it by pushing the blocks around and even then it only works good sometimes.
Anyone know of any solutions or alternate ways to achieve this look? I don’t want to just flat out remove it but if there’s any other way to display the 3d orb in that specific position that would be great. Also already tried just moving it there with heartbeat but its too slow for rapid movements like that.
here are the scripts, main one to look at is the server script since it has the ball:
Server script:
local replicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local requestOwnership = replicatedStorage:WaitForChild("RequestOwnership")
local startGrab = replicatedStorage:WaitForChild("StartGrab")
local stopGrab = replicatedStorage:WaitForChild("StopGrab")
local updateGrabTarget = replicatedStorage:WaitForChild("UpdateGrabTarget")
local playerData = {}
requestOwnership.OnServerEvent:Connect(function(player, part)
if part and part:IsA("BasePart") and not part.Anchored then
part:SetNetworkOwner(player)
end
end)
startGrab.OnServerEvent:Connect(function(player, part, hitPosition)
local char = player.Character
if not char then return end
local hand = char:FindFirstChild("RightHand") or char:FindFirstChild("Right Arm")
if not hand then return end
if playerData[player] then
local d = playerData[player]
if d.Beam then d.Beam:Destroy() end
if d.HandPart then d.HandPart:Destroy() end
if d.Connection then d.Connection:Disconnect() end
if d.GlowBall then d.GlowBall:Destroy() end
end
-- Hand beam part
local handPart = Instance.new("Part")
handPart.Size = Vector3.new(0.3, 0.3, 0.3)
handPart.Anchored = false
handPart.CanCollide = false
handPart.Transparency = 1
handPart.Name = "BeamHandPart"
handPart.CFrame = hand.CFrame * CFrame.new(0, -1, 0)
handPart.Parent = workspace
local handWeld = Instance.new("WeldConstraint")
handWeld.Part0 = handPart
handWeld.Part1 = hand
handWeld.Parent = handPart
local handAttach = Instance.new("Attachment")
handAttach.Rotation = Vector3.new(0, 0, -90)
handAttach.Parent = handPart
-- Attachment on part
local localOffset = part.CFrame:PointToObjectSpace(hitPosition)
local partAttach = Instance.new("Attachment")
partAttach.Position = localOffset
partAttach.Rotation = Vector3.new(0, 0, -90)
partAttach.Parent = part
-- Glowing ball
local glowBall = Instance.new("Part")
glowBall.Name = "GlowBall"
glowBall.Shape = Enum.PartType.Ball
glowBall.Material = Enum.Material.Neon
glowBall.Color = Color3.fromRGB(0, 200, 255)
glowBall.Size = Vector3.new(0.4, 0.4, 0.4)
glowBall.Anchored = false
glowBall.CanCollide = false
glowBall.CanTouch = false
glowBall.CanQuery = false
glowBall.Massless = true
glowBall.CFrame = part.CFrame * CFrame.new(localOffset)
glowBall.Parent = part
local weld = Instance.new("WeldConstraint")
weld.Part0 = glowBall
weld.Part1 = part
weld.Parent = part
-- Beam
local beam = Instance.new("Beam")
beam.Attachment0 = handAttach
beam.Attachment1 = partAttach
beam.Color = ColorSequence.new(Color3.fromRGB(100, 200, 255))
beam.Width0 = 0.2
beam.Width1 = 0.2
beam.LightEmission = 1
beam.FaceCamera = true
beam.TextureSpeed = 2
beam.CurveSize0 = 0
beam.CurveSize1 = -2
beam.Parent = handPart
-- Animate beam curve
local t0 = tick()
local conn = RunService.Heartbeat:Connect(function()
if beam then
beam.CurveSize1 = math.sin((tick() - t0) * 2) * -2
end
end)
playerData[player] = {
Beam = beam,
HandPart = handPart,
Connection = conn,
GlowBall = glowBall,
}
end)
updateGrabTarget.OnServerEvent:Connect(function(player, _)
-- No need to process here due to beam visuals being auto-attached (But need this to prevent remote event exhaustion)
end)
stopGrab.OnServerEvent:Connect(function(player)
local d = playerData[player]
if d then
if d.Beam then d.Beam:Destroy() end
if d.HandPart then d.HandPart:Destroy() end
if d.Connection then d.Connection:Disconnect() end
if d.GlowBall then d.GlowBall:Destroy() end
end
playerData[player] = nil
end)
Local Script:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local runService = game:GetService("RunService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local userInputService = game:GetService("UserInputService")
local requestOwnership = replicatedStorage:WaitForChild("RequestOwnership")
local startGrab = replicatedStorage:WaitForChild("StartGrab")
local stopGrab = replicatedStorage:WaitForChild("StopGrab")
local updateGrabTarget = replicatedStorage:WaitForChild("UpdateGrabTarget")
local holdingPart = nil
local vectorForce = nil
local attachment = nil
local grabbing = false
-- Arm physics
local rightShoulder = nil
local originalC0 = nil
local currentArmAngle = 0
local armVelocity = 0
local holdDistance = 10
userInputService.InputBegan:Connect(function(input, processed)
if processed or input.UserInputType ~= Enum.UserInputType.MouseButton1 or grabbing then return end
local target = mouse.Target
if target and target:IsA("BasePart") and not target.Anchored then
-- Clean up any old grab
if vectorForce then vectorForce:Destroy() end
if attachment then attachment:Destroy() end
holdingPart = target
local hitPos = mouse.Hit.Position
requestOwnership:FireServer(target)
startGrab:FireServer(target, hitPos)
task.delay(0.05, function()
if holdingPart and holdingPart.Parent then
attachment = Instance.new("Attachment")
attachment.Name = "GrabAttachment"
attachment.Parent = holdingPart
vectorForce = Instance.new("VectorForce")
vectorForce.Name = "GrabForce"
vectorForce.Attachment0 = attachment
vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
vectorForce.ApplyAtCenterOfMass = true
vectorForce.Force = Vector3.zero
vectorForce.Parent = holdingPart
end
end)
local char = player.Character or player.CharacterAdded:Wait()
local torso = char:FindFirstChild("Torso")
local arm = char:FindFirstChild("Right Arm")
if torso and arm then
rightShoulder = torso:FindFirstChild("Right Shoulder")
if rightShoulder and rightShoulder:IsA("Motor6D") then
originalC0 = rightShoulder.C0
end
end
grabbing = true
end
end)
userInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 and grabbing then
stopGrab:FireServer()
if vectorForce then vectorForce:Destroy() end
if attachment then attachment:Destroy() end
holdingPart = nil
vectorForce = nil
attachment = nil
grabbing = false
end
end)
runService.RenderStepped:Connect(function()
local char = player.Character
if not char then return end
if grabbing and holdingPart and holdingPart.Parent and vectorForce then
local unitRay = mouse.UnitRay
local massFactor = math.clamp(holdingPart.AssemblyMass / 25, 0.8, 1.5)
local targetPos = unitRay.Origin + unitRay.Direction * holdDistance * massFactor
local bobOffset = math.sin(tick() * 2) * 0.2
targetPos += Vector3.new(0, bobOffset, 0)
updateGrabTarget:FireServer(targetPos)
local velocity = (targetPos - holdingPart.Position) * 50
local drag = holdingPart.AssemblyLinearVelocity * 5
vectorForce.Force = (velocity - drag) * holdingPart.AssemblyMass
end
local torso = char:FindFirstChild("Torso")
if torso and rightShoulder and originalC0 then
local torsoPos = torso.Position
local aimTarget = (holdingPart and holdingPart.Position) or (torsoPos + Vector3.new(0, 0, -10))
local direction = (aimTarget - torsoPos).Unit
local verticalOffset = direction.Y
local targetAngle = math.clamp(verticalOffset * 2, -1.2, 1.2)
local stiffness = 0.15
local damping = 0.2
local force = (targetAngle - currentArmAngle) * stiffness
armVelocity = armVelocity + force - armVelocity * damping
currentArmAngle = currentArmAngle + armVelocity
rightShoulder.C0 = originalC0 * CFrame.Angles(0, 0, currentArmAngle)
end
end)
Thanks!