Help with rope swinging thingy

I wanna make the player able to swing from a rope like a spiderman thingy, but I can’t seem to figure out how to make it work.

Specifically with the force required to make it work, I’ve made the rope attach when you click on a part, but I can’t seem to figure out how to make a force to make the character swing.

I just really don’t understand what force is required and what force to use.

Could anyone help?

	local rope = Instance.new("RopeConstraint")
			rope.Visible = true
			rope.Color = BrickColor.new("Baby blue")
			rope.Thickness = 0.05
			
			local attachment = Instance.new("Attachment")
			attachment.Parent = char.HumanoidRootPart
			attachment.WorldPosition = origin
			local attachment1 = Instance.new("Attachment")
			attachment1.Parent = result.Instance
			attachment1.WorldPosition = position
			
			rope.Attachment0 = attachment
			rope.Attachment1 = attachment1
			
			rope.Length = (attachment.WorldPosition - attachment1.WorldPosition).Magnitude + 1
			
			rope.Parent = char.HumanoidRootPart

			local linearvelocity = Instance.new("VectorForce")
			local forceattachment = Instance.new("Attachment")
			forceattachment.WorldPosition = char.HumanoidRootPart.Position
			forceattachment.Parent = char.HumanoidRootPart
			
			linearvelocity.Attachment0 = forceattachment
						
			linearvelocity.Parent = char.HumanoidRootPart
			remoteevent:FireClient(plr, linearvelocity)
remoteevent.OnClientEvent:Connect(function(linearvelocity)
	linearvelocity.ApplyAtCenterOfMass = true
	linearvelocity.Force = Vector3.new(1000,0,1000)
end)

I’ve looked everywhere but nothing seems to help me.

How would I make the character swing?

(And yes a variable called linearvelocity references vectorforce and what are you going to do about it)

For this kind of problem I would use VectorForce like you did, but I would set the force on the client, since the character physics are simulated on the client; that would not only make it simpler to make, but also reduce the reaction time when moving.
About calculating the force value, you could use the Humanoid.MoveDirection property

1 Like
linearvelocity.Force = Vector3.new(plr.Character.Humanoid.MoveDirection.X * 100, 0, plr.Character.Humanoid.MoveDirection.Z * 100)

So something like that?

Yes, but you could simplify it by multiplying the whole move direction by 100 like this

plr.Character.Humanoid.MoveDirection * 100
1 Like

For your case It would probably be better to use BodyVelocity, Linear velocities would require several values to balance or get the results you want.

Secondly, Looking at your video to make a rope swinging thingy, You should probably just retract the rope’s Length. I made a game to simply give the effect of swinging by rag dolling the player or setting the player into a Physics or Ragdolled State and Disabling the GettingUp State.

The way you explained it is quite broad can you explain a little more?

1 Like

Something like that gif he provided

They gave a conclusion utilize this, thanks for the resource!

Since its in FPV I’m pretty sure there’s no rag dolling or anything.

Ohh, Do you want something like this?

Yeah something like this would be amazing, could you tell me how I could do it?

Let me cook something up for you…

2 Likes

Hey, so. All i can say is that I tried, the swinging thing is really difficult to replicate.

Local Script || StarterCharacterScripts

-- Services
local PlayService = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local DebrisService = game:GetService("Debris")

-- Objects
local Player = PlayService.LocalPlayer
local Mouse = Player:GetMouse()

local Character : Model = script.Parent
local Humanoid : Humanoid = Character:WaitForChild("Humanoid")
local Root : BasePart = Character.PrimaryPart or Character:WaitForChild("HumanoidRootPart")

local Camera = workspace.CurrentCamera

local RootAttachment = Root:WaitForChild("RootAttachment")
local EndAttachment = Instance.new("Attachment", Root)
EndAttachment.Name = "SwingerAttachment"

-- Constants
local MAX_GRAPPLE_DISTANCE = 300
local MIN_GRAPPLE_DISTANCE = 30

local GRAPPLE_DELAY = 0.6
local SWING_DELAY = 0.8

local MAX_SWING_DISTANCE = 300
local MIN_SWING_DISTANCE = 5

local ROPE_COLOR = Color3.fromRGB(34,34,34) -- has to be RGB as for current implementation

local GRAPPLE_KEY, SWING_KEY = Enum.KeyCode.F, Enum.KeyCode.E

-- State Variables
local GrappleDown, SwingDown = false, false

local IsGrappling = false
local IsSwinging = false

-- Values
local SpringTweenInfo = TweenInfo.new(0.8, Enum.EasingStyle.Elastic, Enum.EasingDirection.Out, 0, false, 0)
local Params = RaycastParams.new()
Params.FilterDescendantsInstances = {Character}

local SwingRope = nil
local SwingForce = nil

-- Functions
function Lerp(a, b, t)
	return a + (b - a) * t
