Positioning player after deleting a Weld (or vice-versa) not working as expected!

While scripting for my game I came across this issue where:

When welding a player to an object, then trying to position the player away from that object and delete the weld causes it to either go two ways depending on what line of code came first

1: Move the player THEN the delete the weld
player is moved (alongside the welded part which I don’t want), but the weld is not deleted

2: delete the weld THEN move the player
weld is deleted, but the player is not moved

From my testing it seems that waiting 0.1 seconds (using task.wait) between each line resolves this, but I require this to happen near instantly, as to not break player immersion.

here’s the code with the bare necessities to recreate the problem

as well as a place file: weld_Issues.rbxl (60.2 KB)



--this script is nearly an exact copy of what is happening in my game 
--but I am excluding a couple things that are not neccesary to replicate what is happening

local outside = workspace.Outside
--structured like this
--[[

	|	--	Model
	\
	 | -- Welds
	 | -- SendTo
	 | -- Primary
	 \
	  | -- ClickDetector

]]

local inside = workspace.Inside
--structured like this
--[[

	|	--	Model
	\
	 | -- Welds
	 | -- SendTo
	 | -- Primary
	 \
	  | -- ClickDetector

]]

local playersOutside = {}

--The destination is already pre-determined
--This function seems to work



local function sendPlayerOutSide(player: Player)
	
	local weld: Weld = Instance.new("Weld")
	weld.Name = player.Name
	weld.Part0 = outside.SendTo
	weld.Part1 = player.Character.PrimaryPart
	
	-- `outSide.Welds` folder to contain all the welds
	weld.Parent = outside.Welds
	
	player.Character:PivotTo(outside.SendTo.CFrame)
	
	table.insert(playersOutside, player.Character)
	
end

--use this to switch how the lines are read as mentioned in my post
local switch = true
local function sendPlayerInside(player: Player)
	
	for i,v in ipairs(playersOutside) do
		if v == player.Character then
			
			if switch then
				outside.Welds:FindFirstChild(player.Name):Destroy()
				player.Character:PivotTo(inside.SendTo.CFrame)
				
				playersOutside[i] = nil
				
			else
				player.Character:PivotTo(inside.SendTo.CFrame)
				outside.Welds:FindFirstChild(player.Name):Destroy()
				
				playersOutside[i] = nil
			end
			
			
		end
	end
	
end

-- the inside area and outside area are supposed to be seperated so the player can reach them
--but for ease of access i've put them next to each other with indicators

outside.Primary.ClickDetector.MouseClick:Connect(function(playerWhoClicked: Player) 
	
	sendPlayerInside(playerWhoClicked)	
	
end)

inside.Primary.ClickDetector.MouseClick:Connect(function(playerWhoClicked: Player) 
	
	sendPlayerOutSide(playerWhoClicked)	
	
end)

*Edit – Minor grammatical error + added structure to where models are assigned + moved some stuff around

image
youre creating the weld, then pivoting the character.
see what happens when you reverse this, pivot then weld?

The sendPlayersOutSide() function isn’t the main culprit. It was the sendPlayersInside() function that I’ve been having trouble with.

But I did test this now just in case if it had anything to do with it, and it seems that it doesn’t affect it

okay then switch these
image
destroy weld first then pivot

I have already tried that, my bad for not making it clear in the main bit but, the only way I’ve found to make them work is adding a wait of 0.1 seconds in between the two lines,
but as I mentioned above this breaks the players immersion which I don’t want to do if absolutely necessary.

I suggest you could try this:

local function sendPlayerInside(player: Player)
	for i,v in ipairs(playersOutside) do
		if v == player.Character then
			outside.Welds:FindFirstChild(player.Name).Enabled = false
			game:GetService("RunService").Heartbeat:Wait()
			outside.Welds:FindFirstChild(player.Name):Destroy()
			game:GetService("RunService").Heartbeat:Wait()
			player.Character:PivotTo(inside.SendTo.CFrame)

			playersOutside[i] = nil
		end
	end
end

Or this:

local function sendPlayerInside(player: Player)
	for i,v in ipairs(playersOutside) do
		if v == player.Character then
			outside.Welds:FindFirstChild(player.Name).Enabled = false
			game:GetService("RunService").Heartbeat:Wait()
			outside.Welds:FindFirstChild(player.Name):Destroy()
			task.wait()
			player.Character:PivotTo(inside.SendTo.CFrame)

			playersOutside[i] = nil
		end
	end
end

Check if any of those wont break the immersion.
Otherwise you could use Motor6d, to move the player while they are welded and after moving it, destroy it

1 Like

Thank you!
Both of your solutions work phenomenally!
I knew it had something to do with waiting some amount of time, but for the life of me I couldn’t figure it out haha

2 Likes

Yes, its the because the physics engine not having enough time to solve the quick sequence of destroying the weld and trying to move the character model, it needs wait at least one frame of the physics solving

2 Likes

if it needs to wait at least one frame, then instead of taks.wait() use runservice.RenderStepped:Wait(), if this is on the client, else use Heartbeat to guarantee this works for everyone and players with low fps

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.