How to properly connect 2 players using Rope / Rod constraints

Hi guys! In this short guide I will tell you how to correctly connect 2 or more players using Rope / Rod constraints, avoiding the glitches with the network connection that may occur…

Let’s consider 2 cases when players connect with each other:

Only one player has controls

In this case, players are connected to the constraint directly, through attachments located in their character root parts from the server side. The downside of this method is that with such a connection, a dilemma arises between their network ownerships. It consists of the fact that one network is trying to gain ownership over the other, thereby overlapping it and causing lags on the client side of the other player.
To implement this, we will create a RopeConstraint on the server and set its Attachment0 and Attachment1 to the attachments located in the root parts of our players’ characters. I would like to note that the player whose attachment was installed last will be “under” the network ownership of another player and will have lags.
To change the leading player, you need to transfer network ownership over all BaseParts of another player character to him.
Check out a demo of this below:

Usually this type of connection is used when the player who is attached does nothing, he is simply dragged somewhere. It is recommended to enable PlatformStand in Humanoid (specifically from the server side)

Two or more players have controls

Let’s consider the case when several players need to move at once. Then the first method will not work correctly. I found a great post from @PostVivic that talks about this and based on it I did something similar!

His method is based on the fact that players are not connected via Rope / Rod directly through Attachment0 and Attachment1, they are connected only visually when teleporting independent BasePart holders of 2 constraint ends in CFrame of root parts of each player character (on each of the clients to avoid latency from the server) and also due to an independent holder in the role of which a certain BasePart constantly teleports to the CFrame of the root part of the opposite player character (on the server side)
Check out a demo of this below:

As you can see, there are no lags on any of the clients!

For this I used this LocalScript. Just makes the appearance constraint.

local RunService = game:GetService('RunService')

local function RopePlayers(Player1: Player, Player2: Player)
	local P1Character = Player1.Character
	local P2Character =  Player2.Character
	local P1CHumanoidRootPart: BasePart = P1Character.HumanoidRootPart
	local P2CHumanoidRootPart: BasePart = P2Character.HumanoidRootPart
	local function MakeRopeHolder(RopeHolderName: string, RopeHolderParent: Model)
		local RopeHolder = Instance.new('Part', RopeHolderParent)
		RopeHolder.Name = RopeHolderName
		RopeHolder.CanTouch = false
		RopeHolder.CanCollide = false
		RopeHolder.CanQuery = false
		RopeHolder.Size = Vector3.zero
		RopeHolder.Transparency = 1
		RopeHolder.Anchored = true
		RopeHolder.Massless = true
		return RopeHolder
	end
	local RopeHolder0 = MakeRopeHolder('FakeRopeHolder0', P1Character)
	local RopeAttachment0 = Instance.new('Attachment', RopeHolder0)
	RopeAttachment0.Name = 'FakeRopeAttachment0'
	local RopeHolder1 = MakeRopeHolder('FakeRopeHolder1', P2Character)
	local RopeAttachment1 = Instance.new('Attachment', RopeHolder1)
	RopeAttachment1.Name = 'FakeRopeAttachment1'
	RunService.RenderStepped:Connect(function()
		RopeHolder0.CFrame = P1CHumanoidRootPart.CFrame
		RopeHolder1.CFrame = P2CHumanoidRootPart.CFrame
	end)
	task.wait()
	local Rope = Instance.new('RopeConstraint', P1Character)
	Rope.Name = 'FakeRope'
	Rope.Visible = true
	Rope.Length = 10
	Rope.Attachment0 = RopeAttachment0
	Rope.Attachment1 = RopeAttachment1
end

And here is such a Script. Executes the physical logic of the interaction between a attached player and an independent holder on another player.

local RunService = game:GetService('RunService')

local function RopePlayers(Player1: Player, Player2: Player)
	local P1Character = Player1.Character
	local P2Character =  Player2.Character
	local P1CHumanoidRootPart: BasePart = P1Character.HumanoidRootPart
	local P2CHumanoidRootPart: BasePart = P2Character.HumanoidRootPart
	local RopeAttachment0 = Instance.new('Attachment', P1CHumanoidRootPart)
	RopeAttachment0.Name = 'RealRopeAttachment0'
	local RopeHolder = Instance.new('Part', P2Character)
	RopeHolder.Name = 'RealRopeHolder'
	RopeHolder.CanTouch = false
	RopeHolder.CanCollide = false
	RopeHolder.CanQuery = false
	RopeHolder.Size = Vector3.zero
	RopeHolder.Transparency = 1
	RopeHolder.Anchored = true
	RopeHolder.Massless = true
	local RopeAttachment1 = Instance.new('Attachment', RopeHolder)
	RopeAttachment1.Name = 'RealRopeAttachment1'
	RunService.Heartbeat:Connect(function()
		RopeHolder.CFrame = P2CHumanoidRootPart.CFrame
	end)
	task.wait()
	local Rope = Instance.new('RopeConstraint', P1Character)
	Rope.Name = 'RealRope'
	Rope.Visible = false
	Rope.Length = 10
	Rope.Attachment0 = RopeAttachment0
	Rope.Attachment1 = RopeAttachment1
end

I hope my tips helped you and you learned how to connect 2 players together correctly. Good luck!

9 Likes

Thank you! Its really nice to see my post be linked. Also it was great to see the method I talked about being put in practice as it was just theory on my part.

It seems a lot of games nowadays are going with the idea of a two player obby with both players being chained together.

Another thing to note is this system likely has its drawbacks in high-ping situations, drawbacks that we can see in most games who use this mechanic.

1: hard-setting the cframe results in each client taking each other as the de-facto standard. Low ping is fine here, but the drawback of networking means each client is seeing a delayed version of the world based on their ping. High ping players will be taking a delayed snapshot of the other client as the standard and lock their position based on that.

We can see this in regular roblox with the two player infinite jump glitch, both clients are basing their calculations on the delayed other player, causing the other player to be on the bottom of the chain on both screens

You can even see this drawback in your video!

Notice how both clients appear to be on the bottom! Both of them limiting their speed because they’re basing it off of the delayed afterimage of the other player (who’s also limiting their speed based off of the first player)!

This effect is a lot worse when games use a rubber band style chain where being farther away from a player results in a more powerful “bouncing back” force. This bouncing back force compounds into both clients flinging up and down at incredibly fast and unpredictable speeds.

As far as fixing this goes, my best idea is to dampen the other player’s follower basepart. Instead of hard setting it, maybe through use of an AlignPosition or a VectorForce to approximate the location of the basepart? But I would love to see you (or even another devforum poster) theory-craft and experiment with a solution to this!

2: Most games handle teleportation incorrectly. This is a relatively simple fix, but you have to ensure both clients disable their rope system temporarily before they teleport and re-enable after the teleport has been confirmed to be finished. The server can have remote events to disable and enable the rope system at will, then you could simply handle all of the teleportation logic on the server!

2 Likes

Thanks for your additions and advice on this system! Yes, it is not perfect and its performance result depends on the ping of 2 players together. I will try to work on this in the future to make it better.
Anyways, I will also be pleased if someone else will use this topic based on your theory in practice and also try to find a solution!

1 Like