Weld Part to Cameras Position

Hello, when a player joins the game, I want to clone a part, then re-position it to where the players camera is, and make it stick to it. (AKA weld it) I’ve tried a few things so far but the closest I could get was where it only worked on the client-side, meaning the player could only see the part positioned at their camera, not anyone else’s. Also, it’s really laggy being re-positioned over and over again, so I’d rather it got welded than re-positioned.
Client Script:

local PartClone = game.ReplicatedStorage.TestPart:Clone()
PartClone.Parent = game.Workspace

while wait() do
	PartClone.Position = game.Workspace.CurrentCamera.CFrame.Position
end

I would like it to be positioned on the server-side, but you can’t access the players’ current camera there, which is a problem.

haven’t tried this but u can try passing the cframe value to the server and put it as a part’s position

If you want it to be positioned on the server-side you can use a RemoteEvent | Roblox Creator Documentation

If you give client network ownership of the part via part:SetNetworkOwner(plr), the player can use a LocalScript to position the part on RenderStepped. The position will be 100% smooth on the client, and the server will get updates as fast as possible, without clogging up your RemoteEvent queue. Other players will see this.

Just make sure the part is unanchored before you try to set the network owner. The part also has to be created on the server & SetNetworkOwner can only be called on the server.

1 Like

I’ve never used network owner before and I have no idea how this works, sorry.

It works exactly how I said. All you have to do is call part:SetNetworkOwner(plr), and then when that player uses LocalScripts to move the part, it will move for everyone in the game

Here’s an example. Server script:

local part = game:GetService('ReplicatedStorage').TestPart

local function playerAdded(plr)
    local function characterAdded(char)
        local clone = part:Clone()
        clone.Parent = char
        -- This `if` statement needs to be here because Roblox is about to break `:Wait()` with Deferred Events
        if not char:IsDescendantOf(workspace) then char.AncestryChanged:Wait() end
        clone:SetNetworkOwner(plr)
    end

    plr.CharacterAdded:Connect(characterAdded)
    if plr.Character then characterAdded(plr.Character) end
end

local players = game:GetService('Players')
players.PlayerAdded:Connect(playerAdded)

for _, plr in ipairs(players:GetChildren()) do
    playerAdded(plr)
end

So much boilerplate just to parent a part to a character. Whatever…

LocalScript (in StarterPlayer.StarterCharacterScripts):

local part = script.Parent:WaitForChild('TestPart')

game:GetService('RunService').RenderStepped:Connect(function()
    part.CFrame = workspace.CurrentCamera.CFrame
    part.AssemblyLinearVelocity *= 0
    part.AssemblyAngularVelocity *= 0
end)

Should the local script be inside StarterCharacterScripts? Because I’ve got it in StarterPlayerScripts.

Yes, it should be inside StarterCharacterScripts:

That way it will respawn with the character and pick up the new TestPart each time.

1 Like

It gave an error saying Can only call Network Ownership API on a part that is descendent of Workspace on the line that says clone:SetNetworkOwner(plr).

Oh, forgot CharacterAdded is called before the character is parented to Workspace. Might want to slap a wait() in there, right before the call to SetNetworkOwner, since char.AncestryChanged:Wait() would stop working once Roblox finishes butchering events.

Good, it works now but it keeps glitching around.

Maybe set part.Velocity *= 0 inside of the RenderStepped function?

I just tested this in Studio and it seems to fix the problem.