end

function IsDead() : boolean
	return Humanoid.Health <= 0
end

function GetForce() : BodyVelocity
	local BodyVelocity = Instance.new("BodyVelocity")
	BodyVelocity.Name = "APPLIED_FORCE"
	return BodyVelocity
end

local Spring = nil
local springConnection = nil
local springTween = nil
function RopeEffect(From: Vector3, To: Vector3, ToObject: BasePart, MakeFinal: boolean?) : RopeConstraint? -- makes the rope effect.
	local direction = To - From
	local distance = direction.Magnitude
	
	EndAttachment.Parent = ToObject
	EndAttachment.WorldPosition = To
	
	Spring = Instance.new("SpringConstraint")
	Spring.Color = BrickColor.new(ROPE_COLOR.R/255,ROPE_COLOR.G/255,ROPE_COLOR.B/255)
	Spring.Stiffness = 0
	Spring.Radius = 0.4
	Spring.Coils = 8
	Spring.MaxForce = 0
	Spring.Damping = 0
	Spring.FreeLength = distance
	Spring.Visible = false
	Spring.Attachment0 = RootAttachment
	Spring.Attachment1 = EndAttachment
	Spring.Parent = Root
	
	local Rope : RopeConstraint? = nil
	
	if MakeFinal == true then
		Rope = Instance.new("RodConstraint", Root)
		Rope.Name = "SwingerRope"
		Rope.Color = BrickColor.new(ROPE_COLOR.R/255,ROPE_COLOR.G/255,ROPE_COLOR.B/255)
		Rope.Length = distance
		Rope.Visible = false
		Rope.Attachment0 = RootAttachment
		Rope.Attachment1 = EndAttachment
	end
	
 	springTween = TweenService:Create(Spring, SpringTweenInfo, {
		Coils = 0,
		Radius = 0
	})
	
	Spring.Visible = true
	springTween:Play()
	
	springConnection = springTween.Completed:Once(function()
		Spring:Destroy()
		if MakeFinal == true then
			Rope.Visible = true
		end
	end)
	
	return Rope
end

function StopRopeEffect()
	if Spring then
		Spring:Destroy()
	end
	if springConnection then
		springConnection:Disconnect()
	end
	if springTween then
		springTween:Cancel()
	end
end

function Graple() -- Simply pushes the player toward the goal position
	if IsGrappling or IsSwinging or IsDead() then return end
	local Direction = (Mouse.Hit.Position - Root.Position).Unit
	local Raycast = workspace:Raycast(Root.Position, Direction*MAX_GRAPPLE_DISTANCE, Params)
	if not Raycast then return end
	
	local To = Raycast.Position
	local GrapleDirection = To - Root.Position
	local GrapleDistance = GrapleDirection.Magnitude
	
	if GrapleDistance > MAX_GRAPPLE_DISTANCE then
		return
	elseif GrapleDistance < MIN_GRAPPLE_DISTANCE then
		return
	end
	
	IsGrappling = true
	
	local GrapleForce = Instance.new("VectorForce", Root)
	GrapleForce.Force = Vector3.zero
	GrapleForce.Attachment0 = RootAttachment
	GrapleForce.RelativeTo = Enum.ActuatorRelativeTo.World
	
	local StrengthFactor = math.abs((GrapleDistance-MIN_GRAPPLE_DISTANCE)/MAX_GRAPPLE_DISTANCE)
	local RequiredStrength = Lerp(600,1300, StrengthFactor) * Root.AssemblyMass -- Strength scaling from distance.
	GrapleForce.Parent = Root
	
	task.spawn(function()
		for count = 10,1,-1 do
			GrapleForce.Force = (Direction).Unit * RequiredStrength * (count/10)
			task.wait(0.05)
		end
		GrapleForce.Force = Vector3.zero
		StopRopeEffect()
	end)
	
	RopeEffect(Root.Position, To, Raycast.Instance, false)
	
	wait(GRAPPLE_DELAY)
	IsGrappling = false
end

local swingLength = 0
local swingVelocity = Vector3.new(0, 0, 0)
local swingAnchor = nil

local _debug_part = Instance.new("Part")
_debug_part.Anchored = true
_debug_part.CanCollide = false
_debug_part.CanTouch = false
_debug_part.CanQuery = false
_debug_part.CastShadow = false
_debug_part.Size = Vector3.one
_debug_part.BrickColor = BrickColor.Green()
_debug_part.Transparency = 0.3

function StartSwing()
	if IsGrappling or IsSwinging or IsDead() then return end
	local Direction = (Mouse.Hit.Position - Root.Position).Unit
	local Raycast = workspace:Raycast(Root.Position, Direction * MAX_SWING_DISTANCE, Params)
	if not Raycast then return end

	local To = Raycast.Position
	local Target = Raycast.Instance

	swingLength = (To - Root.Position).Magnitude
	if swingLength > MAX_SWING_DISTANCE or swingLength < MIN_SWING_DISTANCE then return end

	IsSwinging = true
	swingAnchor = To
	swingVelocity = Root.AssemblyLinearVelocity * 0.8  -- Preserve some momentum from before swing

	SwingRope = RopeEffect(Root.Position, To, Target, true)

	for _, child in pairs(Root:GetChildren()) do
		if child:IsA("BodyForce") or child:IsA("VectorForce") and child.Name == "SwingForce" then
			child:Destroy()
		end
	end

	SwingForce = Instance.new("VectorForce", Root)
	SwingForce.Name = "SwingForce"
	SwingForce.Force = Vector3.zero
	SwingForce.Attachment0 = RootAttachment
	SwingForce.RelativeTo = Enum.ActuatorRelativeTo.World

	_debug_part.Parent = workspace
	_debug_part.Position = swingAnchor
	
	local existingForce = Root:FindFirstChild("GravityForce")
	if not existingForce then
		local gravityForce = Instance.new("VectorForce", Root)
		gravityForce.Name = "GravityForce"
		gravityForce.Force = Vector3.new(0, -Root.AssemblyMass * workspace.Gravity, 0) 
		gravityForce.Attachment0 = RootAttachment
		gravityForce.RelativeTo = Enum.ActuatorRelativeTo.World
	end
end

local SWING_GRAVITY = workspace.Gravity 
local SWING_DAMPING = 1
local SWING_INPUT_FORCE = 15
local SWING_MAX_VELOCITY = 120
local SWING_AIR_RESISTANCE = 1 


function UpdateSwing(delta)
	if not IsSwinging or not swingAnchor then return end

	local toAnchor = swingAnchor - Root.Position
	local distance = toAnchor.Magnitude
	local normalizedToAnchor = toAnchor.Unit

	
	local gravityForce = Vector3.new(0, -SWING_GRAVITY * Root.AssemblyMass, 0)
	
	local velocity = Root.AssemblyLinearVelocity
	local tangentDir = (velocity - velocity:Dot(normalizedToAnchor) * normalizedToAnchor).Unit
	local normalDir = normalizedToAnchor
	
	local tangentSpeed = (velocity - velocity:Dot(normalizedToAnchor) * normalizedToAnchor).Magnitude
	local centripetalForce = (tangentSpeed * tangentSpeed / swingLength) * Root.AssemblyMass
	
	local moveDir = Humanoid.MoveDirection
	local inputForce = Vector3.new(moveDir.X, 0, moveDir.Z) * SWING_INPUT_FORCE * Root.AssemblyMass
	
	local totalForce = gravityForce + normalDir * centripetalForce + inputForce

	
	SwingForce.Force = totalForce

	
	Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity * SWING_AIR_RESISTANCE
	if Root.AssemblyLinearVelocity.Magnitude > SWING_MAX_VELOCITY then
		Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity.Unit * SWING_MAX_VELOCITY
	end

	
	if moveDir.Magnitude < 0.1 then
		Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity * SWING_DAMPING
	end
end

function StopSwing()
	IsSwinging = false
	swingAnchor = nil
	_debug_part.Parent = nil

	StopRopeEffect()
	if SwingRope then
		SwingRope:Destroy()
	end
	if SwingForce then
		SwingForce:Destroy()
	end

	local gravityForce = Root:FindFirstChild("GravityForce")
	if gravityForce then
		gravityForce:Destroy()
	end
	
	StopRopeEffect()

	local currentVelocity = Root.AssemblyLinearVelocity
	Root.AssemblyLinearVelocity = Vector3.new(currentVelocity.X * 0.8, currentVelocity.Y * 0.3, currentVelocity.Z * 0.8)
end

-- Connections
UserInputService.InputBegan:Connect(function(Input, Typing)
	if Typing then return end
	
	if Input.KeyCode == GRAPPLE_KEY then
		GrappleDown = true
		Graple()
	elseif Input.KeyCode == SWING_KEY then
		SwingDown = true
		StartSwing()
	end
end)

UserInputService.InputEnded:Connect(function(Input, Typing)
	if Typing then return end

	if Input.KeyCode == GRAPPLE_KEY then
		GrappleDown = false
	elseif Input.KeyCode == SWING_KEY then
		SwingDown = false
		StopSwing()
	end
end)

RunService.Heartbeat:Connect(function(delta)
	if IsSwinging then 
		UpdateSwing(delta)
		if SwingRope and swingAnchor then
			SwingRope.Attachment1.WorldPosition = swingAnchor
			SwingRope.Length = (Root.Position - swingAnchor).Magnitude
		end
	end
end)


1 Like

You certainly did cook thank you so much

1 Like